aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/http/modules/ngx_http_quic_module.c37
-rw-r--r--src/http/modules/ngx_http_quic_module.h2
-rw-r--r--src/http/ngx_http.h5
-rw-r--r--src/http/ngx_http_parse.c2
-rw-r--r--src/http/ngx_http_request.c197
-rw-r--r--src/http/ngx_http_request.h2
-rw-r--r--src/http/v3/ngx_http_v3.h10
-rw-r--r--src/http/v3/ngx_http_v3_request.c524
-rw-r--r--src/http/v3/ngx_http_v3_streams.c66
9 files changed, 457 insertions, 388 deletions
diff --git a/src/http/modules/ngx_http_quic_module.c b/src/http/modules/ngx_http_quic_module.c
index ff79cdc8d..5314af35b 100644
--- a/src/http/modules/ngx_http_quic_module.c
+++ b/src/http/modules/ngx_http_quic_module.c
@@ -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
ngx_http_variable_quic(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
diff --git a/src/http/modules/ngx_http_quic_module.h b/src/http/modules/ngx_http_quic_module.h
index bd4930f8a..bc75dd501 100644
--- a/src/http/modules/ngx_http_quic_module.h
+++ b/src/http/modules/ngx_http_quic_module.h
@@ -18,7 +18,7 @@
#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_ */
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 2a3d81a37..778744d71 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -134,6 +134,11 @@ void ngx_http_handler(ngx_http_request_t *r);
void ngx_http_run_posted_requests(ngx_connection_t *c);
ngx_int_t ngx_http_post_request(ngx_http_request_t *r,
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_free_request(ngx_http_request_t *r, ngx_int_t rc);
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 7b5cd30cd..20ad89a77 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -143,7 +143,6 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b)
/* HTTP methods: GET, HEAD, POST */
case sw_start:
- r->parse_start = p;
r->request_start = p;
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 */
case sw_start:
- r->parse_start = p;
r->header_name_start = p;
r->invalid_header = 0;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 0ce4dacec..abcc1bba8 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -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,
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,
ngx_http_virtual_names_t *virtual_names, ngx_str_t *host,
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_lingering_close_handler(ngx_event_t *ev);
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 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;
#if (NGX_HTTP_QUIC)
-
if (hc->addr_conf->quic) {
- ngx_quic_conf_t *qcf;
- 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);
+ if (ngx_http_quic_init(c) == NGX_DONE) {
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
ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
@@ -380,6 +332,13 @@ ngx_http_init_connection(ngx_connection_t *c)
}
#endif
+#if (NGX_HTTP_V3)
+ if (hc->addr_conf->http3) {
+ ngx_http_v3_init(c);
+ return;
+ }
+#endif
+
#if (NGX_HTTP_SSL)
{
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->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.keep_alive_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) {
-#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);
- }
+ rc = ngx_http_parse_request_line(r, r->header_in);
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.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,
"http request line: \"%V\"", &r->request_line);
@@ -1234,15 +1178,6 @@ ngx_http_process_request_line(ngx_event_t *rev)
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) {
/* 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) {
- r->request_line.len = r->header_in->end - r->parse_start;
- r->request_line.data = r->parse_start;
+ r->request_line.len = r->header_in->end - r->request_start;
+ r->request_line.data = r->request_start;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"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);
- rc = NGX_OK;
+ rc = NGX_AGAIN;
for ( ;; ) {
@@ -1453,7 +1388,7 @@ ngx_http_process_request_headers(ngx_event_t *rev)
}
if (rv == NGX_DECLINED) {
- p = r->parse_start;
+ p = r->header_name_start;
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,
"client sent too long header line: \"%*s...\"",
- len, r->parse_start);
+ len, r->header_name_start);
ngx_http_finalize_request(r,
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 */
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
- switch (r->http_version) {
-#if (NGX_HTTP_V3)
- 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);
- }
+ rc = ngx_http_parse_header_line(r, r->header_in,
+ cscf->underscores_in_headers);
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) {
/* there was error while a header line parsing */
ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client sent invalid header line: \"%*s: %*s\"",
- r->header_name_end - r->header_name_start,
- r->header_name_start,
- r->header_end - r->header_start, r->header_start);
+ "client sent invalid header line: \"%*s\"",
+ r->header_end - r->header_name_start,
+ r->header_name_start);
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.data = r->header_name_start;
-
- if (h->key.data[h->key.len]) {
- h->key.data[h->key.len] = '\0';
- }
+ h->key.data[h->key.len] = '\0';
h->value.len = r->header_end - r->header_start;
h->value.data = r->header_start;
-
- if (h->value.data[h->value.len]) {
- h->value.data[h->value.len] = '\0';
- }
+ h->value.data[h->value.len] = '\0';
h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);
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,
"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;
@@ -1693,7 +1611,7 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
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);
@@ -1771,14 +1689,6 @@ ngx_http_alloc_large_header_buffer(ngx_http_request_t *r,
b->pos = 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) {
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_in = b;
+
return NGX_OK;
}
@@ -2047,46 +1959,13 @@ ngx_http_process_request_header(ngx_http_request_t *r)
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,
"client sent HTTP/1.1 request without \"Host\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
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) {
r->headers_in.content_length_n =
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.keep_alive) {
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)
{
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_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_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;
buf = p;
- if (r->request_line.data == NULL && r->parse_start) {
- for (p = r->parse_start; p < r->header_in->last; p++) {
+ if (r->request_line.data == NULL && r->request_start) {
+ for (p = r->request_start; p < r->header_in->last; p++) {
if (*p == CR || *p == LF) {
break;
}
}
- r->request_line.len = p - r->parse_start;
- r->request_line.data = r->parse_start;
+ r->request_line.len = p - r->request_start;
+ r->request_line.data = r->request_start;
}
if (r->request_line.len) {
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 518c2f4d1..4121e3c3b 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -325,6 +325,7 @@ typedef struct {
unsigned ssl:1;
unsigned proxy_protocol:1;
+ unsigned http3:1;
} ngx_http_connection_t;
@@ -581,7 +582,6 @@ struct ngx_http_request_s {
* via ngx_http_ephemeral_t
*/
- u_char *parse_start;
u_char *uri_start;
u_char *uri_end;
u_char *uri_ext;
diff --git a/src/http/v3/ngx_http_v3.h b/src/http/v3/ngx_http_v3.h
index 89ed9c98a..9f91ff8f1 100644
--- a/src/http/v3/ngx_http_v3.h
+++ b/src/http/v3/ngx_http_v3.h
@@ -127,17 +127,11 @@ typedef struct {
uint64_t next_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_http_v3_connection_t;
-ngx_int_t ngx_http_v3_init_connection(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);
+void ngx_http_v3_init(ngx_connection_t *c);
ngx_int_t ngx_http_v3_parse_request_body(ngx_http_request_t *r, ngx_buf_t *b,
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,
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,
uint64_t push_id);
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
diff --git a/src/http/v3/ngx_http_v3_request.c b/src/http/v3/ngx_http_v3_request.c
index 4597bc180..09c1ec335 100644
--- a/src/http/v3/ngx_http_v3_request.c
+++ b/src/http/v3/ngx_http_v3_request.c
@@ -10,8 +10,13 @@
#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,
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 {
@@ -37,230 +42,256 @@ static const struct {
};
-ngx_int_t
-ngx_http_v3_parse_request(ngx_http_request_t *r, ngx_buf_t *b)
+void
+ngx_http_v3_init(ngx_connection_t *c)
{
- size_t len;
- u_char *p;
- ngx_int_t rc, n;
- ngx_str_t *name, *value;
- ngx_connection_t *c;
- ngx_http_v3_parse_headers_t *st;
-
- c = r->connection;
- st = r->h3_parse;
-
- 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));
- if (st == NULL) {
- goto failed;
- }
-
- r->h3_parse = st;
- r->parse_start = b->pos;
- r->state = 1;
+ size_t size;
+ ngx_buf_t *b;
+ ngx_event_t *rev;
+ 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;
}
- 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");
- goto failed;
- }
-
- if (rc == NGX_ERROR) {
- goto failed;
- }
+ if (c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) {
+ ngx_http_v3_init_uni_stream(c);
+ return;
+ }
- if (rc == NGX_BUSY) {
- return NGX_BUSY;
- }
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init request stream");
- b->pos++;
+ hc = c->data;
- if (rc == NGX_AGAIN) {
- continue;
- }
+ cscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_core_module);
- name = &st->header_rep.header.name;
- value = &st->header_rep.header.value;
+ size = cscf->client_header_buffer_size;
- n = ngx_http_v3_process_pseudo_header(r, name, value);
+ b = c->buffer;
- if (n == NGX_ERROR) {
- goto failed;
+ if (b == NULL) {
+ b = ngx_create_temp_buf(c->pool, size);
+ if (b == NULL) {
+ ngx_http_close_connection(c);
+ return;
}
- if (n == NGX_OK && rc == NGX_OK) {
- continue;
- }
+ c->buffer = b;
- len = r->method_name.len + 1
- + (r->uri_end - r->uri_start) + 1
- + sizeof("HTTP/3.0") - 1;
+ } else if (b->start == NULL) {
- p = ngx_pnalloc(c->pool, len);
- if (p == NULL) {
- goto failed;
+ b->start = ngx_palloc(c->pool, size);
+ if (b->start == NULL) {
+ ngx_http_close_connection(c);
+ return;
}
- 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);
+ b->pos = b->start;
+ b->last = b->start;
+ b->end = b->last + size;
+ }
- r->request_end = p;
- r->state = 0;
+ c->log->action = "reading client request";
- return NGX_OK;
+ r = ngx_http_create_request(c);
+ if (r == NULL) {
+ ngx_http_close_connection(c);
+ return;
}
- return NGX_AGAIN;
+ r->http_version = NGX_HTTP_VERSION_30;
-failed:
+ c->data = r;
- return NGX_HTTP_PARSE_INVALID_REQUEST;
+ rev = c->read;
+ rev->handler = ngx_http_v3_process_request;
+
+ ngx_http_v3_process_request(rev);
}
-ngx_int_t
-ngx_http_v3_parse_header(ngx_http_request_t *r, ngx_buf_t *b,
- ngx_uint_t allow_underscores)
+static void
+ngx_http_v3_process_request(ngx_event_t *rev)
{
- u_char ch;
+ ssize_t n;
+ ngx_buf_t *b;
ngx_int_t rc;
- ngx_str_t *name, *value;
- ngx_uint_t hash, i, n;
ngx_connection_t *c;
+ ngx_http_request_t *r;
+ ngx_http_core_srv_conf_t *cscf;
ngx_http_v3_parse_headers_t *st;
- enum {
- sw_start = 0,
- sw_done,
- sw_next,
- sw_header
- };
- c = r->connection;
- st = r->h3_parse;
+ c = rev->data;
+ r = c->data;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http3 process request");
- switch (r->state) {
+ 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;
+ }
- case sw_start:
- r->parse_start = b->pos;
+ st = r->h3_parse;
- if (st->state) {
- r->state = sw_next;
- goto done;
+ if (st == NULL) {
+ st = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_parse_headers_t));
+ if (st == NULL) {
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
}
- name = &st->header_rep.header.name;
+ r->h3_parse = st;
+ }
- if (name->len && name->data[0] != ':') {
- r->state = sw_done;
- goto done;
- }
+ b = r->header_in;
- /* fall through */
+ for ( ;; ) {
- case sw_done:
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "http3 parse header done");
- return NGX_HTTP_PARSE_HEADER_DONE;
+ if (b->pos == b->last) {
- case sw_next:
- r->parse_start = b->pos;
- r->invalid_header = 0;
- break;
+ if (!rev->ready) {
+ break;
+ }
- case sw_header:
- 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");
+ }
- while (b->pos < b->last) {
- rc = ngx_http_v3_parse_headers(c, st, *b->pos++);
+ 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);
if (rc > 0) {
ngx_http_v3_finalize_connection(c, rc,
"could not parse request headers");
- return NGX_HTTP_PARSE_INVALID_HEADER;
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ break;
}
if (rc == NGX_ERROR) {
- return NGX_HTTP_PARSE_INVALID_HEADER;
+ 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_DONE) {
- r->state = sw_done;
- goto done;
+ if (rc == 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;
}
- if (rc == NGX_OK) {
- r->state = sw_next;
- goto done;
+ b->pos++;
+ r->request_length++;
+
+ if (rc == NGX_AGAIN) {
+ continue;
}
- }
- r->state = sw_header;
- return NGX_AGAIN;
+ /* rc == NGX_OK || rc == NGX_DONE */
-done:
+ if (ngx_http_v3_process_header(r, &st->header_rep.header.name,
+ &st->header_rep.header.value)
+ != NGX_OK)
+ {
+ break;
+ }
- name = &st->header_rep.header.name;
- value = &st->header_rep.header.value;
+ if (rc == NGX_DONE) {
+ if (ngx_http_v3_process_request_header(r) != NGX_OK) {
+ break;
+ }
- r->header_name_start = name->data;
- r->header_name_end = name->data + name->len;
- r->header_start = value->data;
- r->header_end = value->data + value->len;
+ ngx_http_process_request(r);
+ break;
+ }
+ }
- hash = 0;
- i = 0;
+ ngx_http_run_posted_requests(c);
- for (n = 0; n < name->len; n++) {
- ch = name->data[n];
+ return;
+}
- 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;
- }
+static ngx_int_t
+ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
+ ngx_str_t *value)
+{
+ ngx_table_elt_t *h;
+ ngx_http_header_t *hh;
+ ngx_http_core_main_conf_t *cmcf;
- if (ch == '_' && !allow_underscores) {
- r->invalid_header = 1;
- continue;
- }
+ if (name->len && name->data[0] == ':') {
+ return ngx_http_v3_process_pseudo_header(r, name, value);
+ }
- if ((ch < 'a' || ch > 'z')
- && (ch < '0' || ch > '9')
- && ch != '-' && ch != '_')
- {
- r->invalid_header = 1;
- continue;
- }
+ if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
+ return NGX_ERROR;
+ }
- hash = ngx_hash(hash, ch);
- r->lowcase_header[i++] = ch;
- i &= (NGX_HTTP_LC_HEADER_LEN - 1);
+ h = ngx_list_push(&r->headers_in.headers);
+ if (h == NULL) {
+ ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_ERROR;
}
- r->header_hash = hash;
- r->lowcase_index = i;
+ 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;
}
@@ -269,75 +300,210 @@ static ngx_int_t
ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, ngx_str_t *name,
ngx_str_t *value)
{
- ngx_uint_t i;
- ngx_connection_t *c;
+ ngx_uint_t i;
- if (name->len == 0 || name->data[0] != ':') {
- return NGX_DONE;
+ if (r->request_line.len) {
+ 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) {
+
r->method_name = *value;
for (i = 0; i < sizeof(ngx_http_v3_methods)
/ sizeof(ngx_http_v3_methods[0]); i++)
{
if (value->len == ngx_http_v3_methods[i].name.len
- && ngx_strncmp(value->data, ngx_http_v3_methods[i].name.data,
- value->len) == 0)
+ && ngx_strncmp(value->data,
+ ngx_http_v3_methods[i].name.data, value->len)
+ == 0)
{
r->method = ngx_http_v3_methods[i].method;
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);
return NGX_OK;
}
if (name->len == 5 && ngx_strncmp(name->data, ":path", 5) == 0) {
+
r->uri_start = value->data;
r->uri_end = value->data + value->len;
if (ngx_http_parse_uri(r) != NGX_OK) {
- ngx_log_error(NGX_LOG_INFO, c->log, 0,
- "client sent invalid :path header: \"%V\"", value);
- return NGX_ERROR;
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "client sent invalid \":path\" header: \"%V\"",
+ 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);
-
return NGX_OK;
}
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,
- "http3 schema \"%V\"", value);
+ r->schema = *value;
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http3 schema \"%V\"", value);
return NGX_OK;
}
if (name->len == 10 && ngx_strncmp(name->data, ":authority", 10) == 0) {
+
r->host_start = value->data;
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);
+ return NGX_OK;
+ }
+
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "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;
}
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "http3 unknown pseudo header \"%V\" \"%V\"", name, value);
+ 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;
+
+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;
}
diff --git a/src/http/v3/ngx_http_v3_streams.c b/src/http/v3/ngx_http_v3_streams.c
index 8ac048715..871914065 100644
--- a/src/http/v3/ngx_http_v3_streams.c
+++ b/src/http/v3/ngx_http_v3_streams.c
@@ -40,44 +40,49 @@ static ngx_int_t ngx_http_v3_send_settings(ngx_connection_t *c);
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_http_v3_uni_stream_t *us;
+ ngx_connection_t *pc;
+ ngx_http_connection_t *phc;
ngx_http_v3_connection_t *h3c;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 init connection");
-
- hc = c->data;
-
- if (c->quic == NULL) {
- h3c = ngx_pcalloc(c->pool, sizeof(ngx_http_v3_connection_t));
- if (h3c == NULL) {
- return NGX_ERROR;
- }
+ pc = c->quic->parent;
+ phc = pc->data;
- h3c->hc = *hc;
-
- ngx_queue_init(&h3c->blocked);
- ngx_queue_init(&h3c->pushing);
-
- c->data = h3c;
+ if (phc->http3) {
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;
}
- if ((c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0) {
- return NGX_OK;
- }
+ h3c->hc = *phc;
+ 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));
if (us == NULL) {
- ngx_http_v3_finalize_connection(c, NGX_HTTP_V3_ERR_INTERNAL_ERROR,
- NULL);
- return NGX_ERROR;
+ ngx_http_close_connection(c);
+ return;
}
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;
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;
- if (h3c->settings_sent) {
- return NGX_OK;
- }
-
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);
@@ -512,17 +511,12 @@ ngx_http_v3_send_settings(ngx_connection_t *c)
goto failed;
}
- h3c->settings_sent = 1;
-
return NGX_OK;
failed:
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;
}