mirror of
https://github.com/nginx/nginx.git
synced 2026-05-28 04:12:47 -04:00
Allow HTTP CONNECT method passthrough
This commit allows h2/h3 connect method to passthrough nginx internal request parsing. Modules can then handle CONNECT method by setting allow_connect bit field to 1. The logic still aligns with HTTP/1.1, allow_connect is always checked first, 405 will return before 400 (Header parsing)
This commit is contained in:
parent
d44205284f
commit
352ee91f5f
3 changed files with 120 additions and 43 deletions
|
|
@ -79,7 +79,17 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
|
|||
|
||||
r->request_body = rb;
|
||||
|
||||
if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
|
||||
if (r->headers_in.content_length_n < 0
|
||||
&& !r->headers_in.chunked
|
||||
#if (NGX_HTTP_V2)
|
||||
&& !(r->stream && r->method == NGX_HTTP_CONNECT)
|
||||
#endif
|
||||
#if (NGX_HTTP_V3)
|
||||
&& !(r->http_version == NGX_HTTP_VERSION_30
|
||||
&& r->method == NGX_HTTP_CONNECT)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
r->request_body_no_buffering = 0;
|
||||
post_handler(r);
|
||||
return NGX_OK;
|
||||
|
|
|
|||
|
|
@ -3570,34 +3570,64 @@ ngx_http_v2_parse_authority(ngx_http_request_t *r, ngx_str_t *value)
|
|||
static ngx_int_t
|
||||
ngx_http_v2_construct_request_line(ngx_http_request_t *r)
|
||||
{
|
||||
u_char *p;
|
||||
size_t len;
|
||||
u_char *p;
|
||||
ngx_http_core_srv_conf_t *cscf;
|
||||
|
||||
static const u_char ending[] = " HTTP/2.0";
|
||||
|
||||
if (r->method_name.len == 0
|
||||
|| r->schema.len == 0
|
||||
|| r->unparsed_uri.len == 0)
|
||||
{
|
||||
if (r->method_name.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :method header");
|
||||
|
||||
} else if (r->schema.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :scheme header");
|
||||
|
||||
} else {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :path header");
|
||||
}
|
||||
|
||||
if (r->method_name.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :method header");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
r->request_line.len = r->method_name.len + 1
|
||||
+ r->unparsed_uri.len
|
||||
+ sizeof(ending) - 1;
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
goto method_connect;
|
||||
}
|
||||
|
||||
if (r->schema.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :scheme header");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r->unparsed_uri.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :path header");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = r->unparsed_uri.len;
|
||||
|
||||
goto construct_request_line;
|
||||
|
||||
method_connect:
|
||||
|
||||
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
||||
|
||||
if (!cscf->allow_connect) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent CONNECT method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r->headers_in.server.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no :authority header");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
len = r->headers_in.server.len;
|
||||
|
||||
construct_request_line:
|
||||
|
||||
r->request_line.len = r->method_name.len + 1 + len + sizeof(ending) - 1;
|
||||
|
||||
p = ngx_pnalloc(r->pool, r->request_line.len + 1);
|
||||
if (p == NULL) {
|
||||
|
|
@ -3611,7 +3641,18 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r)
|
|||
|
||||
*p++ = ' ';
|
||||
|
||||
p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
p = ngx_cpymem(p, r->headers_in.server.data, r->headers_in.server.len);
|
||||
|
||||
r->uri_start = (u_char *) "/";
|
||||
r->uri_end = r->uri_start + 1;
|
||||
ngx_str_set(&r->uri, "/");
|
||||
ngx_str_set(&r->unparsed_uri, "/");
|
||||
r->valid_unparsed_uri = 1;
|
||||
|
||||
} else {
|
||||
p = ngx_cpymem(p, r->unparsed_uri.data, r->unparsed_uri.len);
|
||||
}
|
||||
|
||||
ngx_memcpy(p, ending, sizeof(ending));
|
||||
|
||||
|
|
@ -3920,12 +3961,6 @@ ngx_http_v2_run_request(ngx_http_request_t *r)
|
|||
r->headers_in.chunked = 1;
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client sent CONNECT method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_TRACE) {
|
||||
ngx_log_error(NGX_LOG_INFO, fc->log, 0, "client sent TRACE method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
|
|
|
|||
|
|
@ -909,10 +909,11 @@ failed:
|
|||
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;
|
||||
size_t len, target_len;
|
||||
u_char *p;
|
||||
ngx_int_t rc;
|
||||
ngx_str_t host;
|
||||
ngx_http_core_srv_conf_t *cscf;
|
||||
in_port_t port;
|
||||
|
||||
if (r->request_line.len) {
|
||||
|
|
@ -925,6 +926,10 @@ ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r)
|
|||
goto failed;
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
goto method_connect;
|
||||
}
|
||||
|
||||
if (r->schema.len == 0) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no \":scheme\" header");
|
||||
|
|
@ -937,9 +942,35 @@ ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r)
|
|||
goto failed;
|
||||
}
|
||||
|
||||
len = r->method_name.len + 1
|
||||
+ (r->uri_end - r->uri_start) + 1
|
||||
+ sizeof("HTTP/3.0") - 1;
|
||||
target_len = (size_t) (r->uri_end - r->uri_start);
|
||||
|
||||
goto construct_request_line;
|
||||
|
||||
method_connect:
|
||||
|
||||
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
|
||||
|
||||
if (!cscf->allow_connect) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent CONNECT method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r->host_start == NULL) {
|
||||
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
|
||||
"client sent no \":authority\" header");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
r->uri_start = (u_char *) "/";
|
||||
r->uri_end = r->uri_start + 1;
|
||||
|
||||
target_len = (size_t) (r->host_end - r->host_start);
|
||||
|
||||
construct_request_line:
|
||||
|
||||
len = r->method_name.len + 1 + target_len + 1 + sizeof("HTTP/3.0") - 1;
|
||||
|
||||
p = ngx_pnalloc(r->pool, len);
|
||||
if (p == NULL) {
|
||||
|
|
@ -951,7 +982,14 @@ ngx_http_v3_init_pseudo_headers(ngx_http_request_t *r)
|
|||
|
||||
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);
|
||||
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
p = ngx_cpymem(p, r->host_start, target_len);
|
||||
|
||||
} else {
|
||||
p = ngx_cpymem(p, r->uri_start, target_len);
|
||||
}
|
||||
|
||||
*p++ = ' ';
|
||||
p = ngx_cpymem(p, "HTTP/3.0", sizeof("HTTP/3.0") - 1);
|
||||
|
||||
|
|
@ -1136,12 +1174,6 @@ ngx_http_v3_process_request_header(ngx_http_request_t *r)
|
|||
}
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_CONNECT) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent CONNECT method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
return NGX_ERROR;
|
||||
}
|
||||
|
||||
if (r->method == NGX_HTTP_TRACE) {
|
||||
ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent TRACE method");
|
||||
ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED);
|
||||
|
|
|
|||
Loading…
Reference in a new issue