New upstream version 1.13.10

This commit is contained in:
Christos Trochalakis 2018-03-21 16:14:30 +02:00
parent 0490248e0f
commit 55e1981acb
36 changed files with 5497 additions and 382 deletions

25
CHANGES
View file

@ -1,4 +1,29 @@
Changes with nginx 1.13.10 20 Mar 2018
*) Feature: the "set" parameter of the "include" SSI directive now
allows writing arbitrary responses to a variable; the
"subrequest_output_buffer_size" directive defines maximum response
size.
*) Feature: now nginx uses clock_gettime(CLOCK_MONOTONIC) if available,
to avoid timeouts being incorrectly triggered on system time changes.
*) Feature: the "escape=none" parameter of the "log_format" directive.
Thanks to Johannes Baiter and Calin Don.
*) Feature: the $ssl_preread_alpn_protocols variable in the
ngx_stream_ssl_preread_module.
*) Feature: the ngx_http_grpc_module.
*) Bugfix: in memory allocation error handling in the "geo" directive.
*) Bugfix: when using variables in the "auth_basic_user_file" directive
a null character might appear in logs.
Thanks to Vadim Filimonov.
Changes with nginx 1.13.9 20 Feb 2018
*) Feature: HTTP/2 server push support; the "http2_push" and

View file

@ -1,4 +1,30 @@
Изменения в nginx 1.13.10 20.03.2018
*) Добавление: теперь параметр set в SSI-директиве include позволяет
сохранять в переменную любые ответы; максимальный размер ответа
задаётся директивой subrequest_output_buffer_size.
*) Добавление: теперь nginx использует вызов
clock_gettime(CLOCK_MONOTONIC), если он доступен, что позволяет
избежать некорректного срабатывания таймаутов при изменениях
системного времени.
*) Добавление: параметр "escape=none" директивы log_format.
Спасибо Johannes Baiter и Calin Don.
*) Добавление: переменная $ssl_preread_alpn_protocols в модуле
ngx_stream_ssl_preread_module.
*) Добавление: модуль ngx_http_grpc_module.
*) Исправление: в обработке ошибок выделения памяти в директиве geo.
*) Исправление: при использовании переменных в директиве
auth_basic_user_file в лог мог выводиться символ '\0'.
Спасибо Вадиму Филимонову.
Изменения в nginx 1.13.9 20.02.2018
*) Добавление: поддержка HTTP/2 server push; директивы http2_push и

View file

@ -428,6 +428,7 @@ if [ $HTTP = YES ]; then
src/http/v2/ngx_http_v2_module.h"
ngx_module_srcs="src/http/v2/ngx_http_v2.c \
src/http/v2/ngx_http_v2_table.c \
src/http/v2/ngx_http_v2_encode.c \
src/http/v2/ngx_http_v2_huff_decode.c \
src/http/v2/ngx_http_v2_huff_encode.c \
src/http/v2/ngx_http_v2_module.c"
@ -743,6 +744,17 @@ if [ $HTTP = YES ]; then
. auto/module
fi
if [ $HTTP_GRPC = YES -a $HTTP_V2 = YES ]; then
ngx_module_name=ngx_http_grpc_module
ngx_module_incs=
ngx_module_deps=
ngx_module_srcs=src/http/modules/ngx_http_grpc_module.c
ngx_module_libs=
ngx_module_link=$HTTP_GRPC
. auto/module
fi
if [ $HTTP_PERL != NO ]; then
ngx_module_name=ngx_http_perl_module
ngx_module_incs=src/http/modules/perl

View file

@ -86,6 +86,7 @@ HTTP_PROXY=YES
HTTP_FASTCGI=YES
HTTP_UWSGI=YES
HTTP_SCGI=YES
HTTP_GRPC=YES
HTTP_PERL=NO
HTTP_MEMCACHED=YES
HTTP_LIMIT_CONN=YES
@ -262,6 +263,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated"
--without-http_fastcgi_module) HTTP_FASTCGI=NO ;;
--without-http_uwsgi_module) HTTP_UWSGI=NO ;;
--without-http_scgi_module) HTTP_SCGI=NO ;;
--without-http_grpc_module) HTTP_GRPC=NO ;;
--without-http_memcached_module) HTTP_MEMCACHED=NO ;;
--without-http_limit_conn_module) HTTP_LIMIT_CONN=NO ;;
--without-http_limit_req_module) HTTP_LIMIT_REQ=NO ;;
@ -471,6 +473,7 @@ cat << END
--without-http_fastcgi_module disable ngx_http_fastcgi_module
--without-http_uwsgi_module disable ngx_http_uwsgi_module
--without-http_scgi_module disable ngx_http_scgi_module
--without-http_grpc_module disable ngx_http_grpc_module
--without-http_memcached_module disable ngx_http_memcached_module
--without-http_limit_conn_module disable ngx_http_limit_conn_module
--without-http_limit_req_module disable ngx_http_limit_req_module

View file

@ -791,6 +791,30 @@ ngx_feature_test="struct tm t; time_t c=0; localtime_r(&c, &t)"
. auto/feature
ngx_feature="clock_gettime(CLOCK_MONOTONIC)"
ngx_feature_name="NGX_HAVE_CLOCK_MONOTONIC"
ngx_feature_run=no
ngx_feature_incs="#include <time.h>"
ngx_feature_path=
ngx_feature_libs=
ngx_feature_test="struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts)"
. auto/feature
if [ $ngx_found = no ]; then
# Linux before glibc 2.17, notably CentOS 6
ngx_feature="clock_gettime(CLOCK_MONOTONIC) in librt"
ngx_feature_libs="-lrt"
. auto/feature
if [ $ngx_found = yes ]; then
CORE_LIBS="$CORE_LIBS -lrt"
fi
fi
ngx_feature="posix_memalign()"
ngx_feature_name="NGX_HAVE_POSIX_MEMALIGN"
ngx_feature_run=no

View file

@ -241,6 +241,32 @@ syn keyword ngxDirective contained geoip_org
syn keyword ngxDirective contained geoip_proxy
syn keyword ngxDirective contained geoip_proxy_recursive
syn keyword ngxDirective contained google_perftools_profiles
syn keyword ngxDirective contained grpc_bind
syn keyword ngxDirective contained grpc_buffer_size
syn keyword ngxDirective contained grpc_connect_timeout
syn keyword ngxDirective contained grpc_hide_header
syn keyword ngxDirective contained grpc_ignore_headers
syn keyword ngxDirective contained grpc_intercept_errors
syn keyword ngxDirective contained grpc_next_upstream
syn keyword ngxDirective contained grpc_next_upstream_timeout
syn keyword ngxDirective contained grpc_next_upstream_tries
syn keyword ngxDirective contained grpc_pass
syn keyword ngxDirective contained grpc_pass_header
syn keyword ngxDirective contained grpc_read_timeout
syn keyword ngxDirective contained grpc_send_timeout
syn keyword ngxDirective contained grpc_set_header
syn keyword ngxDirective contained grpc_ssl_certificate
syn keyword ngxDirective contained grpc_ssl_certificate_key
syn keyword ngxDirective contained grpc_ssl_ciphers
syn keyword ngxDirective contained grpc_ssl_crl
syn keyword ngxDirective contained grpc_ssl_name
syn keyword ngxDirective contained grpc_ssl_password_file
syn keyword ngxDirective contained grpc_ssl_protocols
syn keyword ngxDirective contained grpc_ssl_server_name
syn keyword ngxDirective contained grpc_ssl_session_reuse
syn keyword ngxDirective contained grpc_ssl_trusted_certificate
syn keyword ngxDirective contained grpc_ssl_verify
syn keyword ngxDirective contained grpc_ssl_verify_depth
syn keyword ngxDirective contained gunzip
syn keyword ngxDirective contained gunzip_buffers
syn keyword ngxDirective contained gzip
@ -268,11 +294,14 @@ syn keyword ngxDirective contained hls_mp4_max_buffer_size
syn keyword ngxDirective contained http2_body_preread_size
syn keyword ngxDirective contained http2_chunk_size
syn keyword ngxDirective contained http2_idle_timeout
syn keyword ngxDirective contained http2_max_concurrent_pushes
syn keyword ngxDirective contained http2_max_concurrent_streams
syn keyword ngxDirective contained http2_max_field_size
syn keyword ngxDirective contained http2_max_header_size
syn keyword ngxDirective contained http2_max_requests
syn keyword ngxDirective contained http2_pool_size
syn keyword ngxDirective contained http2_push
syn keyword ngxDirective contained http2_push_preload
syn keyword ngxDirective contained http2_recv_buffer_size
syn keyword ngxDirective contained http2_recv_timeout
syn keyword ngxDirective contained http2_streams_index_size
@ -574,6 +603,7 @@ syn keyword ngxDirective contained sub_filter
syn keyword ngxDirective contained sub_filter_last_modified
syn keyword ngxDirective contained sub_filter_once
syn keyword ngxDirective contained sub_filter_types
syn keyword ngxDirective contained subrequest_output_buffer_size
syn keyword ngxDirective contained tcp_nodelay
syn keyword ngxDirective contained tcp_nopush
syn keyword ngxDirective contained thread_pool
@ -1323,11 +1353,8 @@ syn keyword ngxDirectiveThirdParty contained rules_enabled
" Phusion Passenger
" https://www.phusionpassenger.com/library/config/nginx/reference/
syn keyword ngxDirectiveThirdParty contained disable_security_update_check
syn keyword ngxDirectiveThirdParty contained passenger_abort_on_startup_error
syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown
syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_group
syn keyword ngxDirectiveThirdParty contained passenger_analytics_log_user
syn keyword ngxDirectiveThirdParty contained passenger_app_env
syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit
syn keyword ngxDirectiveThirdParty contained passenger_app_group_name
@ -1369,6 +1396,7 @@ syn keyword ngxDirectiveThirdParty contained passenger_max_instances_per_app
syn keyword ngxDirectiveThirdParty contained passenger_max_pool_size
syn keyword ngxDirectiveThirdParty contained passenger_max_preloader_idle_time
syn keyword ngxDirectiveThirdParty contained passenger_max_request_queue_size
syn keyword ngxDirectiveThirdParty contained passenger_max_request_queue_time
syn keyword ngxDirectiveThirdParty contained passenger_max_request_time
syn keyword ngxDirectiveThirdParty contained passenger_max_requests
syn keyword ngxDirectiveThirdParty contained passenger_memory_limit
@ -1402,21 +1430,22 @@ syn keyword ngxDirectiveThirdParty contained passenger_turbocaching
syn keyword ngxDirectiveThirdParty contained passenger_user
syn keyword ngxDirectiveThirdParty contained passenger_user_switching
syn keyword ngxDirectiveThirdParty contained passenger_vary_turbocache_by_cookie
syn keyword ngxDirectiveThirdParty contained rack_env
syn keyword ngxDirectiveThirdParty contained rails_app_spawner_idle_time
syn keyword ngxDirectiveThirdParty contained rails_env
syn keyword ngxDirectiveThirdParty contained security_update_check_proxy
syn keyword ngxDirectiveThirdParty contained union_station_filter
syn keyword ngxDirectiveThirdParty contained union_station_gateway_address
syn keyword ngxDirectiveThirdParty contained union_station_gateway_cert
syn keyword ngxDirectiveThirdParty contained union_station_gateway_port
syn keyword ngxDirectiveThirdParty contained union_station_key
syn keyword ngxDirectiveThirdParty contained union_station_proxy_address
syn keyword ngxDirectiveThirdParty contained union_station_support
syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_group
syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_analytics_log_user
syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_debug_log_file
syn keyword ngxDirectiveThirdPartyDeprecated contained passenger_use_global_queue
syn keyword ngxDirectiveThirdPartyDeprecated contained rack_env
syn keyword ngxDirectiveThirdPartyDeprecated contained rails_app_spawner_idle_time
syn keyword ngxDirectiveThirdPartyDeprecated contained rails_env
syn keyword ngxDirectiveThirdPartyDeprecated contained rails_framework_spawner_idle_time
syn keyword ngxDirectiveThirdPartyDeprecated contained rails_spawn_method
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_filter
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_address
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_cert
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_gateway_port
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_key
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_proxy_address
syn keyword ngxDirectiveThirdPartyDeprecated contained union_station_support
" ngx_postgres is an upstream module that allows nginx to communicate directly with PostgreSQL database
" https://github.com/FRiCKLE/ngx_postgres
@ -2028,6 +2057,7 @@ syn keyword ngxDirectiveThirdParty contained sass_source_map_embed
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_query
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_database
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_host
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_password
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_port
syn keyword ngxDirectiveThirdParty contained selective_cache_purge_redis_unix_socket

View file

@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
#define nginx_version 1013009
#define NGINX_VERSION "1.13.9"
#define nginx_version 1013010
#define NGINX_VERSION "1.13.10"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD

View file

@ -9,6 +9,9 @@
#include <ngx_core.h>
static ngx_msec_t ngx_monotonic_time(time_t sec, ngx_uint_t msec);
/*
* The time may be updated by signal handler or by several threads.
* The time update operations are rare and require to hold the ngx_time_lock.
@ -93,7 +96,7 @@ ngx_time_update(void)
sec = tv.tv_sec;
msec = tv.tv_usec / 1000;
ngx_current_msec = (ngx_msec_t) sec * 1000 + msec;
ngx_current_msec = ngx_monotonic_time(sec, msec);
tp = &cached_time[slot];
@ -189,6 +192,31 @@ ngx_time_update(void)
}
static ngx_msec_t
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);
#elif defined(CLOCK_MONOTONIC_COARSE)
clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
sec = ts.tv_sec;
msec = ts.tv_nsec / 1000000;
#endif
return (ngx_msec_t) sec * 1000 + msec;
}
#if !(NGX_WIN32)
void

View file

@ -388,7 +388,16 @@ ngx_event_connect_set_transparent(ngx_peer_connection_t *pc, ngx_socket_t s)
return NGX_ERROR;
}
#else
ngx_log_error(NGX_LOG_ALERT, pc->log, 0,
"could not enable transparent proxying for IPv6 "
"on this platform");
return NGX_ERROR;
#endif
break;
#endif /* NGX_HAVE_INET6 */

View file

@ -266,8 +266,8 @@ ngx_http_auth_basic_handler(ngx_http_request_t *r)
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"user \"%V\" was not found in \"%V\"",
&r->headers_in.user, &user_file);
"user \"%V\" was not found in \"%s\"",
&r->headers_in.user, user_file.data);
return ngx_http_auth_basic_set_realm(r, &realm);
}

View file

@ -2512,36 +2512,6 @@ ngx_http_fastcgi_non_buffered_filter(void *data, ssize_t bytes)
break;
}
/* provide continuous buffer for subrequests in memory */
if (r->subrequest_in_memory) {
cl = u->out_bufs;
if (cl) {
buf->pos = cl->buf->pos;
}
buf->last = buf->pos;
for (cl = u->out_bufs; cl; cl = cl->next) {
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http fastcgi in memory %p-%p %O",
cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
if (buf->last == cl->buf->pos) {
buf->last = cl->buf->last;
continue;
}
buf->last = ngx_movemem(buf->last, cl->buf->pos,
cl->buf->last - cl->buf->pos);
cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
cl->buf->last = buf->last;
}
}
return NGX_OK;
}
@ -2736,8 +2706,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.uri = { 0, NULL };
* conf->upstream.location = NULL;
* conf->upstream.store_lengths = NULL;
* conf->upstream.store_values = NULL;
*

View file

@ -439,6 +439,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
if (ctx.temp_pool == NULL) {
ngx_destroy_pool(pool);
return NGX_CONF_ERROR;
}
@ -460,6 +461,10 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
*cf = save;
if (rv != NGX_CONF_OK) {
goto failed;
}
geo->proxies = ctx.proxies;
geo->proxy_recursive = ctx.proxy_recursive;
@ -482,7 +487,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *));
if (ctx.high.low[i] == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
ngx_memcpy(ctx.high.low[i], a->elts, len);
@ -508,14 +513,11 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
var->get_handler = ngx_http_geo_range_variable;
var->data = (uintptr_t) geo;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
} else {
if (ctx.tree == NULL) {
ctx.tree = ngx_radix_tree_create(cf->pool, -1);
if (ctx.tree == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
}
@ -525,7 +527,7 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (ctx.tree6 == NULL) {
ctx.tree6 = ngx_radix_tree_create(cf->pool, -1);
if (ctx.tree6 == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
}
@ -535,14 +537,11 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
var->get_handler = ngx_http_geo_cidr_variable;
var->data = (uintptr_t) geo;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
if (ngx_radix32tree_insert(ctx.tree, 0, 0,
(uintptr_t) &ngx_http_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
goto failed;
}
/* NGX_BUSY is okay (default was set explicitly) */
@ -552,12 +551,22 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
(uintptr_t) &ngx_http_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
goto failed;
}
#endif
}
return rv;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
return NGX_CONF_OK;
failed:
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
return NGX_CONF_ERROR;
}

File diff suppressed because it is too large Load diff

View file

@ -90,6 +90,11 @@ typedef struct {
} ngx_http_log_var_t;
#define NGX_HTTP_LOG_ESCAPE_DEFAULT 0
#define NGX_HTTP_LOG_ESCAPE_JSON 1
#define NGX_HTTP_LOG_ESCAPE_NONE 2
static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log,
u_char *buf, size_t len);
static ssize_t ngx_http_log_script_write(ngx_http_request_t *r,
@ -126,7 +131,7 @@ static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf,
ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
ngx_http_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r,
uintptr_t data);
static u_char *ngx_http_log_variable(ngx_http_request_t *r, u_char *buf,
@ -136,6 +141,10 @@ static size_t ngx_http_log_json_variable_getlen(ngx_http_request_t *r,
uintptr_t data);
static u_char *ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op);
static size_t ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r,
uintptr_t data);
static u_char *ngx_http_log_unescaped_variable(ngx_http_request_t *r,
u_char *buf, ngx_http_log_op_t *op);
static void *ngx_http_log_create_main_conf(ngx_conf_t *cf);
@ -905,7 +914,7 @@ ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf,
static ngx_int_t
ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
ngx_str_t *value, ngx_uint_t json)
ngx_str_t *value, ngx_uint_t escape)
{
ngx_int_t index;
@ -916,11 +925,18 @@ ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op,
op->len = 0;
if (json) {
switch (escape) {
case NGX_HTTP_LOG_ESCAPE_JSON:
op->getlen = ngx_http_log_json_variable_getlen;
op->run = ngx_http_log_json_variable;
break;
} else {
case NGX_HTTP_LOG_ESCAPE_NONE:
op->getlen = ngx_http_log_unescaped_variable_getlen;
op->run = ngx_http_log_unescaped_variable;
break;
default: /* NGX_HTTP_LOG_ESCAPE_DEFAULT */
op->getlen = ngx_http_log_variable_getlen;
op->run = ngx_http_log_variable;
}
@ -1073,6 +1089,39 @@ ngx_http_log_json_variable(ngx_http_request_t *r, u_char *buf,
}
static size_t
ngx_http_log_unescaped_variable_getlen(ngx_http_request_t *r, uintptr_t data)
{
ngx_http_variable_value_t *value;
value = ngx_http_get_indexed_variable(r, data);
if (value == NULL || value->not_found) {
return 0;
}
value->escape = 0;
return value->len;
}
static u_char *
ngx_http_log_unescaped_variable(ngx_http_request_t *r, u_char *buf,
ngx_http_log_op_t *op)
{
ngx_http_variable_value_t *value;
value = ngx_http_get_indexed_variable(r, op->data);
if (value == NULL || value->not_found) {
return buf;
}
return ngx_cpymem(buf, value->data, value->len);
}
static void *
ngx_http_log_create_main_conf(ngx_conf_t *cf)
{
@ -1536,18 +1585,21 @@ ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
size_t i, len;
ngx_str_t *value, var;
ngx_int_t *flush;
ngx_uint_t bracket, json;
ngx_uint_t bracket, escape;
ngx_http_log_op_t *op;
ngx_http_log_var_t *v;
json = 0;
escape = NGX_HTTP_LOG_ESCAPE_DEFAULT;
value = args->elts;
if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
data = value[s].data + 7;
if (ngx_strcmp(data, "json") == 0) {
json = 1;
escape = NGX_HTTP_LOG_ESCAPE_JSON;
} else if (ngx_strcmp(data, "none") == 0) {
escape = NGX_HTTP_LOG_ESCAPE_NONE;
} else if (ngx_strcmp(data, "default") != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@ -1636,7 +1688,7 @@ ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
}
}
if (ngx_http_log_variable_compile(cf, op, &var, json)
if (ngx_http_log_variable_compile(cf, op, &var, escape)
!= NGX_OK)
{
return NGX_CONF_ERROR;

View file

@ -592,8 +592,6 @@ ngx_http_memcached_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.bufs.num = 0;
* conf->upstream.next_upstream = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.uri = { 0, NULL };
* conf->upstream.location = NULL;
*/
conf->upstream.local = NGX_CONF_UNSET_PTR;

View file

@ -2321,36 +2321,6 @@ ngx_http_proxy_non_buffered_chunked_filter(void *data, ssize_t bytes)
return NGX_ERROR;
}
/* provide continuous buffer for subrequests in memory */
if (r->subrequest_in_memory) {
cl = u->out_bufs;
if (cl) {
buf->pos = cl->buf->pos;
}
buf->last = buf->pos;
for (cl = u->out_bufs; cl; cl = cl->next) {
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http proxy in memory %p-%p %O",
cl->buf->pos, cl->buf->last, ngx_buf_size(cl->buf));
if (buf->last == cl->buf->pos) {
buf->last = cl->buf->last;
continue;
}
buf->last = ngx_movemem(buf->last, cl->buf->pos,
cl->buf->last - cl->buf->pos);
cl->buf->pos = buf->last - (cl->buf->last - cl->buf->pos);
cl->buf->last = buf->last;
}
}
return NGX_OK;
}
@ -2827,13 +2797,13 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.cache_methods = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.uri = { 0, NULL };
* conf->upstream.location = NULL;
* conf->upstream.store_lengths = NULL;
* conf->upstream.store_values = NULL;
* conf->upstream.ssl_name = NULL;
*
* conf->method = NULL;
* conf->location = NULL;
* conf->url = { 0, NULL };
* conf->headers_source = NULL;
* conf->headers.lengths = NULL;
* conf->headers.values = NULL;

View file

@ -2231,9 +2231,11 @@ ngx_http_ssi_set_variable(ngx_http_request_t *r, void *data, ngx_int_t rc)
{
ngx_str_t *value = data;
if (r->upstream) {
value->len = r->upstream->buffer.last - r->upstream->buffer.pos;
value->data = r->upstream->buffer.pos;
if (r->headers_out.status < NGX_HTTP_SPECIAL_RESPONSE
&& r->out && r->out->buf)
{
value->len = r->out->buf->last - r->out->buf->pos;
value->data = r->out->buf->pos;
}
return rc;

View file

@ -399,6 +399,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, sendfile_max_chunk),
NULL },
{ ngx_string("subrequest_output_buffer_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_size_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, subrequest_output_buffer_size),
NULL },
{ ngx_string("aio"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_core_set_aio,
@ -2237,6 +2244,12 @@ ngx_http_subrequest(ngx_http_request_t *r,
return NGX_ERROR;
}
if (r->subrequest_in_memory) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"nested in-memory subrequest \"%V\"", uri);
return NGX_ERROR;
}
sr = ngx_pcalloc(r->pool, sizeof(ngx_http_request_t));
if (sr == NULL) {
return NGX_ERROR;
@ -2318,6 +2331,10 @@ ngx_http_subrequest(ngx_http_request_t *r,
sr->log_handler = r->log_handler;
if (sr->subrequest_in_memory) {
sr->filter_need_in_memory = 1;
}
if (!sr->background) {
if (c->data == r && r->postponed == NULL) {
c->data = sr;
@ -3356,6 +3373,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
clcf->internal = NGX_CONF_UNSET;
clcf->sendfile = NGX_CONF_UNSET;
clcf->sendfile_max_chunk = NGX_CONF_UNSET_SIZE;
clcf->subrequest_output_buffer_size = NGX_CONF_UNSET_SIZE;
clcf->aio = NGX_CONF_UNSET;
clcf->aio_write = NGX_CONF_UNSET;
#if (NGX_THREADS)
@ -3578,6 +3596,9 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_size_value(conf->sendfile_max_chunk,
prev->sendfile_max_chunk, 0);
ngx_conf_merge_size_value(conf->subrequest_output_buffer_size,
prev->subrequest_output_buffer_size,
(size_t) ngx_pagesize);
ngx_conf_merge_value(conf->aio, prev->aio, NGX_HTTP_AIO_OFF);
ngx_conf_merge_value(conf->aio_write, prev->aio_write, 0);
#if (NGX_THREADS)

View file

@ -351,6 +351,8 @@ struct ngx_http_core_loc_conf_s {
size_t limit_rate_after; /* limit_rate_after */
size_t sendfile_max_chunk; /* sendfile_max_chunk */
size_t read_ahead; /* read_ahead */
size_t subrequest_output_buffer_size;
/* subrequest_output_buffer_size */
ngx_msec_t client_body_timeout; /* client_body_timeout */
ngx_msec_t send_timeout; /* send_timeout */

View file

@ -12,6 +12,8 @@
static ngx_int_t ngx_http_postpone_filter_add(ngx_http_request_t *r,
ngx_chain_t *in);
static ngx_int_t ngx_http_postpone_filter_in_memory(ngx_http_request_t *r,
ngx_chain_t *in);
static ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf);
@ -60,6 +62,10 @@ ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in);
if (r->subrequest_in_memory) {
return ngx_http_postpone_filter_in_memory(r, in);
}
if (r != c->data) {
if (in) {
@ -171,6 +177,78 @@ found:
}
static ngx_int_t
ngx_http_postpone_filter_in_memory(ngx_http_request_t *r, ngx_chain_t *in)
{
size_t len;
ngx_buf_t *b;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter in memory");
if (r->out == NULL) {
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (r->headers_out.content_length_n != -1) {
len = r->headers_out.content_length_n;
if (len > clcf->subrequest_output_buffer_size) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"too big subrequest response: %uz", len);
return NGX_ERROR;
}
} else {
len = clcf->subrequest_output_buffer_size;
}
b = ngx_create_temp_buf(r->pool, len);
if (b == NULL) {
return NGX_ERROR;
}
b->last_buf = 1;
r->out = ngx_alloc_chain_link(r->pool);
if (r->out == NULL) {
return NGX_ERROR;
}
r->out->buf = b;
r->out->next = NULL;
}
b = r->out->buf;
for ( /* void */ ; in; in = in->next) {
if (ngx_buf_special(in->buf)) {
continue;
}
len = in->buf->last - in->buf->pos;
if (len > (size_t) (b->end - b->last)) {
ngx_log_error(NGX_LOG_ERR, c->log, 0,
"too big subrequest response");
return NGX_ERROR;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http postpone filter in memory %uz bytes", len);
b->last = ngx_cpymem(b->last, in->buf->pos, len);
in->buf->pos = in->buf->last;
}
return NGX_OK;
}
static ngx_int_t
ngx_http_postpone_filter_init(ngx_conf_t *cf)
{

View file

@ -132,6 +132,10 @@ ngx_http_header_t ngx_http_headers_in[] = {
offsetof(ngx_http_headers_in_t, transfer_encoding),
ngx_http_process_header_line },
{ ngx_string("TE"),
offsetof(ngx_http_headers_in_t, te),
ngx_http_process_header_line },
{ ngx_string("Expect"),
offsetof(ngx_http_headers_in_t, expect),
ngx_http_process_unique_header_line },

View file

@ -197,6 +197,7 @@ typedef struct {
ngx_table_elt_t *if_range;
ngx_table_elt_t *transfer_encoding;
ngx_table_elt_t *te;
ngx_table_elt_t *expect;
ngx_table_elt_t *upgrade;

View file

@ -55,7 +55,7 @@ static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_process_trailers(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_response(ngx_http_request_t *r,
ngx_http_upstream_t *u);
@ -166,6 +166,8 @@ static ngx_int_t ngx_http_upstream_response_length_variable(
ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_header_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@ -425,6 +427,9 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = {
{ ngx_string("upstream_http_"), NULL, ngx_http_upstream_header_variable,
0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
{ ngx_string("upstream_trailer_"), NULL, ngx_http_upstream_trailer_variable,
0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
{ ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable,
0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 },
@ -1048,6 +1053,13 @@ ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_ERROR;
}
if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
return NGX_ERROR;
}
rc = u->process_header(r);
if (rc == NGX_OK) {
@ -1604,6 +1616,7 @@ ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->request_sent = 0;
u->request_body_sent = 0;
u->request_body_blocked = 0;
if (rc == NGX_AGAIN) {
ngx_add_timer(c->write, u->conf->connect_timeout);
@ -1885,6 +1898,13 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
return NGX_ERROR;
}
if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
return NGX_ERROR;
}
/* reinit the request chain */
file_pos = 0;
@ -1975,7 +1995,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
}
if (rc == NGX_AGAIN) {
if (!c->write->ready) {
if (!c->write->ready || u->request_body_blocked) {
ngx_add_timer(c->write, u->conf->send_timeout);
} else if (c->write->timer_set) {
@ -2000,7 +2020,7 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
}
if (c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
if (ngx_tcp_push(c->fd) == NGX_ERROR) {
if (ngx_tcp_push(c->fd) == -1) {
ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
ngx_tcp_push_n " failed");
ngx_http_upstream_finalize_request(r, u,
@ -2011,7 +2031,9 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
}
u->write_event_handler = ngx_http_upstream_dummy_handler;
if (!u->conf->preserve_output) {
u->write_event_handler = ngx_http_upstream_dummy_handler;
}
if (ngx_handle_write_event(c->write, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
@ -2052,7 +2074,16 @@ ngx_http_upstream_send_request_body(ngx_http_request_t *r,
out = NULL;
}
return ngx_output_chain(&u->output, out);
rc = ngx_output_chain(&u->output, out);
if (rc == NGX_AGAIN) {
u->request_body_blocked = 1;
} else {
u->request_body_blocked = 0;
}
return rc;
}
if (!u->request_sent) {
@ -2093,6 +2124,13 @@ ngx_http_upstream_send_request_body(ngx_http_request_t *r,
ngx_free_chain(r->pool, ln);
}
if (rc == NGX_AGAIN) {
u->request_body_blocked = 1;
} else {
u->request_body_blocked = 0;
}
if (rc == NGX_OK && !r->reading_body) {
break;
}
@ -2157,7 +2195,7 @@ ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
#endif
if (u->header_sent) {
if (u->header_sent && !u->conf->preserve_output) {
u->write_event_handler = ngx_http_upstream_dummy_handler;
(void) ngx_handle_write_event(c->write, 0);
@ -2239,6 +2277,15 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
if (ngx_list_init(&u->headers_in.trailers, r->pool, 2,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
}
#if (NGX_HTTP_CACHE)
if (r->cache) {
@ -2335,45 +2382,7 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
if (!r->subrequest_in_memory) {
ngx_http_upstream_send_response(r, u);
return;
}
/* subrequest content in memory */
if (u->input_filter == NULL) {
u->input_filter_init = ngx_http_upstream_non_buffered_filter_init;
u->input_filter = ngx_http_upstream_non_buffered_filter;
u->input_filter_ctx = r;
}
if (u->input_filter_init(u->input_filter_ctx) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
n = u->buffer.last - u->buffer.pos;
if (n) {
u->buffer.last = u->buffer.pos;
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
}
if (u->length == 0) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
u->read_event_handler = ngx_http_upstream_process_body_in_memory;
ngx_http_upstream_process_body_in_memory(r, u);
ngx_http_upstream_send_response(r, u);
}
@ -2775,81 +2784,48 @@ ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
static void
ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
static ngx_int_t
ngx_http_upstream_process_trailers(ngx_http_request_t *r,
ngx_http_upstream_t *u)
{
size_t size;
ssize_t n;
ngx_buf_t *b;
ngx_event_t *rev;
ngx_connection_t *c;
ngx_uint_t i;
ngx_list_part_t *part;
ngx_table_elt_t *h, *ho;
c = u->peer.connection;
rev = c->read;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http upstream process body in memory");
if (rev->timedout) {
ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out");
ngx_http_upstream_finalize_request(r, u, NGX_HTTP_GATEWAY_TIME_OUT);
return;
if (!u->conf->pass_trailers) {
return NGX_OK;
}
b = &u->buffer;
part = &u->headers_in.trailers.part;
h = part->elts;
for ( ;; ) {
for (i = 0; /* void */; i++) {
size = b->end - b->last;
if (i >= part->nelts) {
if (part->next == NULL) {
break;
}
if (size == 0) {
ngx_log_error(NGX_LOG_ALERT, c->log, 0,
"upstream buffer is too small to read response");
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
part = part->next;
h = part->elts;
i = 0;
}
n = c->recv(c, b->last, size);
if (n == NGX_AGAIN) {
break;
if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
h[i].lowcase_key, h[i].key.len))
{
continue;
}
if (n == 0 || n == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, n);
return;
ho = ngx_list_push(&r->headers_out.trailers);
if (ho == NULL) {
return NGX_ERROR;
}
u->state->bytes_received += n;
u->state->response_length += n;
if (u->input_filter(u->input_filter_ctx, n) == NGX_ERROR) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (!rev->ready) {
break;
}
*ho = h[i];
}
if (u->length == 0) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
if (ngx_handle_read_event(rev, 0) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u, NGX_ERROR);
return;
}
if (rev->active) {
ngx_add_timer(rev, u->conf->read_timeout);
} else if (rev->timer_set) {
ngx_del_timer(rev);
}
return NGX_OK;
}
@ -4359,12 +4335,6 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
#endif
if (r->subrequest_in_memory
&& u->headers_in.status_n >= NGX_HTTP_SPECIAL_RESPONSE)
{
u->buffer.last = u->buffer.pos;
}
r->read_event_handler = ngx_http_block_reading;
if (rc == NGX_DECLINED) {
@ -4396,6 +4366,12 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
}
if (rc == 0) {
if (ngx_http_upstream_process_trailers(r, u) != NGX_OK) {
ngx_http_finalize_request(r, NGX_ERROR);
return;
}
rc = ngx_http_send_special(r, NGX_HTTP_LAST);
} else if (flush) {
@ -5505,6 +5481,21 @@ ngx_http_upstream_header_variable(ngx_http_request_t *r,
}
static ngx_int_t
ngx_http_upstream_trailer_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
if (r->upstream == NULL) {
v->not_found = 1;
return NGX_OK;
}
return ngx_http_variable_unknown_header(v, (ngx_str_t *) data,
&r->upstream->headers_in.trailers.part,
sizeof("upstream_trailer_") - 1);
}
static ngx_int_t
ngx_http_upstream_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)

View file

@ -61,6 +61,7 @@ typedef struct {
ngx_msec_t response_time;
ngx_msec_t connect_time;
ngx_msec_t header_time;
ngx_msec_t queue_time;
off_t response_length;
off_t bytes_received;
@ -221,6 +222,8 @@ typedef struct {
signed store:2;
unsigned intercept_404:1;
unsigned change_buffering:1;
unsigned pass_trailers:1;
unsigned preserve_output:1;
#if (NGX_HTTP_SSL || NGX_COMPAT)
ngx_ssl_t *ssl;
@ -250,6 +253,7 @@ typedef struct {
typedef struct {
ngx_list_t headers;
ngx_list_t trailers;
ngx_uint_t status_n;
ngx_str_t status_line;
@ -388,6 +392,7 @@ struct ngx_http_upstream_s {
unsigned request_sent:1;
unsigned request_body_sent:1;
unsigned request_body_blocked:1;
unsigned header_sent:1;
};

View file

@ -429,7 +429,9 @@ ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
return NULL;
}
v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
if (!(flags & NGX_HTTP_VAR_WEAK)) {
v->flags &= ~NGX_HTTP_VAR_WEAK;
}
return v;
}
@ -494,7 +496,9 @@ ngx_http_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
return NULL;
}
v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
if (!(flags & NGX_HTTP_VAR_WEAK)) {
v->flags &= ~NGX_HTTP_VAR_WEAK;
}
return v;
}

View file

@ -54,8 +54,6 @@ typedef struct {
#define NGX_HTTP_V2_FRAME_BUFFER_SIZE 24
#define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14)
#define NGX_HTTP_V2_ROOT (void *) -1
@ -783,8 +781,8 @@ ngx_http_v2_state_head(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
type, h2c->state.flags, h2c->state.length, h2c->state.sid);
if (type >= NGX_HTTP_V2_FRAME_STATES) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 frame with unknown type %ui", type);
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client sent frame with unknown type %ui", type);
return ngx_http_v2_state_skip(h2c, pos, end);
}
@ -1992,6 +1990,9 @@ ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
}
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 SETTINGS frame");
return ngx_http_v2_state_settings_params(h2c, pos, end);
}
@ -2132,8 +2133,8 @@ ngx_http_v2_state_ping(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_ping);
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 PING frame, flags: %ud", h2c->state.flags);
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 PING frame");
if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) {
return ngx_http_v2_state_skip(h2c, pos, end);
@ -3257,19 +3258,9 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
continue;
}
switch (ch) {
case '\0':
case LF:
case CR:
case ':':
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent invalid header name: \"%V\"",
&header->name);
return NGX_ERROR;
}
if (ch >= 'A' && ch <= 'Z') {
if (ch == '\0' || ch == LF || ch == CR || ch == ':'
|| (ch >= 'A' && ch <= 'Z'))
{
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent invalid header name: \"%V\"",
&header->name);
@ -3283,10 +3274,7 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
for (i = 0; i != header->value.len; i++) {
ch = header->value.data[i];
switch (ch) {
case '\0':
case LF:
case CR:
if (ch == '\0' || ch == LF || ch == CR) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent header \"%V\" with "
"invalid value: \"%V\"",

View file

@ -18,6 +18,7 @@
#define NGX_HTTP_V2_STATE_BUFFER_SIZE 16
#define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14)
#define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1)
#define NGX_HTTP_V2_INT_OCTETS 4
@ -291,6 +292,9 @@ void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
ngx_int_t ngx_http_v2_send_output_queue(ngx_http_v2_connection_t *h2c);
ngx_str_t *ngx_http_v2_get_static_name(ngx_uint_t index);
ngx_str_t *ngx_http_v2_get_static_value(ngx_uint_t index);
ngx_int_t ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c,
ngx_uint_t index, ngx_uint_t name_only);
ngx_int_t ngx_http_v2_add_header(ngx_http_v2_connection_t *h2c,
@ -357,4 +361,53 @@ size_t ngx_http_v2_huff_encode(u_char *src, size_t len, u_char *dst,
#define ngx_http_v2_write_sid ngx_http_v2_write_uint32
#define ngx_http_v2_indexed(i) (128 + (i))
#define ngx_http_v2_inc_indexed(i) (64 + (i))
#define ngx_http_v2_write_name(dst, src, len, tmp) \
ngx_http_v2_string_encode(dst, src, len, tmp, 1)
#define ngx_http_v2_write_value(dst, src, len, tmp) \
ngx_http_v2_string_encode(dst, src, len, tmp, 0)
#define NGX_HTTP_V2_ENCODE_RAW 0
#define NGX_HTTP_V2_ENCODE_HUFF 0x80
#define NGX_HTTP_V2_AUTHORITY_INDEX 1
#define NGX_HTTP_V2_METHOD_INDEX 2
#define NGX_HTTP_V2_METHOD_GET_INDEX 2
#define NGX_HTTP_V2_METHOD_POST_INDEX 3
#define NGX_HTTP_V2_PATH_INDEX 4
#define NGX_HTTP_V2_PATH_ROOT_INDEX 4
#define NGX_HTTP_V2_SCHEME_HTTP_INDEX 6
#define NGX_HTTP_V2_SCHEME_HTTPS_INDEX 7
#define NGX_HTTP_V2_STATUS_INDEX 8
#define NGX_HTTP_V2_STATUS_200_INDEX 8
#define NGX_HTTP_V2_STATUS_204_INDEX 9
#define NGX_HTTP_V2_STATUS_206_INDEX 10
#define NGX_HTTP_V2_STATUS_304_INDEX 11
#define NGX_HTTP_V2_STATUS_400_INDEX 12
#define NGX_HTTP_V2_STATUS_404_INDEX 13
#define NGX_HTTP_V2_STATUS_500_INDEX 14
#define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
#define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
#define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28
#define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31
#define NGX_HTTP_V2_DATE_INDEX 33
#define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44
#define NGX_HTTP_V2_LOCATION_INDEX 46
#define NGX_HTTP_V2_SERVER_INDEX 54
#define NGX_HTTP_V2_USER_AGENT_INDEX 58
#define NGX_HTTP_V2_VARY_INDEX 59
u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
u_char *tmp, ngx_uint_t lower);
#endif /* _NGX_HTTP_V2_H_INCLUDED_ */

View file

@ -0,0 +1,62 @@
/*
* Copyright (C) Nginx, Inc.
* Copyright (C) Valentin V. Bartenev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
ngx_uint_t value);
u_char *
ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
ngx_uint_t lower)
{
size_t hlen;
hlen = ngx_http_v2_huff_encode(src, len, tmp, lower);
if (hlen > 0) {
*dst = NGX_HTTP_V2_ENCODE_HUFF;
dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), hlen);
return ngx_cpymem(dst, tmp, hlen);
}
*dst = NGX_HTTP_V2_ENCODE_RAW;
dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), len);
if (lower) {
ngx_strlow(dst, src, len);
return dst + len;
}
return ngx_cpymem(dst, src, len);
}
static u_char *
ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value)
{
if (value < prefix) {
*pos++ |= value;
return pos;
}
*pos++ |= prefix;
value -= prefix;
while (value >= 128) {
*pos++ = value % 128 + 128;
value /= 128;
}
*pos++ = (u_char) value;
return pos;
}

View file

@ -23,43 +23,6 @@
#define ngx_http_v2_literal_size(h) \
(ngx_http_v2_integer_octets(sizeof(h) - 1) + sizeof(h) - 1)
#define ngx_http_v2_indexed(i) (128 + (i))
#define ngx_http_v2_inc_indexed(i) (64 + (i))
#define ngx_http_v2_write_name(dst, src, len, tmp) \
ngx_http_v2_string_encode(dst, src, len, tmp, 1)
#define ngx_http_v2_write_value(dst, src, len, tmp) \
ngx_http_v2_string_encode(dst, src, len, tmp, 0)
#define NGX_HTTP_V2_ENCODE_RAW 0
#define NGX_HTTP_V2_ENCODE_HUFF 0x80
#define NGX_HTTP_V2_AUTHORITY_INDEX 1
#define NGX_HTTP_V2_METHOD_GET_INDEX 2
#define NGX_HTTP_V2_PATH_INDEX 4
#define NGX_HTTP_V2_SCHEME_HTTP_INDEX 6
#define NGX_HTTP_V2_SCHEME_HTTPS_INDEX 7
#define NGX_HTTP_V2_STATUS_INDEX 8
#define NGX_HTTP_V2_STATUS_200_INDEX 8
#define NGX_HTTP_V2_STATUS_204_INDEX 9
#define NGX_HTTP_V2_STATUS_206_INDEX 10
#define NGX_HTTP_V2_STATUS_304_INDEX 11
#define NGX_HTTP_V2_STATUS_400_INDEX 12
#define NGX_HTTP_V2_STATUS_404_INDEX 13
#define NGX_HTTP_V2_STATUS_500_INDEX 14
#define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16
#define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17
#define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28
#define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31
#define NGX_HTTP_V2_DATE_INDEX 33
#define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44
#define NGX_HTTP_V2_LOCATION_INDEX 46
#define NGX_HTTP_V2_SERVER_INDEX 54
#define NGX_HTTP_V2_USER_AGENT_INDEX 58
#define NGX_HTTP_V2_VARY_INDEX 59
#define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1
@ -93,10 +56,6 @@ static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r);
static ngx_int_t ngx_http_v2_push_resource(ngx_http_request_t *r,
ngx_str_t *path, ngx_str_t *binary);
static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len,
u_char *tmp, ngx_uint_t lower);
static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix,
ngx_uint_t value);
static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame(
ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin);
static ngx_http_v2_out_frame_t *ngx_http_v2_create_push_frame(
@ -177,7 +136,7 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
u_char status, *pos, *start, *p, *tmp;
size_t len, tmp_len;
ngx_str_t host, location;
ngx_uint_t i, port;
ngx_uint_t i, port, fin;
ngx_list_part_t *part;
ngx_table_elt_t *header;
ngx_connection_t *fc;
@ -684,7 +643,10 @@ ngx_http_v2_header_filter(ngx_http_request_t *r)
header[i].value.len, tmp);
}
frame = ngx_http_v2_create_headers_frame(r, start, pos, r->header_only);
fin = r->header_only
|| (r->headers_out.content_length_n == 0 && !r->expect_trailers);
frame = ngx_http_v2_create_headers_frame(r, start, pos, fin);
if (frame == NULL) {
return NGX_ERROR;
}
@ -1111,54 +1073,6 @@ ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path,
}
static u_char *
ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp,
ngx_uint_t lower)
{
size_t hlen;
hlen = ngx_http_v2_huff_encode(src, len, tmp, lower);
if (hlen > 0) {
*dst = NGX_HTTP_V2_ENCODE_HUFF;
dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), hlen);
return ngx_cpymem(dst, tmp, hlen);
}
*dst = NGX_HTTP_V2_ENCODE_RAW;
dst = ngx_http_v2_write_int(dst, ngx_http_v2_prefix(7), len);
if (lower) {
ngx_strlow(dst, src, len);
return dst + len;
}
return ngx_cpymem(dst, src, len);
}
static u_char *
ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, ngx_uint_t value)
{
if (value < prefix) {
*pos++ |= value;
return pos;
}
*pos++ |= prefix;
value -= prefix;
while (value >= 128) {
*pos++ = value % 128 + 128;
value /= 128;
}
*pos++ = (u_char) value;
return pos;
}
static ngx_http_v2_out_frame_t *
ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos,
u_char *end, ngx_uint_t fin)
@ -1255,9 +1169,9 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos,
cl->next = NULL;
frame->last = cl;
ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2:%ui create HEADERS frame %p: len:%uz",
stream->node->id, frame, frame->length);
ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http2:%ui create HEADERS frame %p: len:%uz fin:%ui",
stream->node->id, frame, frame->length, fin);
return frame;
}
@ -1526,7 +1440,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
in = in->next;
}
if (in == NULL) {
if (in == NULL || stream->out_closed) {
if (stream->queued) {
fc->write->active = 1;

View file

@ -86,6 +86,20 @@ static ngx_http_v2_header_t ngx_http_v2_static_table[] = {
/ sizeof(ngx_http_v2_header_t))
ngx_str_t *
ngx_http_v2_get_static_name(ngx_uint_t index)
{
return &ngx_http_v2_static_table[index - 1].name;
}
ngx_str_t *
ngx_http_v2_get_static_value(ngx_uint_t index)
{
return &ngx_http_v2_static_table[index - 1].value;
}
ngx_int_t
ngx_http_v2_get_indexed_header(ngx_http_v2_connection_t *h2c, ngx_uint_t index,
ngx_uint_t name_only)

View file

@ -135,7 +135,7 @@ ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (ngx_freebsd_use_tcp_nopush
&& c->tcp_nopush == NGX_TCP_NOPUSH_UNSET)
{
if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
if (ngx_tcp_nopush(c->fd) == -1) {
err = ngx_socket_errno;
/*

View file

@ -130,7 +130,7 @@ ngx_linux_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
if (c->tcp_nodelay == NGX_TCP_NODELAY_UNSET) {
if (ngx_tcp_nopush(c->fd) == NGX_ERROR) {
if (ngx_tcp_nopush(c->fd) == -1) {
err = ngx_socket_errno;
/*

View file

@ -341,18 +341,18 @@ ngx_stream_geo_addr(ngx_stream_session_t *s, ngx_stream_geo_ctx_t *ctx,
static char *
ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *rv;
size_t len;
ngx_str_t *value, name;
ngx_uint_t i;
ngx_conf_t save;
ngx_pool_t *pool;
ngx_array_t *a;
ngx_stream_variable_t *var;
ngx_stream_geo_ctx_t *geo;
ngx_stream_geo_conf_ctx_t ctx;
char *rv;
size_t len;
ngx_str_t *value, name;
ngx_uint_t i;
ngx_conf_t save;
ngx_pool_t *pool;
ngx_array_t *a;
ngx_stream_variable_t *var;
ngx_stream_geo_ctx_t *geo;
ngx_stream_geo_conf_ctx_t ctx;
#if (NGX_HAVE_INET6)
static struct in6_addr zero;
static struct in6_addr zero;
#endif
value = cf->args->elts;
@ -409,6 +409,7 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ctx.temp_pool = ngx_create_pool(NGX_DEFAULT_POOL_SIZE, cf->log);
if (ctx.temp_pool == NULL) {
ngx_destroy_pool(pool);
return NGX_CONF_ERROR;
}
@ -430,6 +431,10 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
*cf = save;
if (rv != NGX_CONF_OK) {
goto failed;
}
if (ctx.ranges) {
if (ctx.high.low && !ctx.binary_include) {
@ -449,7 +454,7 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *));
if (ctx.high.low[i] == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
ngx_memcpy(ctx.high.low[i], a->elts, len);
@ -475,14 +480,11 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
var->get_handler = ngx_stream_geo_range_variable;
var->data = (uintptr_t) geo;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
} else {
if (ctx.tree == NULL) {
ctx.tree = ngx_radix_tree_create(cf->pool, -1);
if (ctx.tree == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
}
@ -492,7 +494,7 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (ctx.tree6 == NULL) {
ctx.tree6 = ngx_radix_tree_create(cf->pool, -1);
if (ctx.tree6 == NULL) {
return NGX_CONF_ERROR;
goto failed;
}
}
@ -502,14 +504,11 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
var->get_handler = ngx_stream_geo_cidr_variable;
var->data = (uintptr_t) geo;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
if (ngx_radix32tree_insert(ctx.tree, 0, 0,
(uintptr_t) &ngx_stream_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
goto failed;
}
/* NGX_BUSY is okay (default was set explicitly) */
@ -519,12 +518,22 @@ ngx_stream_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
(uintptr_t) &ngx_stream_variable_null_value)
== NGX_ERROR)
{
return NGX_CONF_ERROR;
goto failed;
}
#endif
}
return rv;
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
return NGX_CONF_OK;
failed:
ngx_destroy_pool(ctx.temp_pool);
ngx_destroy_pool(pool);
return NGX_CONF_ERROR;
}

View file

@ -89,6 +89,11 @@ typedef struct {
} ngx_stream_log_var_t;
#define NGX_STREAM_LOG_ESCAPE_DEFAULT 0
#define NGX_STREAM_LOG_ESCAPE_JSON 1
#define NGX_STREAM_LOG_ESCAPE_NONE 2
static void ngx_stream_log_write(ngx_stream_session_t *s, ngx_stream_log_t *log,
u_char *buf, size_t len);
static ssize_t ngx_stream_log_script_write(ngx_stream_session_t *s,
@ -106,7 +111,7 @@ static void ngx_stream_log_flush(ngx_open_file_t *file, ngx_log_t *log);
static void ngx_stream_log_flush_handler(ngx_event_t *ev);
static ngx_int_t ngx_stream_log_variable_compile(ngx_conf_t *cf,
ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t json);
ngx_stream_log_op_t *op, ngx_str_t *value, ngx_uint_t escape);
static size_t ngx_stream_log_variable_getlen(ngx_stream_session_t *s,
uintptr_t data);
static u_char *ngx_stream_log_variable(ngx_stream_session_t *s, u_char *buf,
@ -116,6 +121,10 @@ static size_t ngx_stream_log_json_variable_getlen(ngx_stream_session_t *s,
uintptr_t data);
static u_char *ngx_stream_log_json_variable(ngx_stream_session_t *s,
u_char *buf, ngx_stream_log_op_t *op);
static size_t ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
uintptr_t data);
static u_char *ngx_stream_log_unescaped_variable(ngx_stream_session_t *s,
u_char *buf, ngx_stream_log_op_t *op);
static void *ngx_stream_log_create_main_conf(ngx_conf_t *cf);
@ -682,7 +691,7 @@ ngx_stream_log_copy_long(ngx_stream_session_t *s, u_char *buf,
static ngx_int_t
ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
ngx_str_t *value, ngx_uint_t json)
ngx_str_t *value, ngx_uint_t escape)
{
ngx_int_t index;
@ -693,11 +702,18 @@ ngx_stream_log_variable_compile(ngx_conf_t *cf, ngx_stream_log_op_t *op,
op->len = 0;
if (json) {
switch (escape) {
case NGX_STREAM_LOG_ESCAPE_JSON:
op->getlen = ngx_stream_log_json_variable_getlen;
op->run = ngx_stream_log_json_variable;
break;
} else {
case NGX_STREAM_LOG_ESCAPE_NONE:
op->getlen = ngx_stream_log_unescaped_variable_getlen;
op->run = ngx_stream_log_unescaped_variable;
break;
default: /* NGX_STREAM_LOG_ESCAPE_DEFAULT */
op->getlen = ngx_stream_log_variable_getlen;
op->run = ngx_stream_log_variable;
}
@ -851,6 +867,40 @@ ngx_stream_log_json_variable(ngx_stream_session_t *s, u_char *buf,
}
static size_t
ngx_stream_log_unescaped_variable_getlen(ngx_stream_session_t *s,
uintptr_t data)
{
ngx_stream_variable_value_t *value;
value = ngx_stream_get_indexed_variable(s, data);
if (value == NULL || value->not_found) {
return 0;
}
value->escape = 0;
return value->len;
}
static u_char *
ngx_stream_log_unescaped_variable(ngx_stream_session_t *s, u_char *buf,
ngx_stream_log_op_t *op)
{
ngx_stream_variable_value_t *value;
value = ngx_stream_get_indexed_variable(s, op->data);
if (value == NULL || value->not_found) {
return buf;
}
return ngx_cpymem(buf, value->data, value->len);
}
static void *
ngx_stream_log_create_main_conf(ngx_conf_t *cf)
{
@ -1265,17 +1315,20 @@ ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
size_t i, len;
ngx_str_t *value, var;
ngx_int_t *flush;
ngx_uint_t bracket, json;
ngx_uint_t bracket, escape;
ngx_stream_log_op_t *op;
json = 0;
escape = NGX_STREAM_LOG_ESCAPE_DEFAULT;
value = args->elts;
if (s < args->nelts && ngx_strncmp(value[s].data, "escape=", 7) == 0) {
data = value[s].data + 7;
if (ngx_strcmp(data, "json") == 0) {
json = 1;
escape = NGX_STREAM_LOG_ESCAPE_JSON;
} else if (ngx_strcmp(data, "none") == 0) {
escape = NGX_STREAM_LOG_ESCAPE_NONE;
} else if (ngx_strcmp(data, "default") != 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
@ -1350,7 +1403,7 @@ ngx_stream_log_compile_format(ngx_conf_t *cf, ngx_array_t *flushes,
goto invalid;
}
if (ngx_stream_log_variable_compile(cf, op, &var, json)
if (ngx_stream_log_variable_compile(cf, op, &var, escape)
!= NGX_OK)
{
return NGX_CONF_ERROR;

View file

@ -17,10 +17,12 @@ typedef struct {
typedef struct {
size_t left;
size_t size;
size_t ext;
u_char *pos;
u_char *dst;
u_char buf[4];
ngx_str_t host;
ngx_str_t alpn;
ngx_log_t *log;
ngx_pool_t *pool;
ngx_uint_t state;
@ -32,6 +34,8 @@ static ngx_int_t ngx_stream_ssl_preread_parse_record(
ngx_stream_ssl_preread_ctx_t *ctx, u_char *pos, u_char *last);
static ngx_int_t ngx_stream_ssl_preread_server_name_variable(
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_ssl_preread_alpn_protocols_variable(
ngx_stream_session_t *s, ngx_stream_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf);
static void *ngx_stream_ssl_preread_create_srv_conf(ngx_conf_t *cf);
static char *ngx_stream_ssl_preread_merge_srv_conf(ngx_conf_t *cf, void *parent,
@ -85,6 +89,9 @@ static ngx_stream_variable_t ngx_stream_ssl_preread_vars[] = {
{ ngx_string("ssl_preread_server_name"), NULL,
ngx_stream_ssl_preread_server_name_variable, 0, 0, 0 },
{ ngx_string("ssl_preread_alpn_protocols"), NULL,
ngx_stream_ssl_preread_alpn_protocols_variable, 0, 0, 0 },
ngx_stream_null_variable
};
@ -139,12 +146,14 @@ ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
if (p[0] != 0x16) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: not a handshake");
ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
return NGX_DECLINED;
}
if (p[1] != 3) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: unsupported SSL version");
ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
return NGX_DECLINED;
}
@ -158,6 +167,12 @@ ngx_stream_ssl_preread_handler(ngx_stream_session_t *s)
p += 5;
rc = ngx_stream_ssl_preread_parse_record(ctx, p, p + len);
if (rc == NGX_DECLINED) {
ngx_stream_set_ctx(s, NULL, ngx_stream_ssl_preread_module);
return NGX_DECLINED;
}
if (rc != NGX_AGAIN) {
return rc;
}
@ -175,7 +190,7 @@ static ngx_int_t
ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
u_char *pos, u_char *last)
{
size_t left, n, size;
size_t left, n, size, ext;
u_char *dst, *p;
enum {
@ -192,7 +207,10 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
sw_ext_header, /* extension_type, extension_data length */
sw_sni_len, /* SNI length */
sw_sni_host_head, /* SNI name_type, host_name length */
sw_sni_host /* SNI host_name */
sw_sni_host, /* SNI host_name */
sw_alpn_len, /* ALPN length */
sw_alpn_proto_len, /* ALPN protocol_name length */
sw_alpn_proto_data /* ALPN protocol_name */
} state;
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
@ -201,6 +219,7 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
state = ctx->state;
size = ctx->size;
left = ctx->left;
ext = ctx->ext;
dst = ctx->dst;
p = ctx->buf;
@ -299,10 +318,18 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
break;
case sw_ext_header:
if (p[0] == 0 && p[1] == 0) {
if (p[0] == 0 && p[1] == 0 && ctx->host.data == NULL) {
/* SNI extension */
state = sw_sni_len;
dst = NULL;
dst = p;
size = 2;
break;
}
if (p[0] == 0 && p[1] == 16 && ctx->alpn.data == NULL) {
/* ALPN extension */
state = sw_alpn_len;
dst = p;
size = 2;
break;
}
@ -313,6 +340,7 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
break;
case sw_sni_len:
ext = (p[0] << 8) + p[1];
state = sw_sni_host_head;
dst = p;
size = 3;
@ -325,14 +353,21 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
return NGX_DECLINED;
}
state = sw_sni_host;
size = (p[1] << 8) + p[2];
if (ext < 3 + size) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: SNI format error");
return NGX_DECLINED;
}
ext -= 3 + size;
ctx->host.data = ngx_pnalloc(ctx->pool, size);
if (ctx->host.data == NULL) {
return NGX_ERROR;
}
state = sw_sni_host;
dst = ctx->host.data;
break;
@ -341,19 +376,77 @@ ngx_stream_ssl_preread_parse_record(ngx_stream_ssl_preread_ctx_t *ctx,
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: SNI hostname \"%V\"", &ctx->host);
return NGX_OK;
state = sw_ext;
dst = NULL;
size = ext;
break;
case sw_alpn_len:
ext = (p[0] << 8) + p[1];
ctx->alpn.data = ngx_pnalloc(ctx->pool, ext);
if (ctx->alpn.data == NULL) {
return NGX_ERROR;
}
state = sw_alpn_proto_len;
dst = p;
size = 1;
break;
case sw_alpn_proto_len:
size = p[0];
if (size == 0) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: ALPN empty protocol");
return NGX_DECLINED;
}
if (ext < 1 + size) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: ALPN format error");
return NGX_DECLINED;
}
ext -= 1 + size;
state = sw_alpn_proto_data;
dst = ctx->alpn.data + ctx->alpn.len;
break;
case sw_alpn_proto_data:
ctx->alpn.len += p[0];
ngx_log_debug1(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: ALPN protocols \"%V\"", &ctx->alpn);
if (ext) {
ctx->alpn.data[ctx->alpn.len++] = ',';
state = sw_alpn_proto_len;
dst = p;
size = 1;
break;
}
state = sw_ext;
dst = NULL;
size = 0;
break;
}
if (left < size) {
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: failed to parse handshake");
return NGX_DECLINED;
ngx_log_debug0(NGX_LOG_DEBUG_STREAM, ctx->log, 0,
"ssl preread: failed to parse handshake");
return NGX_DECLINED;
}
}
ctx->state = state;
ctx->size = size;
ctx->left = left;
ctx->ext = ext;
ctx->dst = dst;
return NGX_AGAIN;
@ -383,6 +476,29 @@ ngx_stream_ssl_preread_server_name_variable(ngx_stream_session_t *s,
}
static ngx_int_t
ngx_stream_ssl_preread_alpn_protocols_variable(ngx_stream_session_t *s,
ngx_variable_value_t *v, uintptr_t data)
{
ngx_stream_ssl_preread_ctx_t *ctx;
ctx = ngx_stream_get_module_ctx(s, ngx_stream_ssl_preread_module);
if (ctx == NULL) {
v->not_found = 1;
return NGX_OK;
}
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->len = ctx->alpn.len;
v->data = ctx->alpn.data;
return NGX_OK;
}
static ngx_int_t
ngx_stream_ssl_preread_add_variables(ngx_conf_t *cf)
{

View file

@ -161,7 +161,9 @@ ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
return NULL;
}
v->flags &= flags | ~NGX_STREAM_VAR_WEAK;
if (!(flags & NGX_STREAM_VAR_WEAK)) {
v->flags &= ~NGX_STREAM_VAR_WEAK;
}
return v;
}
@ -227,7 +229,9 @@ ngx_stream_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name,
return NULL;
}
v->flags &= flags | ~NGX_STREAM_VAR_WEAK;
if (!(flags & NGX_STREAM_VAR_WEAK)) {
v->flags &= ~NGX_STREAM_VAR_WEAK;
}
return v;
}