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);
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,
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));
}
#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;
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;
}
}
- 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) {
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);
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 */
}
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");
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
- rc = NGX_OK;
+ rc = NGX_AGAIN;
for ( ;; ) {
}
if (rv == NGX_DECLINED) {
- p = r->parse_start;
+ p = r->header_name_start;
r->lingering_close = 1;
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);
/* 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;
}
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) {
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;
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);
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;
r->header_end = new + (r->header_end - old);
}
+ r->header_in = b;
+
return NGX_OK;
}
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,
}
}
-#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 =
}
-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;
}
-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;
}
-static void
+void
ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
{
ngx_connection_t *c;
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) {
#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 {
};
-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;
}
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;
}