mirror of
https://github.com/nginx/nginx.git
synced 2025-06-17 17:20:42 +08:00
HTTP/3: refactored request parser.
The change reduces diff to the default branch for src/http/ngx_http_request.c and src/http/ngx_http_parse.c.
This commit is contained in:
parent
f3c9e9f961
commit
9e489d208f
@ -175,6 +175,43 @@ static ngx_http_variable_t ngx_http_quic_vars[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ngx_int_t
|
||||||
|
ngx_http_quic_init(ngx_connection_t *c)
|
||||||
|
{
|
||||||
|
ngx_quic_conf_t *qcf;
|
||||||
|
ngx_http_connection_t *hc, *phc;
|
||||||
|
ngx_http_core_loc_conf_t *clcf;
|
||||||
|
|
||||||
|
hc = c->data;
|
||||||
|
|
||||||
|
hc->ssl = 1;
|
||||||
|
|
||||||
|
if (c->quic == NULL) {
|
||||||
|
c->log->connection = c->number;
|
||||||
|
|
||||||
|
qcf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_quic_module);
|
||||||
|
|
||||||
|
ngx_quic_run(c, qcf);
|
||||||
|
|
||||||
|
return NGX_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http init quic stream");
|
||||||
|
|
||||||
|
phc = c->quic->parent->data;
|
||||||
|
|
||||||
|
if (phc->ssl_servername) {
|
||||||
|
hc->ssl_servername = phc->ssl_servername;
|
||||||
|
hc->conf_ctx = phc->conf_ctx;
|
||||||
|
|
||||||
|
clcf = ngx_http_get_module_loc_conf(hc->conf_ctx, ngx_http_core_module);
|
||||||
|
ngx_set_connection_log(c, clcf->error_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_http_variable_quic(ngx_http_request_t *r,
|
ngx_http_variable_quic(ngx_http_request_t *r,
|
||||||
ngx_http_variable_value_t *v, uintptr_t data)
|
ngx_http_variable_value_t *v, uintptr_t data)
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
#define NGX_HTTP_QUIC_ALPN_DRAFT_FMT "\x05hq-%02uD"
|
#define NGX_HTTP_QUIC_ALPN_DRAFT_FMT "\x05hq-%02uD"
|
||||||
|
|
||||||
|
|
||||||
extern ngx_module_t ngx_http_quic_module;
|
ngx_int_t ngx_http_quic_init(ngx_connection_t *c);
|
||||||
|
|
||||||
|
|
||||||
#endif /* _NGX_HTTP_QUIC_H_INCLUDED_ */
|
#endif /* _NGX_HTTP_QUIC_H_INCLUDED_ */
|
||||||
|
@ -134,6 +134,11 @@ void ngx_http_handler(ngx_http_request_t *r);
|
|||||||
void ngx_http_run_posted_requests(ngx_connection_t *c);
|
void ngx_http_run_posted_requests(ngx_connection_t *c);
|
||||||
ngx_int_t ngx_http_post_request(ngx_http_request_t *r,
|
ngx_int_t ngx_http_post_request(ngx_http_request_t *r,
|
||||||
ngx_http_posted_request_t *pr);
|
ngx_http_posted_request_t *pr);
|
||||||
|
ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r,
|
||||||
|
ngx_str_t *host);
|
||||||
|
ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool,
|
||||||
|
ngx_uint_t alloc);
|
||||||
|
void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc);
|
||||||
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
|
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc);
|
||||||
void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc);
|
void ngx_http_free_request(ngx_http_request_t *r, ngx_int_t rc);
|
||||||
|
|
||||||
|
@ -143,7 +143,6 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
|
|||||||
|
|
||||||
/* HTTP methods: GET, HEAD, POST */
|
/* HTTP methods: GET, HEAD, POST */
|
||||||
case sw_start:
|
case sw_start:
|
||||||
r->parse_start = p;
|
|
||||||
r->request_start = p;
|
r->request_start = p;
|
||||||
|
|
||||||
if (ch == CR || ch == LF) {
|
if (ch == CR || ch == LF) {
|
||||||
@ -896,7 +895,6 @@ ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b,
|
|||||||
|
|
||||||
/* first char */
|
/* first char */
|
||||||
case sw_start:
|
case sw_start:
|
||||||
r->parse_start = p;
|
|
||||||
r->header_name_start = p;
|
r->header_name_start = p;
|
||||||
r->invalid_header = 0;
|
r->invalid_header = 0;
|
||||||
|
|
||||||
|
@ -31,10 +31,6 @@ static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
|
|||||||
static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
|
static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
|
||||||
ngx_table_elt_t *h, ngx_uint_t offset);
|
ngx_table_elt_t *h, ngx_uint_t offset);
|
||||||
|
|
||||||
static ngx_int_t ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool,
|
|
||||||
ngx_uint_t alloc);
|
|
||||||
static ngx_int_t ngx_http_set_virtual_server(ngx_http_request_t *r,
|
|
||||||
ngx_str_t *host);
|
|
||||||
static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c,
|
static ngx_int_t ngx_http_find_virtual_server(ngx_connection_t *c,
|
||||||
ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,
|
ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,
|
||||||
ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp);
|
ngx_http_request_t *r, ngx_http_core_srv_conf_t **cscfp);
|
||||||
@ -52,7 +48,6 @@ static void ngx_http_keepalive_handler(ngx_event_t *ev);
|
|||||||
static void ngx_http_set_lingering_close(ngx_connection_t *c);
|
static void ngx_http_set_lingering_close(ngx_connection_t *c);
|
||||||
static void ngx_http_lingering_close_handler(ngx_event_t *ev);
|
static void ngx_http_lingering_close_handler(ngx_event_t *ev);
|
||||||
static ngx_int_t ngx_http_post_action(ngx_http_request_t *r);
|
static ngx_int_t ngx_http_post_action(ngx_http_request_t *r);
|
||||||
static void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t error);
|
|
||||||
static void ngx_http_log_request(ngx_http_request_t *r);
|
static void ngx_http_log_request(ngx_http_request_t *r);
|
||||||
|
|
||||||
static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
|
static u_char *ngx_http_log_error_handler(ngx_http_request_t *r,
|
||||||
@ -303,54 +298,11 @@ ngx_http_init_connection(ngx_connection_t *c)
|
|||||||
hc->conf_ctx = hc->addr_conf->default_server->ctx;
|
hc->conf_ctx = hc->addr_conf->default_server->ctx;
|
||||||
|
|
||||||
#if (NGX_HTTP_QUIC)
|
#if (NGX_HTTP_QUIC)
|
||||||
|
|
||||||
if (hc->addr_conf->quic) {
|
if (hc->addr_conf->quic) {
|
||||||
ngx_quic_conf_t *qcf;
|
if (ngx_http_quic_init(c) == NGX_DONE) {
|
||||||
ngx_http_connection_t *phc;
|
|
||||||
ngx_http_core_loc_conf_t *clcf;
|
|
||||||
|
|
||||||
hc->ssl = 1;
|
|
||||||
|
|
||||||
#if (NGX_HTTP_V3)
|
|
||||||
|
|
||||||
if (hc->addr_conf->http3) {
|
|
||||||
ngx_int_t rc;
|
|
||||||
|
|
||||||
rc = ngx_http_v3_init_connection(c);
|
|
||||||
|
|
||||||
if (rc == NGX_ERROR) {
|
|
||||||
ngx_http_close_connection(c);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == NGX_DONE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (c->quic == NULL) {
|
|
||||||
c->log->connection = c->number;
|
|
||||||
|
|
||||||
qcf = ngx_http_get_module_srv_conf(hc->conf_ctx,
|
|
||||||
ngx_http_quic_module);
|
|
||||||
ngx_quic_run(c, qcf);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
phc = c->quic->parent->data;
|
|
||||||
|
|
||||||
if (phc->ssl_servername) {
|
|
||||||
hc->ssl_servername = phc->ssl_servername;
|
|
||||||
hc->conf_ctx = phc->conf_ctx;
|
|
||||||
|
|
||||||
clcf = ngx_http_get_module_loc_conf(hc->conf_ctx,
|
|
||||||
ngx_http_core_module);
|
|
||||||
ngx_set_connection_log(c, clcf->error_log);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
|
ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
|
||||||
@ -380,6 +332,13 @@ ngx_http_init_connection(ngx_connection_t *c)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (NGX_HTTP_V3)
|
||||||
|
if (hc->addr_conf->http3) {
|
||||||
|
ngx_http_v3_init(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (NGX_HTTP_SSL)
|
#if (NGX_HTTP_SSL)
|
||||||
{
|
{
|
||||||
ngx_http_ssl_srv_conf_t *sscf;
|
ngx_http_ssl_srv_conf_t *sscf;
|
||||||
@ -669,12 +628,6 @@ ngx_http_alloc_request(ngx_connection_t *c)
|
|||||||
r->method = NGX_HTTP_UNKNOWN;
|
r->method = NGX_HTTP_UNKNOWN;
|
||||||
r->http_version = NGX_HTTP_VERSION_10;
|
r->http_version = NGX_HTTP_VERSION_10;
|
||||||
|
|
||||||
#if (NGX_HTTP_V3)
|
|
||||||
if (hc->addr_conf->http3) {
|
|
||||||
r->http_version = NGX_HTTP_VERSION_30;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
r->headers_in.content_length_n = -1;
|
r->headers_in.content_length_n = -1;
|
||||||
r->headers_in.keep_alive_n = -1;
|
r->headers_in.keep_alive_n = -1;
|
||||||
r->headers_out.content_length_n = -1;
|
r->headers_out.content_length_n = -1;
|
||||||
@ -1140,16 +1093,7 @@ ngx_http_process_request_line(ngx_event_t *rev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (r->http_version) {
|
rc = ngx_http_parse_request_line(r, r->header_in);
|
||||||
#if (NGX_HTTP_V3)
|
|
||||||
case NGX_HTTP_VERSION_30:
|
|
||||||
rc = ngx_http_v3_parse_request(r, r->header_in);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default: /* HTTP/1.x */
|
|
||||||
rc = ngx_http_parse_request_line(r, r->header_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == NGX_OK) {
|
if (rc == NGX_OK) {
|
||||||
|
|
||||||
@ -1157,7 +1101,7 @@ ngx_http_process_request_line(ngx_event_t *rev)
|
|||||||
|
|
||||||
r->request_line.len = r->request_end - r->request_start;
|
r->request_line.len = r->request_end - r->request_start;
|
||||||
r->request_line.data = r->request_start;
|
r->request_line.data = r->request_start;
|
||||||
r->request_length = r->header_in->pos - r->parse_start;
|
r->request_length = r->header_in->pos - r->request_start;
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
||||||
"http request line: \"%V\"", &r->request_line);
|
"http request line: \"%V\"", &r->request_line);
|
||||||
@ -1234,15 +1178,6 @@ ngx_http_process_request_line(ngx_event_t *rev)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_BUSY) {
|
|
||||||
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
|
||||||
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc != NGX_AGAIN) {
|
if (rc != NGX_AGAIN) {
|
||||||
|
|
||||||
/* there was error while a request line parsing */
|
/* there was error while a request line parsing */
|
||||||
@ -1272,8 +1207,8 @@ ngx_http_process_request_line(ngx_event_t *rev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rv == NGX_DECLINED) {
|
if (rv == NGX_DECLINED) {
|
||||||
r->request_line.len = r->header_in->end - r->parse_start;
|
r->request_line.len = r->header_in->end - r->request_start;
|
||||||
r->request_line.data = r->parse_start;
|
r->request_line.data = r->request_start;
|
||||||
|
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
"client sent too long URI");
|
"client sent too long URI");
|
||||||
@ -1437,7 +1372,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
|
|
||||||
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||||
|
|
||||||
rc = NGX_OK;
|
rc = NGX_AGAIN;
|
||||||
|
|
||||||
for ( ;; ) {
|
for ( ;; ) {
|
||||||
|
|
||||||
@ -1453,7 +1388,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rv == NGX_DECLINED) {
|
if (rv == NGX_DECLINED) {
|
||||||
p = r->parse_start;
|
p = r->header_name_start;
|
||||||
|
|
||||||
r->lingering_close = 1;
|
r->lingering_close = 1;
|
||||||
|
|
||||||
@ -1473,7 +1408,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
|
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
"client sent too long header line: \"%*s...\"",
|
"client sent too long header line: \"%*s...\"",
|
||||||
len, r->parse_start);
|
len, r->header_name_start);
|
||||||
|
|
||||||
ngx_http_finalize_request(r,
|
ngx_http_finalize_request(r,
|
||||||
NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
|
NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
|
||||||
@ -1491,32 +1426,21 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
/* the host header could change the server configuration context */
|
/* the host header could change the server configuration context */
|
||||||
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
||||||
|
|
||||||
switch (r->http_version) {
|
rc = ngx_http_parse_header_line(r, r->header_in,
|
||||||
#if (NGX_HTTP_V3)
|
cscf->underscores_in_headers);
|
||||||
case NGX_HTTP_VERSION_30:
|
|
||||||
rc = ngx_http_v3_parse_header(r, r->header_in,
|
|
||||||
cscf->underscores_in_headers);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
default: /* HTTP/1.x */
|
|
||||||
rc = ngx_http_parse_header_line(r, r->header_in,
|
|
||||||
cscf->underscores_in_headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == NGX_OK) {
|
if (rc == NGX_OK) {
|
||||||
|
|
||||||
r->request_length += r->header_in->pos - r->parse_start;
|
r->request_length += r->header_in->pos - r->header_name_start;
|
||||||
|
|
||||||
if (r->invalid_header && cscf->ignore_invalid_headers) {
|
if (r->invalid_header && cscf->ignore_invalid_headers) {
|
||||||
|
|
||||||
/* there was error while a header line parsing */
|
/* there was error while a header line parsing */
|
||||||
|
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
"client sent invalid header line: \"%*s: %*s\"",
|
"client sent invalid header line: \"%*s\"",
|
||||||
r->header_name_end - r->header_name_start,
|
r->header_end - r->header_name_start,
|
||||||
r->header_name_start,
|
r->header_name_start);
|
||||||
r->header_end - r->header_start, r->header_start);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1532,17 +1456,11 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
|
|
||||||
h->key.len = r->header_name_end - r->header_name_start;
|
h->key.len = r->header_name_end - r->header_name_start;
|
||||||
h->key.data = r->header_name_start;
|
h->key.data = r->header_name_start;
|
||||||
|
h->key.data[h->key.len] = '\0';
|
||||||
if (h->key.data[h->key.len]) {
|
|
||||||
h->key.data[h->key.len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
h->value.len = r->header_end - r->header_start;
|
h->value.len = r->header_end - r->header_start;
|
||||||
h->value.data = r->header_start;
|
h->value.data = r->header_start;
|
||||||
|
h->value.data[h->value.len] = '\0';
|
||||||
if (h->value.data[h->value.len]) {
|
|
||||||
h->value.data[h->value.len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
|
||||||
if (h->lowcase_key == NULL) {
|
if (h->lowcase_key == NULL) {
|
||||||
@ -1578,7 +1496,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
|
|||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http header done");
|
"http header done");
|
||||||
|
|
||||||
r->request_length += r->header_in->pos - r->parse_start;
|
r->request_length += r->header_in->pos - r->header_name_start;
|
||||||
|
|
||||||
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
|
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
|
||||||
|
|
||||||
@ -1693,7 +1611,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
|
|||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
old = r->parse_start;
|
old = request_line ? r->request_start : r->header_name_start;
|
||||||
|
|
||||||
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
||||||
|
|
||||||
@ -1771,14 +1689,6 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
|
|||||||
b->pos = new + (r->header_in->pos - old);
|
b->pos = new + (r->header_in->pos - old);
|
||||||
b->last = new + (r->header_in->pos - old);
|
b->last = new + (r->header_in->pos - old);
|
||||||
|
|
||||||
r->parse_start = new;
|
|
||||||
|
|
||||||
r->header_in = b;
|
|
||||||
|
|
||||||
if (r->http_version > NGX_HTTP_VERSION_11) {
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (request_line) {
|
if (request_line) {
|
||||||
r->request_start = new;
|
r->request_start = new;
|
||||||
|
|
||||||
@ -1827,6 +1737,8 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
|
|||||||
r->header_end = new + (r->header_end - old);
|
r->header_end = new + (r->header_end - old);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r->header_in = b;
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2047,46 +1959,13 @@ ngx_http_process_request_header(ngx_http_request_t *r)
|
|||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_11) {
|
if (r->headers_in.host == NULL && r->http_version > NGX_HTTP_VERSION_10) {
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
"client sent HTTP/1.1 request without \"Host\" header");
|
"client sent HTTP/1.1 request without \"Host\" header");
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->headers_in.host == NULL && r->http_version == NGX_HTTP_VERSION_20) {
|
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
|
||||||
"client sent HTTP/2 request without "
|
|
||||||
"\":authority\" or \"Host\" header");
|
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->http_version == NGX_HTTP_VERSION_30) {
|
|
||||||
if (r->headers_in.server.len == 0) {
|
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
|
||||||
"client sent HTTP/3 request without "
|
|
||||||
"\":authority\" or \"Host\" header");
|
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->headers_in.host) {
|
|
||||||
if (r->headers_in.host->value.len != r->headers_in.server.len
|
|
||||||
|| ngx_memcmp(r->headers_in.host->value.data,
|
|
||||||
r->headers_in.server.data,
|
|
||||||
r->headers_in.server.len)
|
|
||||||
!= 0)
|
|
||||||
{
|
|
||||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
|
||||||
"client sent HTTP/3 request with different "
|
|
||||||
"values of \":authority\" and \"Host\" headers");
|
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r->headers_in.content_length) {
|
if (r->headers_in.content_length) {
|
||||||
r->headers_in.content_length_n =
|
r->headers_in.content_length_n =
|
||||||
ngx_atoof(r->headers_in.content_length->value.data,
|
ngx_atoof(r->headers_in.content_length->value.data,
|
||||||
@ -2125,12 +2004,6 @@ ngx_http_process_request_header(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if (NGX_HTTP_V3)
|
|
||||||
if (r->http_version == NGX_HTTP_VERSION_30) {
|
|
||||||
r->headers_in.chunked = 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) {
|
if (r->headers_in.connection_type == NGX_HTTP_CONNECTION_KEEP_ALIVE) {
|
||||||
if (r->headers_in.keep_alive) {
|
if (r->headers_in.keep_alive) {
|
||||||
r->headers_in.keep_alive_n =
|
r->headers_in.keep_alive_n =
|
||||||
@ -2235,7 +2108,7 @@ ngx_http_process_request(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
ngx_int_t
|
||||||
ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
|
ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
|
||||||
{
|
{
|
||||||
u_char *h, ch;
|
u_char *h, ch;
|
||||||
@ -2326,7 +2199,7 @@ ngx_http_validate_host(ngx_str_t *host, ngx_pool_t *pool, ngx_uint_t alloc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static ngx_int_t
|
ngx_int_t
|
||||||
ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host)
|
ngx_http_set_virtual_server(ngx_http_request_t *r, ngx_str_t *host)
|
||||||
{
|
{
|
||||||
ngx_int_t rc;
|
ngx_int_t rc;
|
||||||
@ -3744,7 +3617,7 @@ ngx_http_post_action(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void
|
void
|
||||||
ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
|
ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
|
||||||
{
|
{
|
||||||
ngx_connection_t *c;
|
ngx_connection_t *c;
|
||||||
@ -3965,15 +3838,15 @@ ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr,
|
|||||||
len -= p - buf;
|
len -= p - buf;
|
||||||
buf = p;
|
buf = p;
|
||||||
|
|
||||||
if (r->request_line.data == NULL && r->parse_start) {
|
if (r->request_line.data == NULL && r->request_start) {
|
||||||
for (p = r->parse_start; p < r->header_in->last; p++) {
|
for (p = r->request_start; p < r->header_in->last; p++) {
|
||||||
if (*p == CR || *p == LF) {
|
if (*p == CR || *p == LF) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r->request_line.len = p - r->parse_start;
|
r->request_line.len = p - r->request_start;
|
||||||
r->request_line.data = r->parse_start;
|
r->request_line.data = r->request_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (r->request_line.len) {
|
if (r->request_line.len) {
|
||||||
|
@ -325,6 +325,7 @@ typedef struct {
|
|||||||
|
|
||||||
unsigned ssl:1;
|
unsigned ssl:1;
|
||||||
unsigned proxy_protocol:1;
|
unsigned proxy_protocol:1;
|
||||||
|
unsigned http3:1;
|
||||||
} ngx_http_connection_t;
|
} ngx_http_connection_t;
|
||||||
|
|
||||||
|
|
||||||
@ -581,7 +582,6 @@ struct ngx_http_request_s {
|
|||||||
* via ngx_http_ephemeral_t
|
* via ngx_http_ephemeral_t
|
||||||
*/
|
*/
|
||||||
|
|
||||||
u_char *parse_start;
|
|
||||||
u_char *uri_start;
|
u_char *uri_start;
|
||||||
u_char *uri_end;
|
u_char *uri_end;
|
||||||
u_char *uri_ext;
|
u_char *uri_ext;
|
||||||
|
@ -127,17 +127,11 @@ typedef struct {
|
|||||||
uint64_t next_push_id;
|
uint64_t next_push_id;
|
||||||
uint64_t max_push_id;
|
uint64_t max_push_id;
|
||||||
|
|
||||||
ngx_uint_t settings_sent;
|
|
||||||
/* unsigned settings_sent:1; */
|
|
||||||
ngx_connection_t *known_streams[NGX_HTTP_V3_MAX_KNOWN_STREAM];
|
ngx_connection_t *known_streams[NGX_HTTP_V3_MAX_KNOWN_STREAM];
|
||||||
} ngx_http_v3_connection_t;
|
} ngx_http_v3_connection_t;
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t ngx_http_v3_init_connection(ngx_connection_t *c);
|
void ngx_http_v3_init(ngx_connection_t *c);
|
||||||
|
|
||||||
ngx_int_t ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b);
|
|
||||||
ngx_int_t ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b,
|
|
||||||
ngx_uint_t allow_underscores);
|
|
||||||
ngx_int_t ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
|
ngx_int_t ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
|
||||||
ngx_http_chunked_t *ctx);
|
ngx_http_chunked_t *ctx);
|
||||||
|
|
||||||
@ -157,6 +151,8 @@ uintptr_t ngx_http_v3_encode_header_pbi(u_char *p, ngx_uint_t index);
|
|||||||
uintptr_t ngx_http_v3_encode_header_lpbi(u_char *p, ngx_uint_t index,
|
uintptr_t ngx_http_v3_encode_header_lpbi(u_char *p, ngx_uint_t index,
|
||||||
u_char *data, size_t len);
|
u_char *data, size_t len);
|
||||||
|
|
||||||
|
ngx_int_t ngx_http_v3_init_session(ngx_connection_t *c);
|
||||||
|
void ngx_http_v3_init_uni_stream(ngx_connection_t *c);
|
||||||
ngx_connection_t *ngx_http_v3_create_push_stream(ngx_connection_t *c,
|
ngx_connection_t *ngx_http_v3_create_push_stream(ngx_connection_t *c,
|
||||||
uint64_t push_id);
|
uint64_t push_id);
|
||||||
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
|
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
|
||||||
|
@ -10,8 +10,13 @@
|
|||||||
#include <ngx_http.h>
|
#include <ngx_http.h>
|
||||||
|
|
||||||
|
|
||||||
|
static void ngx_http_v3_process_request(ngx_event_t *rev);
|
||||||
|
static ngx_int_t ngx_http_v3_process_header(ngx_http_request_t *r,
|
||||||
|
ngx_str_t *name, ngx_str_t *value);
|
||||||
static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
|
static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
|
||||||
ngx_str_t *name, ngx_str_t *value);
|
ngx_str_t *name, ngx_str_t *value);
|
||||||
|
static ngx_int_t ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r);
|
||||||
|
static ngx_int_t ngx_http_v3_process_request_header(ngx_http_request_t *r);
|
||||||
|
|
||||||
|
|
||||||
static const struct {
|
static const struct {
|
||||||
@ -37,230 +42,256 @@ static const struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
void
|
||||||
ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b)
|
ngx_http_v3_init(ngx_connection_t *c)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t size;
|
||||||
u_char *p;
|
ngx_buf_t *b;
|
||||||
ngx_int_t rc, n;
|
ngx_event_t *rev;
|
||||||
ngx_str_t *name, *value;
|
ngx_http_request_t *r;
|
||||||
|
ngx_http_connection_t *hc;
|
||||||
|
ngx_http_core_srv_conf_t *cscf;
|
||||||
|
|
||||||
|
if (ngx_http_v3_init_session(c) != NGX_OK) {
|
||||||
|
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
||||||
|
"internal error");
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
|
||||||
|
ngx_http_v3_init_uni_stream(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream");
|
||||||
|
|
||||||
|
hc = c->data;
|
||||||
|
|
||||||
|
cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
|
||||||
|
|
||||||
|
size = cscf->client_header_buffer_size;
|
||||||
|
|
||||||
|
b = c->buffer;
|
||||||
|
|
||||||
|
if (b == NULL) {
|
||||||
|
b = ngx_create_temp_buf(c->pool, size);
|
||||||
|
if (b == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->buffer = b;
|
||||||
|
|
||||||
|
} else if (b->start == NULL) {
|
||||||
|
|
||||||
|
b->start = ngx_palloc(c->pool, size);
|
||||||
|
if (b->start == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->pos = b->start;
|
||||||
|
b->last = b->start;
|
||||||
|
b->end = b->last + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
c->log->action = "reading client request";
|
||||||
|
|
||||||
|
r = ngx_http_create_request(c);
|
||||||
|
if (r == NULL) {
|
||||||
|
ngx_http_close_connection(c);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->http_version = NGX_HTTP_VERSION_30;
|
||||||
|
|
||||||
|
c->data = r;
|
||||||
|
|
||||||
|
rev = c->read;
|
||||||
|
rev->handler = ngx_http_v3_process_request;
|
||||||
|
|
||||||
|
ngx_http_v3_process_request(rev);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
ngx_http_v3_process_request(ngx_event_t *rev)
|
||||||
|
{
|
||||||
|
ssize_t n;
|
||||||
|
ngx_buf_t *b;
|
||||||
|
ngx_int_t rc;
|
||||||
ngx_connection_t *c;
|
ngx_connection_t *c;
|
||||||
|
ngx_http_request_t *r;
|
||||||
|
ngx_http_core_srv_conf_t *cscf;
|
||||||
ngx_http_v3_parse_headers_t *st;
|
ngx_http_v3_parse_headers_t *st;
|
||||||
|
|
||||||
c = r->connection;
|
c = rev->data;
|
||||||
|
r = c->data;
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http3 process request");
|
||||||
|
|
||||||
|
if (rev->timedout) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
|
||||||
|
c->timedout = 1;
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
st = r->h3_parse;
|
st = r->h3_parse;
|
||||||
|
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 parse header");
|
|
||||||
|
|
||||||
st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t));
|
st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t));
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
goto failed;
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
r->h3_parse = st;
|
r->h3_parse = st;
|
||||||
r->parse_start = b->pos;
|
|
||||||
r->state = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (b->pos < b->last) {
|
b = r->header_in;
|
||||||
|
|
||||||
|
for ( ;; ) {
|
||||||
|
|
||||||
|
if (b->pos == b->last) {
|
||||||
|
|
||||||
|
if (!rev->ready) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = c->recv(c, b->start, b->end - b->start);
|
||||||
|
|
||||||
|
if (n == NGX_AGAIN) {
|
||||||
|
if (!rev->timer_set) {
|
||||||
|
cscf = ngx_http_get_module_srv_conf(r,
|
||||||
|
ngx_http_core_module);
|
||||||
|
ngx_add_timer(rev, cscf->client_header_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
||||||
|
"client prematurely closed connection");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n == 0 || n == NGX_ERROR) {
|
||||||
|
c->error = 1;
|
||||||
|
c->log->action = "reading client request";
|
||||||
|
|
||||||
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->pos = b->start;
|
||||||
|
b->last = b->start + n;
|
||||||
|
}
|
||||||
|
|
||||||
rc = ngx_http_v3_parse_headers(c, st, *b->pos);
|
rc = ngx_http_v3_parse_headers(c, st, *b->pos);
|
||||||
|
|
||||||
if (rc > 0) {
|
if (rc > 0) {
|
||||||
ngx_http_v3_finalize_connection(c, rc,
|
ngx_http_v3_finalize_connection(c, rc,
|
||||||
"could not parse request headers");
|
"could not parse request headers");
|
||||||
goto failed;
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_ERROR) {
|
if (rc == NGX_ERROR) {
|
||||||
goto failed;
|
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
||||||
|
"internal error");
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_BUSY) {
|
if (rc == NGX_BUSY) {
|
||||||
return NGX_BUSY;
|
if (rev->error) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_CLOSE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
b->pos++;
|
b->pos++;
|
||||||
|
r->request_length++;
|
||||||
|
|
||||||
if (rc == NGX_AGAIN) {
|
if (rc == NGX_AGAIN) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = &st->header_rep.header.name;
|
/* rc == NGX_OK || rc == NGX_DONE */
|
||||||
value = &st->header_rep.header.value;
|
|
||||||
|
|
||||||
n = ngx_http_v3_process_pseudo_header(r, name, value);
|
if (ngx_http_v3_process_header(r, &st->header_rep.header.name,
|
||||||
|
&st->header_rep.header.value)
|
||||||
if (n == NGX_ERROR) {
|
!= NGX_OK)
|
||||||
goto failed;
|
{
|
||||||
}
|
break;
|
||||||
|
|
||||||
if (n == NGX_OK && rc == NGX_OK) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = r->method_name.len + 1
|
|
||||||
+ (r->uri_end - r->uri_start) + 1
|
|
||||||
+ sizeof("HTTP/3.0") - 1;
|
|
||||||
|
|
||||||
p = ngx_pnalloc(c->pool, len);
|
|
||||||
if (p == NULL) {
|
|
||||||
goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
r->request_start = p;
|
|
||||||
|
|
||||||
p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
|
|
||||||
r->method_end = p - 1;
|
|
||||||
*p++ = ' ';
|
|
||||||
p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
|
|
||||||
*p++ = ' ';
|
|
||||||
r->http_protocol.data = p;
|
|
||||||
p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1);
|
|
||||||
|
|
||||||
r->request_end = p;
|
|
||||||
r->state = 0;
|
|
||||||
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NGX_AGAIN;
|
|
||||||
|
|
||||||
failed:
|
|
||||||
|
|
||||||
return NGX_HTTP_PARSE_INVALID_REQUEST;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
|
||||||
ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b,
|
|
||||||
ngx_uint_t allow_underscores)
|
|
||||||
{
|
|
||||||
u_char ch;
|
|
||||||
ngx_int_t rc;
|
|
||||||
ngx_str_t *name, *value;
|
|
||||||
ngx_uint_t hash, i, n;
|
|
||||||
ngx_connection_t *c;
|
|
||||||
ngx_http_v3_parse_headers_t *st;
|
|
||||||
enum {
|
|
||||||
sw_start = 0,
|
|
||||||
sw_done,
|
|
||||||
sw_next,
|
|
||||||
sw_header
|
|
||||||
};
|
|
||||||
|
|
||||||
c = r->connection;
|
|
||||||
st = r->h3_parse;
|
|
||||||
|
|
||||||
switch (r->state) {
|
|
||||||
|
|
||||||
case sw_start:
|
|
||||||
r->parse_start = b->pos;
|
|
||||||
|
|
||||||
if (st->state) {
|
|
||||||
r->state = sw_next;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = &st->header_rep.header.name;
|
|
||||||
|
|
||||||
if (name->len && name->data[0] != ':') {
|
|
||||||
r->state = sw_done;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* fall through */
|
|
||||||
|
|
||||||
case sw_done:
|
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
|
||||||
"http3 parse header done");
|
|
||||||
return NGX_HTTP_PARSE_HEADER_DONE;
|
|
||||||
|
|
||||||
case sw_next:
|
|
||||||
r->parse_start = b->pos;
|
|
||||||
r->invalid_header = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case sw_header:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (b->pos < b->last) {
|
|
||||||
rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
|
|
||||||
|
|
||||||
if (rc > 0) {
|
|
||||||
ngx_http_v3_finalize_connection(c, rc,
|
|
||||||
"could not parse request headers");
|
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rc == NGX_ERROR) {
|
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_DONE) {
|
if (rc == NGX_DONE) {
|
||||||
r->state = sw_done;
|
if (ngx_http_v3_process_request_header(r) != NGX_OK) {
|
||||||
goto done;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == NGX_OK) {
|
ngx_http_process_request(r);
|
||||||
r->state = sw_next;
|
break;
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r->state = sw_header;
|
ngx_http_run_posted_requests(c);
|
||||||
return NGX_AGAIN;
|
|
||||||
|
|
||||||
done:
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
name = &st->header_rep.header.name;
|
|
||||||
value = &st->header_rep.header.value;
|
|
||||||
|
|
||||||
r->header_name_start = name->data;
|
static ngx_int_t
|
||||||
r->header_name_end = name->data + name->len;
|
ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
|
||||||
r->header_start = value->data;
|
ngx_str_t *value)
|
||||||
r->header_end = value->data + value->len;
|
{
|
||||||
|
ngx_table_elt_t *h;
|
||||||
|
ngx_http_header_t *hh;
|
||||||
|
ngx_http_core_main_conf_t *cmcf;
|
||||||
|
|
||||||
hash = 0;
|
if (name->len && name->data[0] == ':') {
|
||||||
i = 0;
|
return ngx_http_v3_process_pseudo_header(r, name, value);
|
||||||
|
|
||||||
for (n = 0; n < name->len; n++) {
|
|
||||||
ch = name->data[n];
|
|
||||||
|
|
||||||
if (ch >= 'A' && ch <= 'Z') {
|
|
||||||
/*
|
|
||||||
* A request or response containing uppercase
|
|
||||||
* header field names MUST be treated as malformed
|
|
||||||
*/
|
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '\0') {
|
|
||||||
return NGX_HTTP_PARSE_INVALID_HEADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ch == '_' && !allow_underscores) {
|
|
||||||
r->invalid_header = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ch < 'a' || ch > 'z')
|
|
||||||
&& (ch < '0' || ch > '9')
|
|
||||||
&& ch != '-' && ch != '_')
|
|
||||||
{
|
|
||||||
r->invalid_header = 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash = ngx_hash(hash, ch);
|
|
||||||
r->lowcase_header[i++] = ch;
|
|
||||||
i &= (NGX_HTTP_LC_HEADER_LEN - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r->header_hash = hash;
|
if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
|
||||||
r->lowcase_index = i;
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
h = ngx_list_push(&r->headers_in.headers);
|
||||||
|
if (h == NULL) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
h->key = *name;
|
||||||
|
h->value = *value;
|
||||||
|
h->lowcase_key = h->key.data;
|
||||||
|
h->hash = ngx_hash_key(h->key.data, h->key.len);
|
||||||
|
|
||||||
|
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
|
||||||
|
|
||||||
|
hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
|
||||||
|
h->lowcase_key, h->key.len);
|
||||||
|
|
||||||
|
if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
|
"http3 header: \"%V: %V\"", name, value);
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,75 +300,210 @@ static ngx_int_t
|
|||||||
ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
|
ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
|
||||||
ngx_str_t *value)
|
ngx_str_t *value)
|
||||||
{
|
{
|
||||||
ngx_uint_t i;
|
ngx_uint_t i;
|
||||||
ngx_connection_t *c;
|
|
||||||
|
|
||||||
if (name->len == 0 || name->data[0] != ':') {
|
if (r->request_line.len) {
|
||||||
return NGX_DONE;
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client sent out of order pseudo-headers");
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = r->connection;
|
|
||||||
|
|
||||||
if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) {
|
if (name->len == 7 && ngx_strncmp(name->data, ":method", 7) == 0) {
|
||||||
|
|
||||||
r->method_name = *value;
|
r->method_name = *value;
|
||||||
|
|
||||||
for (i = 0; i < sizeof(ngx_http_v3_methods)
|
for (i = 0; i < sizeof(ngx_http_v3_methods)
|
||||||
/ sizeof(ngx_http_v3_methods[0]); i++)
|
/ sizeof(ngx_http_v3_methods[0]); i++)
|
||||||
{
|
{
|
||||||
if (value->len == ngx_http_v3_methods[i].name.len
|
if (value->len == ngx_http_v3_methods[i].name.len
|
||||||
&& ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data,
|
&& ngx_strncmp(value->data,
|
||||||
value->len) == 0)
|
ngx_http_v3_methods[i].name.data, value->len)
|
||||||
|
== 0)
|
||||||
{
|
{
|
||||||
r->method = ngx_http_v3_methods[i].method;
|
r->method = ngx_http_v3_methods[i].method;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http3 method \"%V\" %ui", value, r->method);
|
"http3 method \"%V\" %ui", value, r->method);
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) {
|
if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) {
|
||||||
|
|
||||||
r->uri_start = value->data;
|
r->uri_start = value->data;
|
||||||
r->uri_end = value->data + value->len;
|
r->uri_end = value->data + value->len;
|
||||||
|
|
||||||
if (ngx_http_parse_uri(r) != NGX_OK) {
|
if (ngx_http_parse_uri(r) != NGX_OK) {
|
||||||
ngx_log_error(NGX_LOG_INFO, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
"client sent invalid :path header: \"%V\"", value);
|
"client sent invalid \":path\" header: \"%V\"",
|
||||||
return NGX_ERROR;
|
value);
|
||||||
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http3 path \"%V\"", value);
|
"http3 path \"%V\"", value);
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) {
|
if (name->len == 7 && ngx_strncmp(name->data, ":scheme", 7) == 0) {
|
||||||
r->schema_start = value->data;
|
|
||||||
r->schema_end = value->data + value->len;
|
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
r->schema = *value;
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http3 schema \"%V\"", value);
|
"http3 schema \"%V\"", value);
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) {
|
if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) {
|
||||||
|
|
||||||
r->host_start = value->data;
|
r->host_start = value->data;
|
||||||
r->host_end = value->data + value->len;
|
r->host_end = value->data + value->len;
|
||||||
|
|
||||||
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
"http3 authority \"%V\"", value);
|
"http3 authority \"%V\"", value);
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
"http3 unknown pseudo header \"%V\" \"%V\"", name, value);
|
"client sent unknown pseudo-header \"%V\"", name);
|
||||||
|
|
||||||
|
failed:
|
||||||
|
|
||||||
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
u_char *p;
|
||||||
|
ngx_int_t rc;
|
||||||
|
ngx_str_t host;
|
||||||
|
|
||||||
|
if (r->request_line.len) {
|
||||||
|
return NGX_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = r->method_name.len + 1
|
||||||
|
+ (r->uri_end - r->uri_start) + 1
|
||||||
|
+ sizeof("HTTP/3.0") - 1;
|
||||||
|
|
||||||
|
p = ngx_pnalloc(r->pool, len);
|
||||||
|
if (p == NULL) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->request_line.data = p;
|
||||||
|
|
||||||
|
p = ngx_cpymem(p, r->method_name.data, r->method_name.len);
|
||||||
|
*p++ = ' ';
|
||||||
|
p = ngx_cpymem(p, r->uri_start, r->uri_end - r->uri_start);
|
||||||
|
*p++ = ' ';
|
||||||
|
p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1);
|
||||||
|
|
||||||
|
r->request_line.len = p - r->request_line.data;
|
||||||
|
|
||||||
|
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
|
||||||
|
"http3 request line: \"%V\"", &r->request_line);
|
||||||
|
|
||||||
|
ngx_str_set(&r->http_protocol, "HTTP/3.0");
|
||||||
|
|
||||||
|
if (ngx_http_process_request_uri(r) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->host_end) {
|
||||||
|
|
||||||
|
host.len = r->host_end - r->host_start;
|
||||||
|
host.data = r->host_start;
|
||||||
|
|
||||||
|
rc = ngx_http_validate_host(&host, r->pool, 0);
|
||||||
|
|
||||||
|
if (rc == NGX_DECLINED) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client sent invalid host in request line");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rc == NGX_ERROR) {
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
r->headers_in.server = host;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
|
||||||
|
sizeof(ngx_table_elt_t))
|
||||||
|
!= NGX_OK)
|
||||||
|
{
|
||||||
|
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
|
||||||
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static ngx_int_t
|
||||||
|
ngx_http_v3_process_request_header(ngx_http_request_t *r)
|
||||||
|
{
|
||||||
|
if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->headers_in.server.len == 0) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client sent neither \":authority\" nor \"Host\" header");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->headers_in.host) {
|
||||||
|
if (r->headers_in.host->value.len != r->headers_in.server.len
|
||||||
|
|| ngx_memcmp(r->headers_in.host->value.data,
|
||||||
|
r->headers_in.server.data,
|
||||||
|
r->headers_in.server.len)
|
||||||
|
!= 0)
|
||||||
|
{
|
||||||
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client sent \":authority\" and \"Host\" headers "
|
||||||
|
"with different values");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r->headers_in.content_length) {
|
||||||
|
r->headers_in.content_length_n =
|
||||||
|
ngx_atoof(r->headers_in.content_length->value.data,
|
||||||
|
r->headers_in.content_length->value.len);
|
||||||
|
|
||||||
|
if (r->headers_in.content_length_n == NGX_ERROR) {
|
||||||
|
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||||
|
"client sent invalid \"Content-Length\" header");
|
||||||
|
goto failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NGX_OK;
|
||||||
|
|
||||||
|
failed:
|
||||||
|
|
||||||
|
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||||
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,44 +40,49 @@ static ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c);
|
|||||||
|
|
||||||
|
|
||||||
ngx_int_t
|
ngx_int_t
|
||||||
ngx_http_v3_init_connection(ngx_connection_t *c)
|
ngx_http_v3_init_session(ngx_connection_t *c)
|
||||||
{
|
{
|
||||||
ngx_http_connection_t *hc;
|
ngx_connection_t *pc;
|
||||||
ngx_http_v3_uni_stream_t *us;
|
ngx_http_connection_t *phc;
|
||||||
ngx_http_v3_connection_t *h3c;
|
ngx_http_v3_connection_t *h3c;
|
||||||
|
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init connection");
|
pc = c->quic->parent;
|
||||||
|
phc = pc->data;
|
||||||
|
|
||||||
hc = c->data;
|
if (phc->http3) {
|
||||||
|
|
||||||
if (c->quic == NULL) {
|
|
||||||
h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t));
|
|
||||||
if (h3c == NULL) {
|
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3c->hc = *hc;
|
|
||||||
|
|
||||||
ngx_queue_init(&h3c->blocked);
|
|
||||||
ngx_queue_init(&h3c->pushing);
|
|
||||||
|
|
||||||
c->data = h3c;
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ngx_http_v3_send_settings(c) == NGX_ERROR) {
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init session");
|
||||||
|
|
||||||
|
h3c = ngx_pcalloc(pc->pool, sizeof(ngx_http_v3_connection_t));
|
||||||
|
if (h3c == NULL) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) {
|
h3c->hc = *phc;
|
||||||
return NGX_OK;
|
h3c->hc.http3 = 1;
|
||||||
}
|
|
||||||
|
ngx_queue_init(&h3c->blocked);
|
||||||
|
ngx_queue_init(&h3c->pushing);
|
||||||
|
|
||||||
|
pc->data = h3c;
|
||||||
|
|
||||||
|
return ngx_http_v3_send_settings(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ngx_http_v3_init_uni_stream(ngx_connection_t *c)
|
||||||
|
{
|
||||||
|
ngx_http_v3_uni_stream_t *us;
|
||||||
|
|
||||||
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init uni stream");
|
||||||
|
|
||||||
us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
|
us = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_uni_stream_t));
|
||||||
if (us == NULL) {
|
if (us == NULL) {
|
||||||
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
ngx_http_close_connection(c);
|
||||||
NULL);
|
return;
|
||||||
return NGX_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
us->index = -1;
|
us->index = -1;
|
||||||
@ -88,8 +93,6 @@ ngx_http_v3_init_connection(ngx_connection_t *c)
|
|||||||
c->write->handler = ngx_http_v3_dummy_write_handler;
|
c->write->handler = ngx_http_v3_dummy_write_handler;
|
||||||
|
|
||||||
ngx_http_v3_read_uni_stream_type(c->read);
|
ngx_http_v3_read_uni_stream_type(c->read);
|
||||||
|
|
||||||
return NGX_DONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -478,10 +481,6 @@ ngx_http_v3_send_settings(ngx_connection_t *c)
|
|||||||
|
|
||||||
h3c = c->quic->parent->data;
|
h3c = c->quic->parent->data;
|
||||||
|
|
||||||
if (h3c->settings_sent) {
|
|
||||||
return NGX_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");
|
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 send settings");
|
||||||
|
|
||||||
cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
|
cc = ngx_http_v3_get_uni_stream(c, NGX_HTTP_V3_STREAM_CONTROL);
|
||||||
@ -512,17 +511,12 @@ ngx_http_v3_send_settings(ngx_connection_t *c)
|
|||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3c->settings_sent = 1;
|
|
||||||
|
|
||||||
return NGX_OK;
|
return NGX_OK;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
|
||||||
ngx_http_v3_close_uni_stream(cc);
|
ngx_http_v3_close_uni_stream(cc);
|
||||||
|
|
||||||
ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
|
|
||||||
"could not send settings");
|
|
||||||
|
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user