Merge branch 'nginx:master' into feature/PROXY_V2_SUPPORT

This commit is contained in:
mdewitt11 2026-04-21 11:11:48 -05:00 committed by GitHub
commit 7045de7e69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
25 changed files with 504 additions and 71 deletions

View file

@ -0,0 +1,23 @@
name: Check Version Bump
on:
pull_request:
types: [ opened, synchronize ]
jobs:
check-version-bump:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Check git log
run: |
echo "## Check for 'Version bump' commit" >${GITHUB_STEP_SUMMARY}
subj=$(git log --format=%s $(git describe --abbrev=0 --tags).. | tail -1)
if ! expr "$subj" : 'Version bump' >/dev/null
then
echo "❌ No 'Version bump' commit immediately after release tag" | tee -a ${GITHUB_STEP_SUMMARY}
exit 2
fi

View file

@ -68,9 +68,14 @@ to 76 characters
code; examples include "Upstream:", "QUIC:", or "Core:"; see the commit history
to get an idea of the prefixes used
- Reference issues in the the subject line; if the commit fixes an issue,
[name it](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue)
accordingly
- If the commit fixes an open issue then you can use the "Closes:" tag/trailer
to reference it and have GitHub automatically close it once it's been merged.
E.g.:
`Closes: https://github.com/nginx/nginx/issues/9999`
That should go at the end of the commit message, separated by a blank line,
along with any other tags.
### Before Submitting

View file

@ -5,6 +5,62 @@
<change_log title="nginx">
<changes ver="1.29.8" date="2026-04-07">
<change type="feature">
<para lang="ru">
директива max_headers.<br/>
Спасибо Максиму Дунину.
</para>
<para lang="en">
the "max_headers" directive.<br/>
Thanks to Maxim Dounin.
</para>
</change>
<change type="feature">
<para lang="ru">
совместимость с OpenSSL 4.0.
</para>
<para lang="en">
OpenSSL 4.0 compatibility.
</para>
</change>
<change type="feature">
<para lang="ru">
теперь директива include внутри блока geo поддерживает маски.
</para>
<para lang="en">
now the "include" directive inside the "geo" block supports wildcards.
</para>
</change>
<change type="bugfix">
<para lang="ru">
в обработке ответов с кодом HTTP 103 (Early Hints)
от проксируемого бэкенда.
</para>
<para lang="en">
in processing of HTTP 103 (Early Hints) responses
from a proxied backend.
</para>
</change>
<change type="bugfix">
<para lang="ru">
переменные $request_port и $is_request_port
были недоступны в подзапросах.
</para>
<para lang="en">
the $request_port and $is_request_port variables
were not available in subrequests.
</para>
</change>
</changes>
<changes ver="1.29.7" date="2026-03-24">
<change type="security">

View file

@ -6,7 +6,7 @@ TEMP = tmp
CC = cl
OBJS = objs.msvc8
OPENSSL = openssl-3.5.5
OPENSSL = openssl-3.5.6
ZLIB = zlib-1.3.2
PCRE = pcre2-10.47

View file

@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
#define nginx_version 1029007
#define NGINX_VERSION "1.29.7"
#define nginx_version 1031000
#define NGINX_VERSION "1.31.0"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD

View file

@ -114,11 +114,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
ngx_cpystrn(cycle->conf_file.data, old_cycle->conf_file.data,
old_cycle->conf_file.len + 1);
cycle->conf_param.len = old_cycle->conf_param.len;
cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
if (cycle->conf_param.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
if (old_cycle->conf_param.len) {
cycle->conf_param.len = old_cycle->conf_param.len;
cycle->conf_param.data = ngx_pstrdup(pool, &old_cycle->conf_param);
if (cycle->conf_param.data == NULL) {
ngx_destroy_pool(pool);
return NULL;
}
}

View file

@ -198,11 +198,7 @@ ngx_monotonic_time(time_t sec, ngx_uint_t msec)
#if (NGX_HAVE_CLOCK_MONOTONIC)
struct timespec ts;
#if defined(CLOCK_MONOTONIC_FAST)
clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
sec = ts.tv_sec;
msec = ts.tv_nsec / 1000000;

View file

@ -948,6 +948,10 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
char *err;
X509 *x509;
X509_NAME *name;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *sname;
X509_STORE *store;
STACK_OF(X509) *chain;
STACK_OF(X509_NAME) *list;
@ -1003,8 +1007,8 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR;
}
name = X509_get_subject_name(x509);
if (name == NULL) {
sname = X509_get_subject_name(x509);
if (sname == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
"X509_get_subject_name(\"%s\") failed", cert->data);
sk_X509_NAME_pop_free(list, X509_NAME_free);
@ -1012,7 +1016,7 @@ ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_str_t *cert,
return NGX_ERROR;
}
name = X509_NAME_dup(name);
name = X509_NAME_dup(sname);
if (name == NULL) {
sk_X509_NAME_pop_free(list, X509_NAME_free);
sk_X509_pop_free(chain, X509_free);
@ -1197,6 +1201,9 @@ ngx_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
char *subject, *issuer;
int err, depth;
X509 *cert;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *sname, *iname;
ngx_connection_t *c;
ngx_ssl_conn_t *ssl_conn;
@ -3890,6 +3897,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
|| n == SSL_R_NO_SHARED_CIPHER /* 193 */
#ifdef SSL_R_PACKET_LENGTH_TOO_LONG
|| n == SSL_R_PACKET_LENGTH_TOO_LONG /* 198 */
#endif
#ifdef SSL_R_INVALID_ALERT
|| n == SSL_R_INVALID_ALERT /* 205 */
#endif
|| n == SSL_R_RECORD_LENGTH_MISMATCH /* 213 */
#ifdef SSL_R_TOO_MANY_WARNING_ALERTS
@ -3950,10 +3960,15 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
#endif
#ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG
|| n == SSL_R_SSL3_SESSION_ID_TOO_LONG /* 300 */
#elif (defined SSL_R_TLS_SESSION_ID_TOO_LONG)
|| n == SSL_R_TLS_SESSION_ID_TOO_LONG /* 300 */
#endif
#ifdef SSL_R_BAD_ECPOINT
|| n == SSL_R_BAD_ECPOINT /* 306 */
#endif
#ifdef SSL_R_RECORD_LAYER_FAILURE
|| n == SSL_R_RECORD_LAYER_FAILURE /* 313 */
#endif
#ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
|| n == SSL_R_RENEGOTIATE_EXT_TOO_LONG /* 335 */
|| n == SSL_R_RENEGOTIATION_ENCODING_ERR /* 336 */
@ -3986,33 +4001,8 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
#ifdef SSL_R_BAD_RECORD_TYPE
|| n == SSL_R_BAD_RECORD_TYPE /* 443 */
#endif
|| n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
#ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE
|| n == SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE /* 1010 */
|| n == SSL_R_SSLV3_ALERT_BAD_RECORD_MAC /* 1020 */
|| n == SSL_R_TLSV1_ALERT_DECRYPTION_FAILED /* 1021 */
|| n == SSL_R_TLSV1_ALERT_RECORD_OVERFLOW /* 1022 */
|| n == SSL_R_SSLV3_ALERT_DECOMPRESSION_FAILURE /* 1030 */
|| n == SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE /* 1040 */
|| n == SSL_R_SSLV3_ALERT_NO_CERTIFICATE /* 1041 */
|| n == SSL_R_SSLV3_ALERT_BAD_CERTIFICATE /* 1042 */
|| n == SSL_R_SSLV3_ALERT_UNSUPPORTED_CERTIFICATE /* 1043 */
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_REVOKED /* 1044 */
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_EXPIRED /* 1045 */
|| n == SSL_R_SSLV3_ALERT_CERTIFICATE_UNKNOWN /* 1046 */
|| n == SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER /* 1047 */
|| n == SSL_R_TLSV1_ALERT_UNKNOWN_CA /* 1048 */
|| n == SSL_R_TLSV1_ALERT_ACCESS_DENIED /* 1049 */
|| n == SSL_R_TLSV1_ALERT_DECODE_ERROR /* 1050 */
|| n == SSL_R_TLSV1_ALERT_DECRYPT_ERROR /* 1051 */
|| n == SSL_R_TLSV1_ALERT_EXPORT_RESTRICTION /* 1060 */
|| n == SSL_R_TLSV1_ALERT_PROTOCOL_VERSION /* 1070 */
|| n == SSL_R_TLSV1_ALERT_INSUFFICIENT_SECURITY /* 1071 */
|| n == SSL_R_TLSV1_ALERT_INTERNAL_ERROR /* 1080 */
|| n == SSL_R_TLSV1_ALERT_USER_CANCELLED /* 1090 */
|| n == SSL_R_TLSV1_ALERT_NO_RENEGOTIATION /* 1100 */
#endif
|| n == 1121 /* SSL_R_TLSV1_ALERT_ECH_REQUIRED */
|| (n >= SSL_AD_REASON_OFFSET /* 1000 */
&& n <= SSL_AD_REASON_OFFSET + 255)
)
{
switch (c->log_error) {
@ -6012,6 +6002,9 @@ ngx_ssl_get_subject_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
BIO *bio;
X509 *cert;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *name;
s->len = 0;
@ -6066,6 +6059,9 @@ ngx_ssl_get_issuer_dn(ngx_connection_t *c, ngx_pool_t *pool, ngx_str_t *s)
{
BIO *bio;
X509 *cert;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *name;
s->len = 0;
@ -6122,6 +6118,9 @@ ngx_ssl_get_subject_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
char *p;
size_t len;
X509 *cert;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *name;
s->len = 0;
@ -6170,6 +6169,9 @@ ngx_ssl_get_issuer_dn_legacy(ngx_connection_t *c, ngx_pool_t *pool,
char *p;
size_t len;
X509 *cert;
#if (OPENSSL_VERSION_NUMBER >= 0x40000000L)
const
#endif
X509_NAME *name;
s->len = 0;

View file

@ -67,6 +67,11 @@
#endif
#if (OPENSSL_VERSION_NUMBER < 0x1010000fL)
#define ASN1_STRING_get0_data(x) (x)->data
#endif
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined SSL_get_peer_certificate)
#define SSL_get_peer_certificate(s) SSL_get1_peer_certificate(s)
#endif

View file

@ -2667,9 +2667,10 @@ ngx_ssl_ocsp_cache_store(ngx_ssl_ocsp_ctx_t *ctx)
static ngx_int_t
ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx)
{
u_char *p;
X509_NAME *name;
ASN1_INTEGER *serial;
u_char *p;
ngx_int_t length;
ASN1_INTEGER *serial;
const X509_NAME *name;
p = ngx_pnalloc(ctx->pool, 60);
if (p == NULL) {
@ -2693,12 +2694,14 @@ ngx_ssl_ocsp_create_key(ngx_ssl_ocsp_ctx_t *ctx)
p += 20;
serial = X509_get_serialNumber(ctx->cert);
if (serial->length > 20) {
length = ASN1_STRING_length(serial);
if (length > 20) {
return NGX_ERROR;
}
p = ngx_cpymem(p, serial->data, serial->length);
ngx_memzero(p, 20 - serial->length);
p = ngx_cpymem(p, ASN1_STRING_get0_data(serial), length);
ngx_memzero(p, 20 - length);
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ctx->log, 0,
"ssl ocsp key %xV", &ctx->key);

View file

@ -152,21 +152,17 @@ ngx_quic_cbs_recv_rcd(ngx_ssl_conn_t *ssl_conn,
qc = ngx_quic_get_connection(c);
ctx = ngx_quic_get_send_ctx(qc, qc->read_level);
for (cl = ctx->crypto.chain; cl; cl = cl->next) {
cl = ctx->crypto.chain;
if (cl == NULL || cl->buf->sync) {
*data = NULL;
*bytes_read = 0;
} else {
b = cl->buf;
if (b->sync) {
/* hole */
*bytes_read = 0;
break;
}
*data = b->pos;
*bytes_read = b->last - b->pos;
break;
}
return 1;

View file

@ -514,6 +514,7 @@ static ngx_keyval_t ngx_http_grpc_headers[] = {
{ ngx_string("TE"), ngx_string("$grpc_internal_trailers") },
{ ngx_string("Host"), ngx_string("") },
{ ngx_string("Connection"), ngx_string("") },
{ ngx_string("Proxy-Connection"), ngx_string("") },
{ ngx_string("Transfer-Encoding"), ngx_string("") },
{ ngx_string("Keep-Alive"), ngx_string("") },
{ ngx_string("Expect"), ngx_string("") },

View file

@ -747,6 +747,7 @@ static char ngx_http_proxy_version_11[] = " HTTP/1.1" CRLF;
static ngx_keyval_t ngx_http_proxy_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_internal_host") },
{ ngx_string("Connection"), ngx_string("") },
{ ngx_string("Proxy-Connection"), ngx_string("") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
{ ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
{ ngx_string("TE"), ngx_string("") },
@ -775,6 +776,7 @@ static ngx_str_t ngx_http_proxy_hide_headers[] = {
static ngx_keyval_t ngx_http_proxy_cache_headers[] = {
{ ngx_string("Host"), ngx_string("$proxy_internal_host") },
{ ngx_string("Connection"), ngx_string("") },
{ ngx_string("Proxy-Connection"), ngx_string("") },
{ ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
{ ngx_string("Transfer-Encoding"), ngx_string("$proxy_internal_chunked") },
{ ngx_string("TE"), ngx_string("") },

View file

@ -252,6 +252,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_srv_conf_t, large_client_header_buffers),
NULL },
{ ngx_string("max_headers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_num_slot,
NGX_HTTP_SRV_CONF_OFFSET,
offsetof(ngx_http_core_srv_conf_t, max_headers),
NULL },
{ ngx_string("ignore_invalid_headers"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@ -2446,6 +2453,8 @@ ngx_http_subrequest(ngx_http_request_t *r,
sr->method = NGX_HTTP_GET;
sr->http_version = r->http_version;
sr->port = r->port;
sr->request_line = r->request_line;
sr->uri = *uri;
@ -3511,6 +3520,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t *cf)
cscf->request_pool_size = NGX_CONF_UNSET_SIZE;
cscf->client_header_timeout = NGX_CONF_UNSET_MSEC;
cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE;
cscf->max_headers = NGX_CONF_UNSET_UINT;
cscf->ignore_invalid_headers = NGX_CONF_UNSET;
cscf->merge_slashes = NGX_CONF_UNSET;
cscf->underscores_in_headers = NGX_CONF_UNSET;
@ -3552,6 +3562,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
ngx_conf_merge_uint_value(conf->max_headers, prev->max_headers, 1000);
ngx_conf_merge_value(conf->ignore_invalid_headers,
prev->ignore_invalid_headers, 1);

View file

@ -199,6 +199,8 @@ typedef struct {
ngx_msec_t client_header_timeout;
ngx_uint_t max_headers;
ngx_flag_t ignore_invalid_headers;
ngx_flag_t merge_slashes;
ngx_flag_t underscores_in_headers;

View file

@ -26,6 +26,8 @@ static ngx_int_t ngx_http_process_host(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_connection(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_proxy_connection(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
@ -82,6 +84,9 @@ ngx_http_header_t ngx_http_headers_in[] = {
{ ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
ngx_http_process_connection },
{ ngx_string("Proxy-Connection"), 0,
ngx_http_process_proxy_connection },
{ ngx_string("If-Modified-Since"),
offsetof(ngx_http_headers_in_t, if_modified_since),
ngx_http_process_unique_header_line },
@ -1494,6 +1499,15 @@ ngx_http_process_request_headers(ngx_event_t *rev)
/* a header line has been parsed successfully */
if (r->headers_in.count++ >= cscf->max_headers) {
r->lingering_close = 1;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent too many header lines");
ngx_http_finalize_request(r,
NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
break;
}
h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@ -1919,6 +1933,21 @@ ngx_http_process_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
}
static ngx_int_t
ngx_http_process_proxy_connection(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
if (r->http_version >= NGX_HTTP_VERSION_20) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent \"Proxy-Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)

View file

@ -184,6 +184,7 @@ typedef struct {
typedef struct {
ngx_list_t headers;
ngx_uint_t count;
ngx_table_elt_t *host;
ngx_table_elt_t *connection;

View file

@ -2067,6 +2067,7 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_ERROR;
}
u->early_hints_length = 0;
u->keepalive = 0;
u->upgrade = 0;
u->error = 0;
@ -2550,6 +2551,8 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->response_received = 1;
again:
rc = u->process_header(r);
if (rc == NGX_AGAIN) {
@ -2570,11 +2573,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
rc = ngx_http_upstream_process_early_hints(r, u);
if (rc == NGX_OK) {
rc = u->process_header(r);
if (rc == NGX_AGAIN) {
continue;
}
goto again;
}
}
@ -5654,7 +5653,7 @@ ngx_http_upstream_copy_content_type(ngx_http_request_t *r, ngx_table_elt_t *h,
last = h->value.data + h->value.len;
if (*(last - 1) == '"') {
if (last > p && *(last - 1) == '"') {
last--;
}

View file

@ -1823,6 +1823,15 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
}
} else {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
if (r->headers_in.count++ >= cscf->max_headers) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent too many header lines");
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
goto error;
}
h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
return ngx_http_v2_connection_error(h2c,
@ -3811,6 +3820,46 @@ ngx_http_v2_run_request(ngx_http_request_t *r)
r->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;
if (r->headers_in.connection) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.keep_alive) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Keep-Alive\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Transfer-Encoding\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.upgrade) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent \"Upgrade\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.te
&& (r->headers_in.te->next
|| r->headers_in.te->value.len != 8
|| ngx_strncasecmp(r->headers_in.te->value.data,
(u_char *) "trailers", 8) != 0))
{
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent invalid \"TE\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
goto failed;
}
if (r->headers_in.server.len == 0) {
ngx_log_error(NGX_LOG_INFO, fc->log, 0,
"client sent neither \":authority\" nor \"Host\" header");

View file

@ -633,9 +633,23 @@ ngx_http_v3_parse_literal(ngx_connection_t *c, ngx_http_v3_parse_literal_t *st,
st->huffstate = 0;
}
st->last = ngx_pnalloc(c->pool, n + 1);
if (st->last == NULL) {
return NGX_ERROR;
if (st->buf) {
if ((size_t) (st->buf->end - st->buf->last) < n + 1) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"not enough dynamic table capacity");
st->last = NULL;
return NGX_ERROR;
}
st->last = st->buf->last;
st->buf->last += n + 1;
} else {
st->last = ngx_pnalloc(c->pool, n + 1);
if (st->last == NULL) {
return NGX_ERROR;
}
}
st->value.data = st->last;
@ -1486,6 +1500,11 @@ ngx_http_v3_parse_field_inr(ngx_connection_t *c,
ch = *b->pos;
st->literal.buf = ngx_http_v3_get_insert_buffer(c);
if (st->literal.buf == NULL) {
return NGX_ERROR;
}
st->dynamic = (ch & 0x40) ? 0 : 1;
st->state = sw_name_index;
@ -1590,6 +1609,11 @@ ngx_http_v3_parse_field_iln(ngx_connection_t *c,
ch = *b->pos;
st->literal.buf = ngx_http_v3_get_insert_buffer(c);
if (st->literal.buf == NULL) {
return NGX_ERROR;
}
st->literal.huffman = (ch & 0x20) ? 1 : 0;
st->state = sw_name_len;

View file

@ -51,6 +51,7 @@ typedef struct {
ngx_str_t value;
u_char *last;
u_char huffstate;
ngx_buf_t *buf;
} ngx_http_v3_parse_literal_t;

View file

@ -665,6 +665,15 @@ ngx_http_v3_process_header(ngx_http_request_t *r, ngx_str_t *name,
}
} else {
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
if (r->headers_in.count++ >= cscf->max_headers) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent too many header lines");
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_HEADER_TOO_LARGE);
return NGX_ERROR;
}
h = ngx_list_push(&r->headers_in.headers);
if (h == NULL) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
@ -1012,6 +1021,46 @@ ngx_http_v3_process_request_header(ngx_http_request_t *r)
c = r->connection;
if (r->headers_in.connection) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Connection\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.keep_alive) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Keep-Alive\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.transfer_encoding) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Transfer-Encoding\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.upgrade) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent \"Upgrade\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (r->headers_in.te
&& (r->headers_in.te->next
|| r->headers_in.te->value.len != 8
|| ngx_strncasecmp(r->headers_in.te->value.data,
(u_char *) "trailers", 8) != 0))
{
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent invalid \"TE\" header");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
if (ngx_http_v3_init_pseudo_headers(r) != NGX_OK) {
return NGX_ERROR;
}

View file

@ -155,6 +155,28 @@ static ngx_http_v3_field_t ngx_http_v3_static_table[] = {
};
ngx_buf_t *
ngx_http_v3_get_insert_buffer(ngx_connection_t *c)
{
ngx_http_v3_session_t *h3c;
ngx_http_v3_dynamic_table_t *dt;
h3c = ngx_http_v3_get_session(c);
dt = &h3c->table;
if (dt->insert_buffer == NULL) {
dt->insert_buffer = ngx_create_temp_buf(c->pool, dt->capacity);
if (dt->insert_buffer == NULL) {
return NULL;
}
}
dt->insert_buffer->last = dt->insert_buffer->pos;
return dt->insert_buffer;
}
ngx_int_t
ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value)

View file

@ -29,11 +29,13 @@ typedef struct {
uint64_t insert_count;
uint64_t ack_insert_count;
ngx_event_t send_insert_count;
ngx_buf_t *insert_buffer;
} ngx_http_v3_dynamic_table_t;
void ngx_http_v3_inc_insert_count_handler(ngx_event_t *ev);
void ngx_http_v3_cleanup_table(ngx_http_v3_session_t *h3c);
ngx_buf_t *ngx_http_v3_get_insert_buffer(ngx_connection_t *c);
ngx_int_t ngx_http_v3_ref_insert(ngx_connection_t *c, ngx_uint_t dynamic,
ngx_uint_t index, ngx_str_t *value);
ngx_int_t ngx_http_v3_insert(ngx_connection_t *c, ngx_str_t *name,

View file

@ -43,6 +43,7 @@ typedef struct {
ngx_str_t ssl_ciphers;
ngx_stream_complex_value_t *ssl_name;
ngx_flag_t ssl_server_name;
ngx_array_t *ssl_alpn;
ngx_flag_t ssl_verify;
ngx_uint_t ssl_verify_depth;
@ -98,6 +99,8 @@ static char *ngx_stream_proxy_protocol_tlv(ngx_conf_t *cf, ngx_command_t *cmd,
#if (NGX_STREAM_SSL)
static ngx_int_t ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s);
static char *ngx_stream_proxy_ssl_alpn_set_slot(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);
static char *ngx_stream_proxy_ssl_password_file(ngx_conf_t *cf,
@ -108,6 +111,7 @@ static void ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s);
static void ngx_stream_proxy_ssl_handshake(ngx_connection_t *pc);
static void ngx_stream_proxy_ssl_save_session(ngx_connection_t *c);
static ngx_int_t ngx_stream_proxy_ssl_name(ngx_stream_session_t *s);
static ngx_int_t ngx_stream_proxy_ssl_alpn(ngx_stream_session_t *s);
static ngx_int_t ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s);
static ngx_int_t ngx_stream_proxy_merge_ssl(ngx_conf_t *cf,
ngx_stream_proxy_srv_conf_t *conf, ngx_stream_proxy_srv_conf_t *prev);
@ -321,6 +325,13 @@ static ngx_command_t ngx_stream_proxy_commands[] = {
offsetof(ngx_stream_proxy_srv_conf_t, ssl_server_name),
NULL },
{ ngx_string("proxy_ssl_alpn"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_1MORE,
ngx_stream_proxy_ssl_alpn_set_slot,
NGX_STREAM_SRV_CONF_OFFSET,
0,
NULL },
{ ngx_string("proxy_ssl_verify"),
NGX_STREAM_MAIN_CONF|NGX_STREAM_SRV_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@ -1124,6 +1135,61 @@ ngx_stream_proxy_send_proxy_protocol(ngx_stream_session_t *s)
}
static char *
ngx_stream_proxy_ssl_alpn_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
ngx_stream_proxy_srv_conf_t *pscf = conf;
ngx_str_t *value;
ngx_uint_t i;
ngx_stream_complex_value_t *cv;
ngx_stream_compile_complex_value_t ccv;
if (pscf->ssl_alpn != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}
value = cf->args->elts;
pscf->ssl_alpn = ngx_array_create(cf->pool, cf->args->nelts - 1,
sizeof(ngx_stream_complex_value_t));
if (pscf->ssl_alpn == NULL) {
return NGX_CONF_ERROR;
}
cv = ngx_array_push_n(pscf->ssl_alpn, cf->args->nelts - 1);
for (i = 1; i < cf->args->nelts; i++) {
ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
ccv.cf = cf;
ccv.value = &value[i];
ccv.complex_value = &cv[i - 1];
if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}
if (cv[i - 1].lengths == NULL && value[i].len > 255) {
return "protocol too long";
}
}
return NGX_CONF_OK;
#else
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"proxy_ssl_alpn\" directive requires "
"OpenSSL with ALPN support");
return NGX_CONF_ERROR;
#endif
}
static char *
ngx_stream_proxy_ssl_certificate_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
@ -1281,6 +1347,13 @@ ngx_stream_proxy_ssl_init_connection(ngx_stream_session_t *s)
}
}
if (pscf->ssl_alpn) {
if (ngx_stream_proxy_ssl_alpn(s) != NGX_OK) {
ngx_stream_proxy_finalize(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
return;
}
}
if (pscf->ssl_certificate
&& pscf->ssl_certificate->value.len
&& (pscf->ssl_certificate->lengths
@ -1480,6 +1553,82 @@ done:
}
static ngx_int_t
ngx_stream_proxy_ssl_alpn(ngx_stream_session_t *s)
{
#ifdef TLSEXT_TYPE_application_layer_protocol_negotiation
size_t len;
u_char *p, *buf;
ngx_str_t proto;
ngx_uint_t i;
ngx_connection_t *c;
ngx_stream_upstream_t *u;
ngx_stream_complex_value_t *cv;
ngx_stream_proxy_srv_conf_t *pscf;
pscf = ngx_stream_get_module_srv_conf(s, ngx_stream_proxy_module);
u = s->upstream;
c = u->peer.connection;
len = 0;
cv = pscf->ssl_alpn->elts;
for (i = 0; i < pscf->ssl_alpn->nelts; i++) {
if (ngx_stream_complex_value(s, &cv[i], &proto) != NGX_OK) {
return NGX_ERROR;
}
if (proto.len == 0 || proto.len > 255) {
continue;
}
len += 1 + proto.len;
}
if (len == 0) {
return NGX_OK;
}
buf = ngx_pnalloc(c->pool, len);
if (buf == NULL) {
return NGX_ERROR;
}
p = buf;
for (i = 0; i < pscf->ssl_alpn->nelts; i++) {
if (ngx_stream_complex_value(s, &cv[i], &proto) != NGX_OK) {
return NGX_ERROR;
}
if (proto.len == 0 || proto.len > 255) {
continue;
}
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
"upstream SSL ALPN: \"%V\"", &proto);
*p++ = proto.len;
p = ngx_cpymem(p, proto.data, proto.len);
}
if (SSL_set_alpn_protos(c->ssl->connection, buf, p - buf) != 0) {
ngx_ssl_error(NGX_LOG_ERR, c->log, 0,
"SSL_set_alpn_protos() failed");
return NGX_ERROR;
}
#endif
return NGX_OK;
}
static ngx_int_t
ngx_stream_proxy_ssl_certificate(ngx_stream_session_t *s)
{
@ -2308,6 +2457,7 @@ ngx_stream_proxy_create_srv_conf(ngx_conf_t *cf)
conf->ssl_session_reuse = NGX_CONF_UNSET;
conf->ssl_name = NGX_CONF_UNSET_PTR;
conf->ssl_server_name = NGX_CONF_UNSET;
conf->ssl_alpn = NGX_CONF_UNSET_PTR;
conf->ssl_verify = NGX_CONF_UNSET;
conf->ssl_verify_depth = NGX_CONF_UNSET_UINT;
conf->ssl_certificate = NGX_CONF_UNSET_PTR;
@ -2387,6 +2537,8 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->ssl_server_name, prev->ssl_server_name, 0);
ngx_conf_merge_ptr_value(conf->ssl_alpn, prev->ssl_alpn, NULL);
ngx_conf_merge_value(conf->ssl_verify, prev->ssl_verify, 0);
ngx_conf_merge_uint_value(conf->ssl_verify_depth,