From a7bf678e7cbde2993d4a053b976a9df6609df7b7 Mon Sep 17 00:00:00 2001 From: fthielen Date: Thu, 10 Aug 2017 14:23:46 +0200 Subject: [PATCH] Update auf Nginx 1.13.4 --- auto/cc/bcc | 1 - auto/cc/msvc | 1 - auto/cc/owc | 1 - auto/lib/conf | 2 +- auto/modules | 22 + auto/options | 3 + auto/os/conf | 8 + auto/os/win32 | 1 + auto/unix | 5 +- configure | 2 +- src/core/nginx.c | 6 + src/core/nginx.h | 4 +- src/core/ngx_connection.c | 4 +- src/core/ngx_cycle.c | 4 +- src/core/ngx_file.c | 4 +- src/core/ngx_parse_time.c | 16 +- src/core/ngx_resolver.c | 132 +++--- src/core/ngx_resolver.h | 4 +- src/core/ngx_rwlock.c | 11 +- src/core/ngx_rwlock.h | 1 + src/core/ngx_slab.c | 60 +-- src/core/ngx_slab.h | 1 + src/core/ngx_string.c | 8 +- src/event/ngx_event_openssl.c | 2 +- src/event/ngx_event_openssl_stapling.c | 2 +- .../modules/ngx_http_addition_filter_module.c | 2 + src/http/modules/ngx_http_browser_module.c | 45 +- .../modules/ngx_http_chunked_filter_module.c | 158 +++++-- src/http/modules/ngx_http_fastcgi_module.c | 2 +- src/http/modules/ngx_http_geoip_module.c | 2 +- .../modules/ngx_http_gzip_filter_module.c | 8 +- .../modules/ngx_http_headers_filter_module.c | 170 ++++++-- src/http/modules/ngx_http_mirror_module.c | 264 ++++++++++++ src/http/modules/ngx_http_proxy_module.c | 167 +++----- .../modules/ngx_http_range_filter_module.c | 13 +- src/http/modules/ngx_http_realip_module.c | 2 +- src/http/modules/ngx_http_referer_module.c | 39 +- .../modules/ngx_http_slice_filter_module.c | 10 +- src/http/modules/ngx_http_ssi_filter_module.c | 6 +- src/http/modules/ngx_http_ssl_module.c | 2 +- .../modules/ngx_http_stub_status_module.c | 2 +- src/http/modules/ngx_http_try_files_module.c | 404 ++++++++++++++++++ .../modules/ngx_http_upstream_zone_module.c | 95 +++- .../modules/ngx_http_userid_filter_module.c | 4 + src/http/ngx_http.c | 21 +- src/http/ngx_http_core_module.c | 316 +------------- src/http/ngx_http_core_module.h | 18 +- src/http/ngx_http_file_cache.c | 1 + src/http/ngx_http_parse.c | 14 +- src/http/ngx_http_request.c | 8 + src/http/ngx_http_request.h | 3 + src/http/ngx_http_upstream.c | 63 ++- src/http/ngx_http_variables.c | 33 +- src/http/ngx_http_variables.h | 2 + src/http/v2/ngx_http_v2.c | 122 +++--- src/http/v2/ngx_http_v2.h | 9 + src/http/v2/ngx_http_v2_filter_module.c | 166 ++++++- src/http/v2/ngx_http_v2_module.c | 2 +- src/misc/ngx_google_perftools_module.c | 2 +- src/os/unix/ngx_udp_sendmsg_chain.c | 6 +- src/stream/ngx_stream_geoip_module.c | 2 +- src/stream/ngx_stream_realip_module.c | 2 +- src/stream/ngx_stream_ssl_module.c | 2 +- src/stream/ngx_stream_ssl_preread_module.c | 2 +- src/stream/ngx_stream_upstream.c | 2 +- src/stream/ngx_stream_upstream_zone_module.c | 95 +++- src/stream/ngx_stream_variables.c | 2 +- src/stream/ngx_stream_variables.h | 2 + 68 files changed, 1782 insertions(+), 813 deletions(-) create mode 100644 src/http/modules/ngx_http_mirror_module.c create mode 100644 src/http/modules/ngx_http_try_files_module.c diff --git a/auto/cc/bcc b/auto/cc/bcc index ec82e60..e990a9f 100644 --- a/auto/cc/bcc +++ b/auto/cc/bcc @@ -62,7 +62,6 @@ ngx_include_opt="-I" ngx_objout="-o" ngx_binout="-e" ngx_objext="obj" -ngx_binext=".exe" ngx_long_start='@&&| ' diff --git a/auto/cc/msvc b/auto/cc/msvc index 4eef101..8257252 100644 --- a/auto/cc/msvc +++ b/auto/cc/msvc @@ -142,7 +142,6 @@ ngx_pic_opt= ngx_objout="-Fo" ngx_binout="-Fe" ngx_objext="obj" -ngx_binext=".exe" ngx_long_start='@<< ' diff --git a/auto/cc/owc b/auto/cc/owc index a063aa3..f7fd88c 100644 --- a/auto/cc/owc +++ b/auto/cc/owc @@ -84,7 +84,6 @@ ngx_include_opt="-i=" ngx_objout="-fo" ngx_binout="-fe=" ngx_objext="obj" -ngx_binext=".exe" ngx_regex_dirsep='\\' ngx_dirsep="\\" diff --git a/auto/lib/conf b/auto/lib/conf index 0b8545a..2c7af10 100644 --- a/auto/lib/conf +++ b/auto/lib/conf @@ -7,7 +7,7 @@ if [ $USE_PCRE = YES -o $PCRE != NONE ]; then . auto/lib/pcre/conf else - if [ $USE_PCRE = DISABLED -a $HTTP_REWRITE = YES ]; then + if [ $USE_PCRE = DISABLED -a $HTTP = YES -a $HTTP_REWRITE = YES ]; then cat << END diff --git a/auto/modules b/auto/modules index be3561e..26b05bd 100644 --- a/auto/modules +++ b/auto/modules @@ -506,6 +506,28 @@ if [ $HTTP = YES ]; then . auto/module fi + if [ $HTTP_MIRROR = YES ]; then + ngx_module_name=ngx_http_mirror_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_mirror_module.c + ngx_module_libs= + ngx_module_link=$HTTP_MIRROR + + . auto/module + fi + + if :; then + ngx_module_name=ngx_http_try_files_module + ngx_module_incs= + ngx_module_deps= + ngx_module_srcs=src/http/modules/ngx_http_try_files_module.c + ngx_module_libs= + ngx_module_link=YES + + . auto/module + fi + if [ $HTTP_AUTH_REQUEST = YES ]; then ngx_module_name=ngx_http_auth_request_module ngx_module_incs= diff --git a/auto/options b/auto/options index 66b822a..24c2618 100644 --- a/auto/options +++ b/auto/options @@ -70,6 +70,7 @@ HTTP_DAV=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_AUTH_REQUEST=NO +HTTP_MIRROR=YES HTTP_USERID=YES HTTP_SLICE=NO HTTP_AUTOINDEX=YES @@ -249,6 +250,7 @@ $0: warning: the \"--with-ipv6\" option is deprecated" --without-http_userid_module) HTTP_USERID=NO ;; --without-http_access_module) HTTP_ACCESS=NO ;; --without-http_auth_basic_module) HTTP_AUTH_BASIC=NO ;; + --without-http_mirror_module) HTTP_MIRROR=NO ;; --without-http_autoindex_module) HTTP_AUTOINDEX=NO ;; --without-http_status_module) HTTP_STATUS=NO ;; --without-http_geo_module) HTTP_GEO=NO ;; @@ -458,6 +460,7 @@ cat << END --without-http_userid_module disable ngx_http_userid_module --without-http_access_module disable ngx_http_access_module --without-http_auth_basic_module disable ngx_http_auth_basic_module + --without-http_mirror_module disable ngx_http_mirror_module --without-http_autoindex_module disable ngx_http_autoindex_module --without-http_geo_module disable ngx_http_geo_module --without-http_map_module disable ngx_http_map_module diff --git a/auto/os/conf b/auto/os/conf index 6ad0e74..6096af5 100644 --- a/auto/os/conf +++ b/auto/os/conf @@ -41,6 +41,14 @@ case "$NGX_PLATFORM" in ' ;; + NetBSD:*) + CORE_INCS="$UNIX_INCS" + CORE_DEPS="$UNIX_DEPS $POSIX_DEPS" + CORE_SRCS="$UNIX_SRCS" + + NGX_RPATH=YES + ;; + HP-UX:*) # HP/UX have=NGX_HPUX . auto/have_headers diff --git a/auto/os/win32 b/auto/os/win32 index 650cf49..7a82774 100644 --- a/auto/os/win32 +++ b/auto/os/win32 @@ -13,6 +13,7 @@ NGX_ICONS="$NGX_WIN32_ICONS" SELECT_SRCS=$WIN32_SELECT_SRCS ngx_pic_opt= +ngx_binext=".exe" case "$NGX_CC_NAME" in diff --git a/auto/unix b/auto/unix index 7c6a855..10835f6 100644 --- a/auto/unix +++ b/auto/unix @@ -428,7 +428,10 @@ ngx_feature_incs="#include #include " ngx_feature_path= ngx_feature_libs= -ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" +ngx_feature_test="struct in_pktinfo pkt; + pkt.ipi_spec_dst.s_addr = INADDR_ANY; + (void) pkt; + setsockopt(0, IPPROTO_IP, IP_PKTINFO, NULL, 0)" . auto/feature diff --git a/configure b/configure index ceff15e..7e6e33a 100755 --- a/configure +++ b/configure @@ -36,7 +36,7 @@ if test -z "$NGX_PLATFORM"; then NGX_PLATFORM="$NGX_SYSTEM:$NGX_RELEASE:$NGX_MACHINE"; case "$NGX_SYSTEM" in - MINGW32_*) + MINGW32_* | MINGW64_* | MSYS_*) NGX_PLATFORM=win32 ;; esac diff --git a/src/core/nginx.c b/src/core/nginx.c index abaa50d..c3a29cc 100644 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -273,6 +273,12 @@ main(int argc, char *const *argv) return 1; } + /* + * ngx_slab_sizes_init() requires ngx_pagesize set in ngx_os_init() + */ + + ngx_slab_sizes_init(); + if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } diff --git a/src/core/nginx.h b/src/core/nginx.h index 8cc2d80..3649945 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1013001 -#define NGINX_VERSION "1.13.1" +#define nginx_version 1013004 +#define NGINX_VERSION "1.13.4" #define NGINX_VER "nginx/" NGINX_VERSION #ifdef NGX_BUILD diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c index ec4692b..392fc35 100644 --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -473,7 +473,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) #if (NGX_HAVE_REUSEPORT) - if (ls[i].reuseport) { + if (ls[i].reuseport && !ngx_test_config) { int reuseport; reuseport = 1; @@ -483,7 +483,7 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, - "setsockopt(SO_REUSEPORT) %V failed, ignored", + "setsockopt(SO_REUSEPORT) %V failed", &ls[i].addr_text); if (ngx_close_socket(s) == -1) { diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c index aee7a58..675a506 100644 --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -1124,9 +1124,7 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) if (user != (ngx_uid_t) NGX_CONF_UNSET_UINT) { ngx_file_info_t fi; - if (ngx_file_info((const char *) file[i].name.data, &fi) - == NGX_FILE_ERROR) - { + if (ngx_file_info(file[i].name.data, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", file[i].name.data); diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c index b7dd4bc..3a94089 100644 --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -622,9 +622,7 @@ ngx_create_paths(ngx_cycle_t *cycle, ngx_uid_t user) { ngx_file_info_t fi; - if (ngx_file_info((const char *) path[i]->name.data, &fi) - == NGX_FILE_ERROR) - { + if (ngx_file_info(path[i]->name.data, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, ngx_file_info_n " \"%s\" failed", path[i]->name.data); return NGX_ERROR; diff --git a/src/core/ngx_parse_time.c b/src/core/ngx_parse_time.c index 13afde3..a5c5034 100644 --- a/src/core/ngx_parse_time.c +++ b/src/core/ngx_parse_time.c @@ -58,7 +58,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = (*p - '0') * 10 + *(p + 1) - '0'; + day = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p == ' ') { @@ -132,7 +132,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); p += 4; } else if (fmt == rfc850) { @@ -140,7 +140,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - year = (*p - '0') * 10 + *(p + 1) - '0'; + year = (*p - '0') * 10 + (*(p + 1) - '0'); year += (year < 70) ? 2000 : 1900; p += 2; } @@ -161,7 +161,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - day = day * 10 + *p++ - '0'; + day = day * 10 + (*p++ - '0'); } if (end - p < 14) { @@ -177,7 +177,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - hour = (*p - '0') * 10 + *(p + 1) - '0'; + hour = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -188,7 +188,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - min = (*p - '0') * 10 + *(p + 1) - '0'; + min = (*p - '0') * 10 + (*(p + 1) - '0'); p += 2; if (*p++ != ':') { @@ -199,7 +199,7 @@ ngx_parse_http_time(u_char *value, size_t len) return NGX_ERROR; } - sec = (*p - '0') * 10 + *(p + 1) - '0'; + sec = (*p - '0') * 10 + (*(p + 1) - '0'); if (fmt == isoc) { p += 2; @@ -216,7 +216,7 @@ ngx_parse_http_time(u_char *value, size_t len) } year = (*p - '0') * 1000 + (*(p + 1) - '0') * 100 - + (*(p + 2) - '0') * 10 + *(p + 3) - '0'; + + (*(p + 2) - '0') * 10 + (*(p + 3) - '0'); } if (hour > 23 || min > 59 || sec > 59) { diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c index e140ab6..cd55520 100644 --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -105,6 +105,8 @@ static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src, u_char *last); +static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r, + ngx_resolver_ctx_t *ctx); static void ngx_resolver_timeout_handler(ngx_event_t *ev); static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn); static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size); @@ -189,6 +191,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n) r->event->handler = ngx_resolver_resend_handler; r->event->data = r; r->event->log = &cf->cycle->new_log; + r->event->cancelable = 1; r->ident = -1; r->resend_timeout = 5; @@ -443,7 +446,7 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) name.data = ngx_resolver_alloc(r, name.len); if (name.data == NULL) { - return NGX_ERROR; + goto failed; } if (slen == ctx->service.len) { @@ -481,6 +484,8 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx) ngx_resolver_free(r, ctx->event); } +failed: + ngx_resolver_free(r, ctx); return NGX_ERROR; @@ -726,24 +731,14 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } last->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; do { ctx->node = rn; @@ -861,18 +856,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -890,6 +875,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx, rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; do { ctx->node = rn; @@ -1003,24 +989,14 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) } if (rn->waiting) { - - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - return NGX_ERROR; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + return NGX_ERROR; } ctx->next = rn->waiting; rn->waiting = ctx; ctx->state = NGX_AGAIN; + ctx->async = 1; ctx->node = rn; /* unlock addr mutex */ @@ -1084,18 +1060,8 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) goto failed; } - if (ctx->event == NULL && ctx->timeout) { - ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); - if (ctx->event == NULL) { - goto failed; - } - - ctx->event->handler = ngx_resolver_timeout_handler; - ctx->event->data = ctx; - ctx->event->log = r->log; - ctx->ident = -1; - - ngx_add_timer(ctx->event, ctx->timeout); + if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) { + goto failed; } if (ngx_resolver_resend_empty(r)) { @@ -1117,6 +1083,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx) /* unlock addr mutex */ ctx->state = NGX_AGAIN; + ctx->async = 1; ctx->node = rn; return NGX_OK; @@ -3017,6 +2984,7 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) srv = cctx->srvs; ctx->count--; + ctx->async |= cctx->async; srv->ctx = NULL; srv->state = cctx->state; @@ -3027,25 +2995,15 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t)); if (addrs == NULL) { - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t)); if (sockaddr == NULL) { ngx_resolver_free(r, addrs); - ngx_resolve_name_done(cctx); - - ctx->state = NGX_ERROR; - ctx->valid = ngx_time() + (r->valid ? r->valid : 10); - - ctx->handler(ctx); - return; + srv->state = NGX_ERROR; + goto done; } for (i = 0; i < cctx->naddrs; i++) { @@ -3062,6 +3020,8 @@ ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx) srv->naddrs = cctx->naddrs; } +done: + ngx_resolve_name_done(cctx); if (ctx->count == 0) { @@ -4034,6 +3994,30 @@ done: } +static ngx_int_t +ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) +{ + if (ctx->event || ctx->timeout == 0) { + return NGX_OK; + } + + ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t)); + if (ctx->event == NULL) { + return NGX_ERROR; + } + + ctx->event->handler = ngx_resolver_timeout_handler; + ctx->event->data = ctx; + ctx->event->log = r->log; + ctx->event->cancelable = ctx->cancelable; + ctx->ident = -1; + + ngx_add_timer(ctx->event, ctx->timeout); + + return NGX_OK; +} + + static void ngx_resolver_timeout_handler(ngx_event_t *ev) { @@ -4247,10 +4231,21 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) ngx_resolver_addr_t *addrs; ngx_resolver_srv_name_t *srvs; + srvs = ctx->srvs; + nsrvs = ctx->nsrvs; + naddrs = 0; - for (i = 0; i < ctx->nsrvs; i++) { - naddrs += ctx->srvs[i].naddrs; + for (i = 0; i < nsrvs; i++) { + if (srvs[i].state == NGX_ERROR) { + ctx->state = NGX_ERROR; + ctx->valid = ngx_time() + (r->valid ? r->valid : 10); + + ctx->handler(ctx); + return; + } + + naddrs += srvs[i].naddrs; } if (naddrs == 0) { @@ -4270,9 +4265,6 @@ ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx) return; } - srvs = ctx->srvs; - nsrvs = ctx->nsrvs; - i = 0; n = 0; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h index a0d6fc3..0bd3921 100644 --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -218,7 +218,9 @@ struct ngx_resolver_ctx_s { void *data; ngx_msec_t timeout; - ngx_uint_t quick; /* unsigned quick:1; */ + unsigned quick:1; + unsigned async:1; + unsigned cancelable:1; ngx_uint_t recursion; ngx_event_t *event; }; diff --git a/src/core/ngx_rwlock.c b/src/core/ngx_rwlock.c index 905de78..ed2b0f8 100644 --- a/src/core/ngx_rwlock.c +++ b/src/core/ngx_rwlock.c @@ -94,7 +94,7 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) readers = *lock; if (readers == NGX_RWLOCK_WLOCK) { - *lock = 0; + (void) ngx_atomic_cmp_set(lock, NGX_RWLOCK_WLOCK, 0); return; } @@ -109,6 +109,15 @@ ngx_rwlock_unlock(ngx_atomic_t *lock) } +void +ngx_rwlock_downgrade(ngx_atomic_t *lock) +{ + if (*lock == NGX_RWLOCK_WLOCK) { + *lock = 1; + } +} + + #else #if (NGX_HTTP_UPSTREAM_ZONE || NGX_STREAM_UPSTREAM_ZONE) diff --git a/src/core/ngx_rwlock.h b/src/core/ngx_rwlock.h index 8b16eca..41b42aa 100644 --- a/src/core/ngx_rwlock.h +++ b/src/core/ngx_rwlock.h @@ -16,6 +16,7 @@ void ngx_rwlock_wlock(ngx_atomic_t *lock); void ngx_rwlock_rlock(ngx_atomic_t *lock); void ngx_rwlock_unlock(ngx_atomic_t *lock); +void ngx_rwlock_downgrade(ngx_atomic_t *lock); #endif /* _NGX_RWLOCK_H_INCLUDED_ */ diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c index 1d4ce2b..4023870 100644 --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -82,6 +82,19 @@ static ngx_uint_t ngx_slab_exact_size; static ngx_uint_t ngx_slab_exact_shift; +void +ngx_slab_sizes_init(void) +{ + ngx_uint_t n; + + ngx_slab_max_size = ngx_pagesize / 2; + ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); + for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { + /* void */ + } +} + + void ngx_slab_init(ngx_slab_pool_t *pool) { @@ -91,16 +104,6 @@ ngx_slab_init(ngx_slab_pool_t *pool) ngx_uint_t i, n, pages; ngx_slab_page_t *slots, *page; - /* STUB */ - if (ngx_slab_max_size == 0) { - ngx_slab_max_size = ngx_pagesize / 2; - ngx_slab_exact_size = ngx_pagesize / (8 * sizeof(uintptr_t)); - for (n = ngx_slab_exact_size; n >>= 1; ngx_slab_exact_shift++) { - /* void */ - } - } - /**/ - pool->min_size = (size_t) 1 << pool->min_shift; slots = ngx_slab_slots(pool); @@ -181,8 +184,8 @@ void * ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) { size_t s; - uintptr_t p, n, m, mask, *bitmap; - ngx_uint_t i, slot, shift, map; + uintptr_t p, m, mask, *bitmap; + ngx_uint_t i, n, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; if (size > ngx_slab_max_size) { @@ -226,7 +229,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap = (uintptr_t *) ngx_slab_page_addr(pool, page); - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); for (n = 0; n < map; n++) { @@ -239,7 +242,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) bitmap[n] |= m; - i = (n * sizeof(uintptr_t) * 8 + i) << shift; + i = (n * 8 * sizeof(uintptr_t) + i) << shift; p = (uintptr_t) bitmap + i; @@ -339,11 +342,17 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) } /* "n" elements for bitmap, plus one requested */ - bitmap[0] = ((uintptr_t) 2 << n) - 1; - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + for (i = 0; i < (n + 1) / (8 * sizeof(uintptr_t)); i++) { + bitmap[i] = NGX_SLAB_BUSY; + } - for (i = 1; i < map; i++) { + m = ((uintptr_t) 1 << ((n + 1) % (8 * sizeof(uintptr_t)))) - 1; + bitmap[i] = m; + + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); + + for (i = i + 1; i < map; i++) { bitmap[i] = 0; } @@ -369,7 +378,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size) slots[slot].next = page; - pool->stats[slot].total += sizeof(uintptr_t) * 8; + pool->stats[slot].total += 8 * sizeof(uintptr_t); p = ngx_slab_page_addr(pool, page); @@ -480,8 +489,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) } n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; - m = (uintptr_t) 1 << (n % (sizeof(uintptr_t) * 8)); - n /= sizeof(uintptr_t) * 8; + m = (uintptr_t) 1 << (n % (8 * sizeof(uintptr_t))); + n /= 8 * sizeof(uintptr_t); bitmap = (uintptr_t *) ((uintptr_t) p & ~((uintptr_t) ngx_pagesize - 1)); @@ -506,13 +515,16 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) n = 1; } - if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { + i = n / (8 * sizeof(uintptr_t)); + m = ((uintptr_t) 1 << (n % (8 * sizeof(uintptr_t)))) - 1; + + if (bitmap[i] & ~m) { goto done; } - map = (ngx_pagesize >> shift) / (sizeof(uintptr_t) * 8); + map = (ngx_pagesize >> shift) / (8 * sizeof(uintptr_t)); - for (i = 1; i < map; i++) { + for (i = i + 1; i < map; i++) { if (bitmap[i]) { goto done; } @@ -558,7 +570,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p) ngx_slab_free_pages(pool, page, 1); - pool->stats[slot].total -= sizeof(uintptr_t) * 8; + pool->stats[slot].total -= 8 * sizeof(uintptr_t); goto done; } diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h index eff893c..d1876bb 100644 --- a/src/core/ngx_slab.h +++ b/src/core/ngx_slab.h @@ -59,6 +59,7 @@ typedef struct { } ngx_slab_pool_t; +void ngx_slab_sizes_init(void); void ngx_slab_init(ngx_slab_pool_t *pool); void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size); void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c index 7526f60..de10a06 100644 --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -178,7 +178,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) slen = (size_t) -1; while (*fmt >= '0' && *fmt <= '9') { - width = width * 10 + *fmt++ - '0'; + width = width * 10 + (*fmt++ - '0'); } @@ -211,7 +211,7 @@ ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) fmt++; while (*fmt >= '0' && *fmt <= '9') { - frac_width = frac_width * 10 + *fmt++ - '0'; + frac_width = frac_width * 10 + (*fmt++ - '0'); } break; @@ -1655,7 +1655,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) state = sw_usual; if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (type & NGX_UNESCAPE_REDIRECT) { if (ch > '%' && ch < 0x7f) { @@ -1675,7 +1675,7 @@ ngx_unescape_uri(u_char **dst, u_char **src, size_t size, ngx_uint_t type) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (type & NGX_UNESCAPE_URI) { if (ch == '?') { diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c index 2c4e114..07646b6 100644 --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -3128,7 +3128,7 @@ ngx_ssl_session_ticket_keys(ngx_conf_t *cf, ngx_ssl_t *ssl, ngx_array_t *paths) { if (paths) { ngx_log_error(NGX_LOG_WARN, ssl->log, 0, - "\"ssl_session_ticket_keys\" ignored, not supported"); + "\"ssl_session_ticket_key\" ignored, not supported"); } return NGX_OK; diff --git a/src/event/ngx_event_openssl_stapling.c b/src/event/ngx_event_openssl_stapling.c index d332c11..0bea5e7 100644 --- a/src/event/ngx_event_openssl_stapling.c +++ b/src/event/ngx_event_openssl_stapling.c @@ -1486,7 +1486,7 @@ ngx_ssl_ocsp_parse_status_line(ngx_ssl_ocsp_ctx_t *ctx) return NGX_ERROR; } - ctx->code = ctx->code * 10 + ch - '0'; + ctx->code = ctx->code * 10 + (ch - '0'); if (++ctx->count == 3) { state = sw_space_after_status; diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c index 2fad0e5..e546f0d 100644 --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -123,6 +123,8 @@ ngx_http_addition_header_filter(ngx_http_request_t *r) ngx_http_clear_accept_ranges(r); ngx_http_weak_etag(r); + r->preserve_body = 1; + return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_browser_module.c b/src/http/modules/ngx_http_browser_module.c index 80da0d8..f774254 100644 --- a/src/http/modules/ngx_http_browser_module.c +++ b/src/http/modules/ngx_http_browser_module.c @@ -37,13 +37,6 @@ typedef struct { } ngx_http_modern_browser_t; -typedef struct { - ngx_str_t name; - ngx_http_get_variable_pt handler; - uintptr_t data; -} ngx_http_browser_variable_t; - - typedef struct { ngx_array_t *modern_browsers; ngx_array_t *ancient_browsers; @@ -63,7 +56,7 @@ static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r, static ngx_uint_t ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf); -static ngx_int_t ngx_http_browser_add_variable(ngx_conf_t *cf); +static ngx_int_t ngx_http_browser_add_variables(ngx_conf_t *cf); static void *ngx_http_browser_create_conf(ngx_conf_t *cf); static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -114,7 +107,7 @@ static ngx_command_t ngx_http_browser_commands[] = { static ngx_http_module_t ngx_http_browser_module_ctx = { - ngx_http_browser_add_variable, /* preconfiguration */ + ngx_http_browser_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -218,13 +211,18 @@ static ngx_http_modern_browser_mask_t ngx_http_modern_browser_masks[] = { }; -static ngx_http_browser_variable_t ngx_http_browsers[] = { - { ngx_string("msie"), ngx_http_msie_variable, 0 }, - { ngx_string("modern_browser"), ngx_http_browser_variable, - NGX_HTTP_MODERN_BROWSER }, - { ngx_string("ancient_browser"), ngx_http_browser_variable, - NGX_HTTP_ANCIENT_BROWSER }, - { ngx_null_string, NULL, 0 } +static ngx_http_variable_t ngx_http_browser_vars[] = { + + { ngx_string("msie"), NULL, ngx_http_msie_variable, + 0, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("modern_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_MODERN_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + { ngx_string("ancient_browser"), NULL, ngx_http_browser_variable, + NGX_HTTP_ANCIENT_BROWSER, NGX_HTTP_VAR_CHANGEABLE, 0 }, + + ngx_http_null_variable }; @@ -397,20 +395,19 @@ ngx_http_msie_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, static ngx_int_t -ngx_http_browser_add_variable(ngx_conf_t *cf) +ngx_http_browser_add_variables(ngx_conf_t *cf) { - ngx_http_browser_variable_t *var; - ngx_http_variable_t *v; + ngx_http_variable_t *var, *v; - for (var = ngx_http_browsers; var->name.len; var++) { + for (v = ngx_http_browser_vars; v->name.len; v++) { - v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGEABLE); - if (v == NULL) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { return NGX_ERROR; } - v->get_handler = var->handler; - v->data = var->data; + var->get_handler = v->get_handler; + var->data = v->data; } return NGX_OK; diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c index ac2e3e8..4d6fd3e 100644 --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -17,6 +17,8 @@ typedef struct { static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf); +static ngx_chain_t *ngx_http_chunked_create_trailers(ngx_http_request_t *r, + ngx_http_chunked_filter_ctx_t *ctx); static ngx_http_module_t ngx_http_chunked_filter_module_ctx = { @@ -69,27 +71,29 @@ ngx_http_chunked_header_filter(ngx_http_request_t *r) return ngx_http_next_header_filter(r); } - if (r->headers_out.content_length_n == -1) { - if (r->http_version < NGX_HTTP_VERSION_11) { - r->keepalive = 0; + if (r->headers_out.content_length_n == -1 + || r->expect_trailers) + { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - } else { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->chunked_transfer_encoding) { - r->chunked = 1; - - ctx = ngx_pcalloc(r->pool, - sizeof(ngx_http_chunked_filter_ctx_t)); - if (ctx == NULL) { - return NGX_ERROR; - } - - ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); - - } else { - r->keepalive = 0; + if (r->http_version >= NGX_HTTP_VERSION_11 + && clcf->chunked_transfer_encoding) + { + if (r->expect_trailers) { + ngx_http_clear_content_length(r); } + + r->chunked = 1; + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_chunked_filter_module); + + } else if (r->headers_out.content_length_n == -1) { + r->keepalive = 0; } } @@ -179,26 +183,17 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } if (cl->buf->last_buf) { - tl = ngx_chain_get_free_buf(r->pool, &ctx->free); + tl = ngx_http_chunked_create_trailers(r, ctx); if (tl == NULL) { return NGX_ERROR; } - b = tl->buf; - - b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; - b->temporary = 0; - b->memory = 1; - b->last_buf = 1; - b->pos = (u_char *) CRLF "0" CRLF CRLF; - b->last = b->pos + 7; - cl->buf->last_buf = 0; *ll = tl; if (size == 0) { - b->pos += 2; + tl->buf->pos += 2; } } else if (size > 0) { @@ -230,6 +225,109 @@ ngx_http_chunked_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } +static ngx_chain_t * +ngx_http_chunked_create_trailers(ngx_http_request_t *r, + ngx_http_chunked_filter_ctx_t *ctx) +{ + size_t len; + ngx_buf_t *b; + ngx_uint_t i; + ngx_chain_t *cl; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + len = 0; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + len += header[i].key.len + sizeof(": ") - 1 + + header[i].value.len + sizeof(CRLF) - 1; + } + + cl = ngx_chain_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NULL; + } + + b = cl->buf; + + b->tag = (ngx_buf_tag_t) &ngx_http_chunked_filter_module; + b->temporary = 0; + b->memory = 1; + b->last_buf = 1; + + if (len == 0) { + b->pos = (u_char *) CRLF "0" CRLF CRLF; + b->last = b->pos + sizeof(CRLF "0" CRLF CRLF) - 1; + return cl; + } + + len += sizeof(CRLF "0" CRLF CRLF) - 1; + + b->pos = ngx_palloc(r->pool, len); + if (b->pos == NULL) { + return NULL; + } + + b->last = b->pos; + + *b->last++ = CR; *b->last++ = LF; + *b->last++ = '0'; + *b->last++ = CR; *b->last++ = LF; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http trailer: \"%V: %V\"", + &header[i].key, &header[i].value); + + b->last = ngx_copy(b->last, header[i].key.data, header[i].key.len); + *b->last++ = ':'; *b->last++ = ' '; + + b->last = ngx_copy(b->last, header[i].value.data, header[i].value.len); + *b->last++ = CR; *b->last++ = LF; + } + + *b->last++ = CR; *b->last++ = LF; + + return cl; +} + + static ngx_int_t ngx_http_chunked_filter_init(ngx_conf_t *cf) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c index 741e577..ea16eca 100644 --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -631,7 +631,7 @@ static ngx_http_variable_t ngx_http_fastcgi_vars[] = { ngx_http_fastcgi_path_info_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c index 8e151aa..5ea4f5f 100644 --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -232,7 +232,7 @@ static ngx_http_variable_t ngx_http_geoip_vars[] = { ngx_http_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index 287fd36..73b6d89 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -1084,10 +1084,6 @@ ngx_http_gzip_ratio_variable(ngx_http_request_t *r, ngx_uint_t zint, zfrac; ngx_http_gzip_ctx_t *ctx; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); if (ctx == NULL || ctx->zout == 0) { @@ -1095,6 +1091,10 @@ ngx_http_gzip_ratio_variable(ngx_http_request_t *r, return NGX_OK; } + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = ngx_pnalloc(r->pool, NGX_INT32_LEN + 3); if (v->data == NULL) { return NGX_ERROR; diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c index 94dc51e..e5f1eb5 100644 --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -48,6 +48,7 @@ typedef struct { time_t expires_time; ngx_http_complex_value_t *expires_value; ngx_array_t *headers; + ngx_array_t *trailers; } ngx_http_headers_conf_t; @@ -98,15 +99,23 @@ static ngx_command_t ngx_http_headers_filter_commands[] = { ngx_http_headers_expires, NGX_HTTP_LOC_CONF_OFFSET, 0, - NULL}, + NULL }, { ngx_string("add_header"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE23, ngx_http_headers_add, NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL}, + offsetof(ngx_http_headers_conf_t, headers), + NULL }, + + { ngx_string("add_trailer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_headers_add, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_headers_conf_t, trailers), + NULL }, ngx_null_command }; @@ -144,6 +153,7 @@ ngx_module_t ngx_http_headers_filter_module = { static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; static ngx_int_t @@ -154,10 +164,15 @@ ngx_http_headers_filter(ngx_http_request_t *r) ngx_http_header_val_t *h; ngx_http_headers_conf_t *conf; + if (r != r->main) { + return ngx_http_next_header_filter(r); + } + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); - if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL) - || r != r->main) + if (conf->expires == NGX_HTTP_EXPIRES_OFF + && conf->headers == NULL + && conf->trailers == NULL) { return ngx_http_next_header_filter(r); } @@ -206,10 +221,100 @@ ngx_http_headers_filter(ngx_http_request_t *r) } } + if (conf->trailers) { + h = conf->trailers->elts; + for (i = 0; i < conf->trailers->nelts; i++) { + + if (!safe_status && !h[i].always) { + continue; + } + + r->expect_trailers = 1; + break; + } + } + return ngx_http_next_header_filter(r); } +static ngx_int_t +ngx_http_trailers_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_str_t value; + ngx_uint_t i, safe_status; + ngx_chain_t *cl; + ngx_table_elt_t *t; + ngx_http_header_val_t *h; + ngx_http_headers_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_headers_filter_module); + + if (in == NULL + || conf->trailers == NULL + || !r->expect_trailers + || r->header_only) + { + return ngx_http_next_body_filter(r, in); + } + + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf) { + break; + } + } + + if (cl == NULL) { + return ngx_http_next_body_filter(r, in); + } + + switch (r->headers_out.status) { + + case NGX_HTTP_OK: + case NGX_HTTP_CREATED: + case NGX_HTTP_NO_CONTENT: + case NGX_HTTP_PARTIAL_CONTENT: + case NGX_HTTP_MOVED_PERMANENTLY: + case NGX_HTTP_MOVED_TEMPORARILY: + case NGX_HTTP_SEE_OTHER: + case NGX_HTTP_NOT_MODIFIED: + case NGX_HTTP_TEMPORARY_REDIRECT: + case NGX_HTTP_PERMANENT_REDIRECT: + safe_status = 1; + break; + + default: + safe_status = 0; + break; + } + + h = conf->trailers->elts; + for (i = 0; i < conf->trailers->nelts; i++) { + + if (!safe_status && !h[i].always) { + continue; + } + + if (ngx_http_complex_value(r, &h[i].value, &value) != NGX_OK) { + return NGX_ERROR; + } + + if (value.len) { + t = ngx_list_push(&r->headers_out.trailers); + if (t == NULL) { + return NGX_ERROR; + } + + t->key = h[i].key; + t->value = value; + t->hash = 1; + } + } + + return ngx_http_next_body_filter(r, in); +} + + static ngx_int_t ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf) { @@ -557,6 +662,7 @@ ngx_http_headers_create_conf(ngx_conf_t *cf) * set by ngx_pcalloc(): * * conf->headers = NULL; + * conf->trailers = NULL; * conf->expires_time = 0; * conf->expires_value = NULL; */ @@ -587,6 +693,10 @@ ngx_http_headers_merge_conf(ngx_conf_t *cf, void *parent, void *child) conf->headers = prev->headers; } + if (conf->trailers == NULL) { + conf->trailers = prev->trailers; + } + return NGX_CONF_OK; } @@ -597,6 +707,9 @@ ngx_http_headers_filter_init(ngx_conf_t *cf) ngx_http_next_header_filter = ngx_http_top_header_filter; ngx_http_top_header_filter = ngx_http_headers_filter; + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_trailers_filter; + return NGX_OK; } @@ -674,42 +787,49 @@ ngx_http_headers_add(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_headers_conf_t *hcf = conf; - ngx_str_t *value; - ngx_uint_t i; - ngx_http_header_val_t *hv; - ngx_http_set_header_t *set; - ngx_http_compile_complex_value_t ccv; + ngx_str_t *value; + ngx_uint_t i; + ngx_array_t **headers; + ngx_http_header_val_t *hv; + ngx_http_set_header_t *set; + ngx_http_compile_complex_value_t ccv; value = cf->args->elts; - if (hcf->headers == NULL) { - hcf->headers = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_header_val_t)); - if (hcf->headers == NULL) { + headers = (ngx_array_t **) ((char *) hcf + cmd->offset); + + if (*headers == NULL) { + *headers = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_header_val_t)); + if (*headers == NULL) { return NGX_CONF_ERROR; } } - hv = ngx_array_push(hcf->headers); + hv = ngx_array_push(*headers); if (hv == NULL) { return NGX_CONF_ERROR; } hv->key = value[1]; - hv->handler = ngx_http_add_header; + hv->handler = NULL; hv->offset = 0; hv->always = 0; - set = ngx_http_set_headers; - for (i = 0; set[i].name.len; i++) { - if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) { - continue; + if (headers == &hcf->headers) { + hv->handler = ngx_http_add_header; + + set = ngx_http_set_headers; + for (i = 0; set[i].name.len; i++) { + if (ngx_strcasecmp(value[1].data, set[i].name.data) != 0) { + continue; + } + + hv->offset = set[i].offset; + hv->handler = set[i].handler; + + break; } - - hv->offset = set[i].offset; - hv->handler = set[i].handler; - - break; } if (value[2].len == 0) { diff --git a/src/http/modules/ngx_http_mirror_module.c b/src/http/modules/ngx_http_mirror_module.c new file mode 100644 index 0000000..787adb3 --- /dev/null +++ b/src/http/modules/ngx_http_mirror_module.c @@ -0,0 +1,264 @@ + +/* + * Copyright (C) Roman Arutyunyan + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *mirror; + ngx_flag_t request_body; +} ngx_http_mirror_loc_conf_t; + + +typedef struct { + ngx_int_t status; +} ngx_http_mirror_ctx_t; + + +static ngx_int_t ngx_http_mirror_handler(ngx_http_request_t *r); +static void ngx_http_mirror_body_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_mirror_handler_internal(ngx_http_request_t *r); +static void *ngx_http_mirror_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static ngx_int_t ngx_http_mirror_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_mirror_commands[] = { + + { ngx_string("mirror"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_mirror, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("mirror_request_body"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_mirror_loc_conf_t, request_body), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_mirror_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_mirror_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_mirror_create_loc_conf, /* create location configuration */ + ngx_http_mirror_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_mirror_module = { + NGX_MODULE_V1, + &ngx_http_mirror_module_ctx, /* module context */ + ngx_http_mirror_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_mirror_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_mirror_ctx_t *ctx; + ngx_http_mirror_loc_conf_t *mlcf; + + if (r != r->main) { + return NGX_DECLINED; + } + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + if (mlcf->mirror == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "mirror handler"); + + if (mlcf->request_body) { + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + if (ctx) { + return ctx->status; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_mirror_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->status = NGX_DONE; + + ngx_http_set_ctx(r, ctx, ngx_http_mirror_module); + + rc = ngx_http_read_client_request_body(r, ngx_http_mirror_body_handler); + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + return ngx_http_mirror_handler_internal(r); +} + + +static void +ngx_http_mirror_body_handler(ngx_http_request_t *r) +{ + ngx_http_mirror_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_mirror_module); + + ctx->status = ngx_http_mirror_handler_internal(r); + + r->preserve_body = 1; + + r->write_event_handler = ngx_http_core_run_phases; + ngx_http_core_run_phases(r); +} + + +static ngx_int_t +ngx_http_mirror_handler_internal(ngx_http_request_t *r) +{ + ngx_str_t *name; + ngx_uint_t i; + ngx_http_request_t *sr; + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_http_get_module_loc_conf(r, ngx_http_mirror_module); + + name = mlcf->mirror->elts; + + for (i = 0; i < mlcf->mirror->nelts; i++) { + if (ngx_http_subrequest(r, &name[i], &r->args, &sr, NULL, + NGX_HTTP_SUBREQUEST_BACKGROUND) + != NGX_OK) + { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + sr->header_only = 1; + sr->method = r->method; + sr->method_name = r->method_name; + } + + return NGX_DECLINED; +} + + +static void * +ngx_http_mirror_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_mirror_loc_conf_t *mlcf; + + mlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_mirror_loc_conf_t)); + if (mlcf == NULL) { + return NULL; + } + + mlcf->mirror = NGX_CONF_UNSET_PTR; + mlcf->request_body = NGX_CONF_UNSET; + + return mlcf; +} + + +static char * +ngx_http_mirror_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_mirror_loc_conf_t *prev = parent; + ngx_http_mirror_loc_conf_t *conf = child; + + ngx_conf_merge_ptr_value(conf->mirror, prev->mirror, NULL); + ngx_conf_merge_value(conf->request_body, prev->request_body, 1); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_mirror(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_mirror_loc_conf_t *mlcf = conf; + + ngx_str_t *value, *s; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + if (mlcf->mirror != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + mlcf->mirror = NULL; + return NGX_CONF_OK; + } + + if (mlcf->mirror == NULL) { + return "is duplicate"; + } + + if (mlcf->mirror == NGX_CONF_UNSET_PTR) { + mlcf->mirror = ngx_array_create(cf->pool, 4, sizeof(ngx_str_t)); + if (mlcf->mirror == NULL) { + return NGX_CONF_ERROR; + } + } + + s = ngx_array_push(mlcf->mirror); + if (s == NULL) { + return NGX_CONF_ERROR; + } + + *s = value[1]; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_mirror_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_mirror_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c index 839d479..b42839c 100644 --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -829,7 +829,7 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = { ngx_http_proxy_internal_chunked_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_NOHASH, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -1143,7 +1143,8 @@ ngx_http_proxy_create_key(ngx_http_request_t *r) static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r) { - size_t len, uri_len, loc_len, body_len; + size_t len, uri_len, loc_len, body_len, + key_len, val_len; uintptr_t escape; ngx_buf_t *b; ngx_str_t method; @@ -1258,11 +1259,20 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.flushed = 1; while (*(uintptr_t *) le.ip) { - while (*(uintptr_t *) le.ip) { + + lcode = *(ngx_http_script_len_code_pt *) le.ip; + key_len = lcode(&le); + + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { lcode = *(ngx_http_script_len_code_pt *) le.ip; - len += lcode(&le); } le.ip += sizeof(uintptr_t); + + if (val_len == 0) { + continue; + } + + len += key_len + sizeof(": ") - 1 + val_len + sizeof(CRLF) - 1; } @@ -1362,30 +1372,41 @@ ngx_http_proxy_create_request(ngx_http_request_t *r) le.ip = headers->lengths->elts; while (*(uintptr_t *) le.ip) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; - /* skip the header line name length */ + lcode = *(ngx_http_script_len_code_pt *) le.ip; (void) lcode(&le); - if (*(ngx_http_script_len_code_pt *) le.ip) { + for (val_len = 0; *(uintptr_t *) le.ip; val_len += lcode(&le)) { + lcode = *(ngx_http_script_len_code_pt *) le.ip; + } + le.ip += sizeof(uintptr_t); - for (len = 0; *(uintptr_t *) le.ip; len += lcode(&le)) { - lcode = *(ngx_http_script_len_code_pt *) le.ip; + if (val_len == 0) { + e.skip = 1; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); } + e.ip += sizeof(uintptr_t); - e.skip = (len == sizeof(CRLF) - 1) ? 1 : 0; - - } else { e.skip = 0; + + continue; } - le.ip += sizeof(uintptr_t); + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + + *e.pos++ = ':'; *e.pos++ = ' '; while (*(uintptr_t *) e.ip) { code = *(ngx_http_script_code_pt *) e.ip; code((ngx_http_script_engine_t *) &e); } e.ip += sizeof(uintptr_t); + + *e.pos++ = CR; *e.pos++ = LF; } b->last = e.pos; @@ -3498,108 +3519,40 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf, continue; } - if (ngx_http_script_variables_count(&src[i].value) == 0) { - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } + copy = ngx_array_push_n(headers->lengths, + sizeof(ngx_http_script_copy_code_t)); + if (copy == NULL) { + return NGX_ERROR; + } - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code; + copy->len = src[i].key.len; + size = (sizeof(ngx_http_script_copy_code_t) + + src[i].key.len + sizeof(uintptr_t) - 1) + & ~(sizeof(uintptr_t) - 1); - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1 - + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); + copy = ngx_array_push_n(headers->values, size); + if (copy == NULL) { + return NGX_ERROR; + } - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } + copy->code = ngx_http_script_copy_code; + copy->len = src[i].key.len; - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1 - + src[i].value.len + sizeof(CRLF) - 1; + p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memcpy(p, src[i].key.data, src[i].key.len); - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p++ = ' '; - p = ngx_cpymem(p, src[i].value.data, src[i].value.len); - *p++ = CR; *p = LF; + sc.cf = cf; + sc.source = &src[i].value; + sc.flushes = &headers->flushes; + sc.lengths = &headers->lengths; + sc.values = &headers->values; - } else { - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = src[i].key.len + sizeof(": ") - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + src[i].key.len + sizeof(": ") - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = src[i].key.len + sizeof(": ") - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - p = ngx_cpymem(p, src[i].key.data, src[i].key.len); - *p++ = ':'; *p = ' '; - - - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &src[i].value; - sc.flushes = &headers->flushes; - sc.lengths = &headers->lengths; - sc.values = &headers->values; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_ERROR; - } - - - copy = ngx_array_push_n(headers->lengths, - sizeof(ngx_http_script_copy_code_t)); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = (ngx_http_script_code_pt) - ngx_http_script_copy_len_code; - copy->len = sizeof(CRLF) - 1; - - - size = (sizeof(ngx_http_script_copy_code_t) - + sizeof(CRLF) - 1 + sizeof(uintptr_t) - 1) - & ~(sizeof(uintptr_t) - 1); - - copy = ngx_array_push_n(headers->values, size); - if (copy == NULL) { - return NGX_ERROR; - } - - copy->code = ngx_http_script_copy_code; - copy->len = sizeof(CRLF) - 1; - - p = (u_char *) copy + sizeof(ngx_http_script_copy_code_t); - *p++ = CR; *p = LF; + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_ERROR; } code = ngx_array_push_n(headers->lengths, sizeof(uintptr_t)); diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c index 8ffca82..6256b13 100644 --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -315,7 +315,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -345,7 +345,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, return NGX_HTTP_RANGE_NOT_SATISFIABLE; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -355,7 +355,7 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, } if (suffix) { - start = content_length - end; + start = (end < content_length) ? content_length - end : 0; end = content_length - 1; } @@ -377,11 +377,18 @@ ngx_http_range_parse(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, range->start = start; range->end = end; + if (size > NGX_MAX_OFF_T_VALUE - (end - start)) { + return NGX_HTTP_RANGE_NOT_SATISFIABLE; + } + size += end - start; if (ranges-- == 0) { return NGX_DECLINED; } + + } else if (start == 0) { + return NGX_DECLINED; } if (*p++ != ',') { diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c index e1839e6..7d3f2a9 100644 --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -122,7 +122,7 @@ static ngx_http_variable_t ngx_http_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_http_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c index 3f0f78e..599dd3a 100644 --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -32,6 +32,7 @@ typedef struct { } ngx_http_referer_conf_t; +static ngx_int_t ngx_http_referer_add_variables(ngx_conf_t *cf); static void * ngx_http_referer_create_conf(ngx_conf_t *cf); static char * ngx_http_referer_merge_conf(ngx_conf_t *cf, void *parent, void *child); @@ -77,7 +78,7 @@ static ngx_command_t ngx_http_referer_commands[] = { static ngx_http_module_t ngx_http_referer_module_ctx = { - NULL, /* preconfiguration */ + ngx_http_referer_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ NULL, /* create main configuration */ @@ -107,6 +108,9 @@ ngx_module_t ngx_http_referer_module = { }; +static ngx_str_t ngx_http_invalid_referer_name = ngx_string("invalid_referer"); + + static ngx_int_t ngx_http_referer_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -263,6 +267,23 @@ valid: } +static ngx_int_t +ngx_http_referer_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var; + + var = ngx_http_add_variable(cf, &ngx_http_invalid_referer_name, + NGX_HTTP_VAR_CHANGEABLE); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = ngx_http_referer_variable; + + return NGX_OK; +} + + static void * ngx_http_referer_create_conf(ngx_conf_t *cf) { @@ -452,19 +473,9 @@ ngx_http_valid_referers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_referer_conf_t *rlcf = conf; - u_char *p; - ngx_str_t *value, uri, name; - ngx_uint_t i; - ngx_http_variable_t *var; - - ngx_str_set(&name, "invalid_referer"); - - var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); - if (var == NULL) { - return NGX_CONF_ERROR; - } - - var->get_handler = ngx_http_referer_variable; + u_char *p; + ngx_str_t *value, uri; + ngx_uint_t i; if (rlcf->keys == NULL) { rlcf->keys = ngx_pcalloc(cf->temp_pool, sizeof(ngx_hash_keys_arrays_t)); diff --git a/src/http/modules/ngx_http_slice_filter_module.c b/src/http/modules/ngx_http_slice_filter_module.c index 7758342..c1edbca 100644 --- a/src/http/modules/ngx_http_slice_filter_module.c +++ b/src/http/modules/ngx_http_slice_filter_module.c @@ -190,6 +190,8 @@ ngx_http_slice_header_filter(ngx_http_request_t *r) return rc; } + r->preserve_body = 1; + if (r->headers_out.status == NGX_HTTP_PARTIAL_CONTENT) { if (ctx->start + (off_t) slcf->size <= r->headers_out.content_offset) { ctx->start = slcf->size @@ -317,7 +319,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } while (*p == ' ') { p++; } @@ -337,7 +339,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - end = end * 10 + *p++ - '0'; + end = end * 10 + (*p++ - '0'); } end++; @@ -362,7 +364,7 @@ ngx_http_slice_parse_content_range(ngx_http_request_t *r, return NGX_ERROR; } - complete_length = complete_length * 10 + *p++ - '0'; + complete_length = complete_length * 10 + (*p++ - '0'); } } else { @@ -479,7 +481,7 @@ ngx_http_slice_get_start(ngx_http_request_t *r) return 0; } - start = start * 10 + *p++ - '0'; + start = start * 10 + (*p++ - '0'); } return start; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index 6fb1fbe..e29e173 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -321,7 +321,7 @@ static ngx_http_variable_t ngx_http_ssi_vars[] = { { ngx_string("date_gmt"), NULL, ngx_http_ssi_date_gmt_local_variable, 1, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -370,6 +370,8 @@ ngx_http_ssi_header_filter(ngx_http_request_t *r) ngx_http_clear_content_length(r); ngx_http_clear_accept_ranges(r); + r->preserve_body = 1; + if (!slcf->last_modified) { ngx_http_clear_last_modified(r); ngx_http_clear_etag(r); @@ -2388,7 +2390,7 @@ ngx_http_ssi_config(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ctx->timefmt.len = value->len; ctx->timefmt.data = ngx_pnalloc(r->pool, value->len + 1); if (ctx->timefmt.data == NULL) { - return NGX_HTTP_SSI_ERROR; + return NGX_ERROR; } ngx_cpystrn(ctx->timefmt.data, value->data, value->len + 1); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c index b466e5d..4370275 100644 --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -329,7 +329,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_http_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_HTTP_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_stub_status_module.c b/src/http/modules/ngx_http_stub_status_module.c index 61199f2..9bdf881 100644 --- a/src/http/modules/ngx_http_stub_status_module.c +++ b/src/http/modules/ngx_http_stub_status_module.c @@ -76,7 +76,7 @@ static ngx_http_variable_t ngx_http_stub_status_vars[] = { { ngx_string("connections_waiting"), NULL, ngx_http_stub_status_variable, 3, NGX_HTTP_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/http/modules/ngx_http_try_files_module.c b/src/http/modules/ngx_http_try_files_module.c new file mode 100644 index 0000000..ce783a2 --- /dev/null +++ b/src/http/modules/ngx_http_try_files_module.c @@ -0,0 +1,404 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#include +#include +#include + + +typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; + ngx_str_t name; + + unsigned code:10; + unsigned test_dir:1; +} ngx_http_try_file_t; + + +typedef struct { + ngx_http_try_file_t *try_files; +} ngx_http_try_files_loc_conf_t; + + +static ngx_int_t ngx_http_try_files_handler(ngx_http_request_t *r); +static char *ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static void *ngx_http_try_files_create_loc_conf(ngx_conf_t *cf); +static ngx_int_t ngx_http_try_files_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_try_files_commands[] = { + + { ngx_string("try_files"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, + ngx_http_try_files, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_try_files_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_try_files_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_try_files_create_loc_conf, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_try_files_module = { + NGX_MODULE_V1, + &ngx_http_try_files_module_ctx, /* module context */ + ngx_http_try_files_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_try_files_handler(ngx_http_request_t *r) +{ + size_t len, root, alias, reserve, allocated; + u_char *p, *name; + ngx_str_t path, args; + ngx_uint_t test_dir; + ngx_http_try_file_t *tf; + ngx_open_file_info_t of; + ngx_http_script_code_pt code; + ngx_http_script_engine_t e; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_len_code_pt lcode; + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_http_get_module_loc_conf(r, ngx_http_try_files_module); + + if (tlcf->try_files == NULL) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try files handler"); + + allocated = 0; + root = 0; + name = NULL; + /* suppress MSVC warning */ + path.data = NULL; + + tf = tlcf->try_files; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + alias = clcf->alias; + + for ( ;; ) { + + if (tf->lengths) { + ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); + + e.ip = tf->lengths->elts; + e.request = r; + + /* 1 is for terminating '\0' as in static names */ + len = 1; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + } else { + len = tf->name.len; + } + + if (!alias) { + reserve = len > r->uri.len ? len - r->uri.len : 0; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + reserve = len; + + } else { + reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; + } + + if (reserve > allocated || !allocated) { + + /* 16 bytes are preallocation */ + allocated = reserve + 16; + + if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + name = path.data + root; + } + + if (tf->values == NULL) { + + /* tf->name.len includes the terminating '\0' */ + + ngx_memcpy(name, tf->name.data, tf->name.len); + + path.len = (name + tf->name.len - 1) - path.data; + + } else { + e.ip = tf->values->elts; + e.pos = name; + e.flushed = 1; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_script_code_pt *) e.ip; + code((ngx_http_script_engine_t *) &e); + } + + path.len = e.pos - path.data; + + *e.pos = '\0'; + + if (alias && alias != NGX_MAX_SIZE_T_VALUE + && ngx_strncmp(name, r->uri.data, alias) == 0) + { + ngx_memmove(name, name + alias, len - alias); + path.len -= alias; + } + } + + test_dir = tf->test_dir; + + tf++; + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "trying to use %s: \"%s\" \"%s\"", + test_dir ? "dir" : "file", name, path.data); + + if (tf->lengths == NULL && tf->name.len == 0) { + + if (tf->code) { + return tf->code; + } + + path.len -= root; + path.data += root; + + if (path.data[0] == '@') { + (void) ngx_http_named_location(r, &path); + + } else { + ngx_http_split_args(r, &path, &args); + + (void) ngx_http_internal_redirect(r, &path, &args); + } + + ngx_http_finalize_request(r, NGX_DONE); + return NGX_DONE; + } + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.read_ahead = clcf->read_ahead; + of.directio = clcf->directio; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.test_only = 1; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK) + { + if (of.err == 0) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (of.err != NGX_ENOENT + && of.err != NGX_ENOTDIR + && of.err != NGX_ENAMETOOLONG) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, + "%s \"%s\" failed", of.failed, path.data); + } + + continue; + } + + if (of.is_dir != test_dir) { + continue; + } + + path.len -= root; + path.data += root; + + if (!alias) { + r->uri = path; + + } else if (alias == NGX_MAX_SIZE_T_VALUE) { + if (!test_dir) { + r->uri = path; + r->add_uri_to_alias = 1; + } + + } else { + name = r->uri.data; + + r->uri.len = alias + path.len; + r->uri.data = ngx_pnalloc(r->pool, r->uri.len); + if (r->uri.data == NULL) { + r->uri.len = 0; + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_copy(r->uri.data, name, alias); + ngx_memcpy(p, path.data, path.len); + } + + ngx_http_set_exten(r); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "try file uri: \"%V\"", &r->uri); + + return NGX_DECLINED; + } + + /* not reached */ +} + + +static char * +ngx_http_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_try_files_loc_conf_t *tlcf = conf; + + ngx_str_t *value; + ngx_int_t code; + ngx_uint_t i, n; + ngx_http_try_file_t *tf; + ngx_http_script_compile_t sc; + + if (tlcf->try_files) { + return "is duplicate"; + } + + tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); + if (tf == NULL) { + return NGX_CONF_ERROR; + } + + tlcf->try_files = tf; + + value = cf->args->elts; + + for (i = 0; i < cf->args->nelts - 1; i++) { + + tf[i].name = value[i + 1]; + + if (tf[i].name.len > 0 + && tf[i].name.data[tf[i].name.len - 1] == '/' + && i + 2 < cf->args->nelts) + { + tf[i].test_dir = 1; + tf[i].name.len--; + tf[i].name.data[tf[i].name.len] = '\0'; + } + + n = ngx_http_script_variables_count(&tf[i].name); + + if (n) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &tf[i].name; + sc.lengths = &tf[i].lengths; + sc.values = &tf[i].values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + /* add trailing '\0' to length */ + tf[i].name.len++; + } + } + + if (tf[i - 1].name.data[0] == '=') { + + code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); + + if (code == NGX_ERROR || code > 999) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid code \"%*s\"", + tf[i - 1].name.len - 1, tf[i - 1].name.data); + return NGX_CONF_ERROR; + } + + tf[i].code = code; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_try_files_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_try_files_loc_conf_t *tlcf; + + tlcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_try_files_loc_conf_t)); + if (tlcf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * tlcf->try_files = NULL; + */ + + return tlcf; +} + + +static ngx_int_t +ngx_http_try_files_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_try_files_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_upstream_zone_module.c b/src/http/modules/ngx_http_upstream_zone_module.c index 7e5bd74..d340b48 100644 --- a/src/http/modules/ngx_http_upstream_zone_module.c +++ b/src/http/modules/ngx_http_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_http_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_http_upstream_rr_peers_t *ngx_http_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf); +static ngx_http_upstream_rr_peer_t *ngx_http_upstream_zone_copy_peer( + ngx_http_upstream_rr_peers_t *peers, ngx_http_upstream_rr_peer_t *src); static ngx_command_t ngx_http_upstream_zone_commands[] = { @@ -185,6 +187,7 @@ static ngx_http_upstream_rr_peers_t * ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_http_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_http_upstream_rr_peer_t *peer, **peerp; ngx_http_upstream_rr_peers_t *peers, *backup; @@ -195,18 +198,30 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_http_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -221,18 +236,17 @@ ngx_http_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_http_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_http_upstream_rr_peer_t)); + peer = ngx_http_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_http_upstream_rr_peer_t)); - *peerp = peer; } @@ -244,3 +258,68 @@ done: return peers; } + + +static ngx_http_upstream_rr_peer_t * +ngx_http_upstream_zone_copy_peer(ngx_http_upstream_rr_peers_t *peers, + ngx_http_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_http_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_http_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_http_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c index 0dbacba..a1a5493 100644 --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -472,6 +472,10 @@ ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, vv = ngx_http_get_indexed_variable(r, ngx_http_userid_reset_index); + if (vv == NULL || vv->not_found) { + return NGX_ERROR; + } + if (vv->len == 0 || (vv->len == 1 && vv->data[0] == '0')) { if (conf->mark == '\0' diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c index c036389..9d8b6d7 100644 --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -382,6 +382,13 @@ ngx_http_init_phases(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) return NGX_ERROR; } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers, + cf->pool, 2, sizeof(ngx_http_handler_pt)) + != NGX_OK) + { + return NGX_ERROR; + } + if (ngx_array_init(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers, cf->pool, 4, sizeof(ngx_http_handler_pt)) != NGX_OK) @@ -459,8 +466,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n = 1 /* find config phase */ + use_rewrite /* post rewrite phase */ - + use_access /* post access phase */ - + cmcf->try_files; + + use_access; /* post access phase */ for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { n += cmcf->phases[i].handlers.nelts; @@ -529,15 +535,6 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) continue; - case NGX_HTTP_TRY_FILES_PHASE: - if (cmcf->try_files) { - ph->checker = ngx_http_core_try_files_phase; - n++; - ph++; - } - - continue; - case NGX_HTTP_CONTENT_PHASE: checker = ngx_http_core_content_phase; break; @@ -548,7 +545,7 @@ ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf) n += cmcf->phases[i].handlers.nelts; - for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) { + for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) { ph->checker = checker; ph->handler = h[j]; ph->next = n; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c index 7e40e78..57a4742 100644 --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -61,8 +61,6 @@ static char *ngx_http_core_directio(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, @@ -649,13 +647,6 @@ static ngx_command_t ngx_http_core_commands[] = { 0, NULL }, - { ngx_string("try_files"), - NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE, - ngx_http_core_try_files, - NGX_HTTP_LOC_CONF_OFFSET, - 0, - NULL }, - { ngx_string("post_action"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF |NGX_CONF_TAKE1, @@ -1158,222 +1149,6 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r, } -ngx_int_t -ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph) -{ - size_t len, root, alias, reserve, allocated; - u_char *p, *name; - ngx_str_t path, args; - ngx_uint_t test_dir; - ngx_http_try_file_t *tf; - ngx_open_file_info_t of; - ngx_http_script_code_pt code; - ngx_http_script_engine_t e; - ngx_http_core_loc_conf_t *clcf; - ngx_http_script_len_code_pt lcode; - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try files phase: %ui", r->phase_handler); - - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - if (clcf->try_files == NULL) { - r->phase_handler++; - return NGX_AGAIN; - } - - allocated = 0; - root = 0; - name = NULL; - /* suppress MSVC warning */ - path.data = NULL; - - tf = clcf->try_files; - - alias = clcf->alias; - - for ( ;; ) { - - if (tf->lengths) { - ngx_memzero(&e, sizeof(ngx_http_script_engine_t)); - - e.ip = tf->lengths->elts; - e.request = r; - - /* 1 is for terminating '\0' as in static names */ - len = 1; - - while (*(uintptr_t *) e.ip) { - lcode = *(ngx_http_script_len_code_pt *) e.ip; - len += lcode(&e); - } - - } else { - len = tf->name.len; - } - - if (!alias) { - reserve = len > r->uri.len ? len - r->uri.len : 0; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - reserve = len; - - } else { - reserve = len > r->uri.len - alias ? len - (r->uri.len - alias) : 0; - } - - if (reserve > allocated || !allocated) { - - /* 16 bytes are preallocation */ - allocated = reserve + 16; - - if (ngx_http_map_uri_to_path(r, &path, &root, allocated) == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - name = path.data + root; - } - - if (tf->values == NULL) { - - /* tf->name.len includes the terminating '\0' */ - - ngx_memcpy(name, tf->name.data, tf->name.len); - - path.len = (name + tf->name.len - 1) - path.data; - - } else { - e.ip = tf->values->elts; - e.pos = name; - e.flushed = 1; - - while (*(uintptr_t *) e.ip) { - code = *(ngx_http_script_code_pt *) e.ip; - code((ngx_http_script_engine_t *) &e); - } - - path.len = e.pos - path.data; - - *e.pos = '\0'; - - if (alias && alias != NGX_MAX_SIZE_T_VALUE - && ngx_strncmp(name, r->uri.data, alias) == 0) - { - ngx_memmove(name, name + alias, len - alias); - path.len -= alias; - } - } - - test_dir = tf->test_dir; - - tf++; - - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "trying to use %s: \"%s\" \"%s\"", - test_dir ? "dir" : "file", name, path.data); - - if (tf->lengths == NULL && tf->name.len == 0) { - - if (tf->code) { - ngx_http_finalize_request(r, tf->code); - return NGX_OK; - } - - path.len -= root; - path.data += root; - - if (path.data[0] == '@') { - (void) ngx_http_named_location(r, &path); - - } else { - ngx_http_split_args(r, &path, &args); - - (void) ngx_http_internal_redirect(r, &path, &args); - } - - ngx_http_finalize_request(r, NGX_DONE); - return NGX_OK; - } - - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); - - of.read_ahead = clcf->read_ahead; - of.directio = clcf->directio; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.test_only = 1; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; - - if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) - != NGX_OK) - { - if (of.err == 0) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - if (of.err != NGX_ENOENT - && of.err != NGX_ENOTDIR - && of.err != NGX_ENAMETOOLONG) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err, - "%s \"%s\" failed", of.failed, path.data); - } - - continue; - } - - if (of.is_dir != test_dir) { - continue; - } - - path.len -= root; - path.data += root; - - if (!alias) { - r->uri = path; - - } else if (alias == NGX_MAX_SIZE_T_VALUE) { - if (!test_dir) { - r->uri = path; - r->add_uri_to_alias = 1; - } - - } else { - name = r->uri.data; - - r->uri.len = alias + path.len; - r->uri.data = ngx_pnalloc(r->pool, r->uri.len); - if (r->uri.data == NULL) { - ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - return NGX_OK; - } - - p = ngx_copy(r->uri.data, name, alias); - ngx_memcpy(p, path.data, path.len); - } - - ngx_http_set_exten(r); - - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "try file uri: \"%V\"", &r->uri); - - r->phase_handler++; - return NGX_AGAIN; - } - - /* not reached */ -} - - ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph) @@ -2484,6 +2259,13 @@ ngx_http_subrequest(ngx_http_request_t *r, return NGX_ERROR; } + if (ngx_list_init(&sr->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + return NGX_ERROR; + } + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); sr->main_conf = cscf->ctx->main_conf; sr->srv_conf = cscf->ctx->srv_conf; @@ -3553,7 +3335,6 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf) * clcf->default_type = { 0, NULL }; * clcf->error_log = NULL; * clcf->error_pages = NULL; - * clcf->try_files = NULL; * clcf->client_body_path = NULL; * clcf->regex = NULL; * clcf->exact_match = 0; @@ -4876,89 +4657,6 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) } -static char * -ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_core_loc_conf_t *clcf = conf; - - ngx_str_t *value; - ngx_int_t code; - ngx_uint_t i, n; - ngx_http_try_file_t *tf; - ngx_http_script_compile_t sc; - ngx_http_core_main_conf_t *cmcf; - - if (clcf->try_files) { - return "is duplicate"; - } - - cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); - - cmcf->try_files = 1; - - tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t)); - if (tf == NULL) { - return NGX_CONF_ERROR; - } - - clcf->try_files = tf; - - value = cf->args->elts; - - for (i = 0; i < cf->args->nelts - 1; i++) { - - tf[i].name = value[i + 1]; - - if (tf[i].name.len > 0 - && tf[i].name.data[tf[i].name.len - 1] == '/' - && i + 2 < cf->args->nelts) - { - tf[i].test_dir = 1; - tf[i].name.len--; - tf[i].name.data[tf[i].name.len] = '\0'; - } - - n = ngx_http_script_variables_count(&tf[i].name); - - if (n) { - ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); - - sc.cf = cf; - sc.source = &tf[i].name; - sc.lengths = &tf[i].lengths; - sc.values = &tf[i].values; - sc.variables = n; - sc.complete_lengths = 1; - sc.complete_values = 1; - - if (ngx_http_script_compile(&sc) != NGX_OK) { - return NGX_CONF_ERROR; - } - - } else { - /* add trailing '\0' to length */ - tf[i].name.len++; - } - } - - if (tf[i - 1].name.data[0] == '=') { - - code = ngx_atoi(tf[i - 1].name.data + 1, tf[i - 1].name.len - 2); - - if (code == NGX_ERROR || code > 999) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid code \"%*s\"", - tf[i - 1].name.len - 1, tf[i - 1].name.data); - return NGX_CONF_ERROR; - } - - tf[i].code = code; - } - - return NGX_CONF_OK; -} - - static char * ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h index 5018da0..a6128b5 100644 --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -119,7 +119,8 @@ typedef enum { NGX_HTTP_ACCESS_PHASE, NGX_HTTP_POST_ACCESS_PHASE, - NGX_HTTP_TRY_FILES_PHASE, + NGX_HTTP_PRECONTENT_PHASE, + NGX_HTTP_CONTENT_PHASE, NGX_HTTP_LOG_PHASE @@ -172,8 +173,6 @@ typedef struct { ngx_array_t *ports; - ngx_uint_t try_files; /* unsigned try_files:1 */ - ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1]; } ngx_http_core_main_conf_t; @@ -296,16 +295,6 @@ typedef struct { } ngx_http_err_page_t; -typedef struct { - ngx_array_t *lengths; - ngx_array_t *values; - ngx_str_t name; - - unsigned code:10; - unsigned test_dir:1; -} ngx_http_try_file_t; - - struct ngx_http_core_loc_conf_s { ngx_str_t name; /* location name */ @@ -425,7 +414,6 @@ struct ngx_http_core_loc_conf_s { #endif ngx_array_t *error_pages; /* error_page */ - ngx_http_try_file_t *try_files; /* try_files */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ @@ -486,8 +474,6 @@ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); -ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, - ngx_http_phase_handler_t *ph); ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c index a823c51..3b2b68a 100644 --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -129,6 +129,7 @@ ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data) if (shm_zone->shm.exists) { cache->sh = cache->shpool->data; cache->bsize = ngx_fs_bsize(cache->path->name.data); + cache->max_size /= cache->bsize; return NGX_OK; } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c index e8e5156..844054c 100644 --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -742,7 +742,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_major = r->http_major * 10 + ch - '0'; + r->http_major = r->http_major * 10 + (ch - '0'); if (r->http_major > 1) { return NGX_HTTP_PARSE_INVALID_VERSION; @@ -784,7 +784,7 @@ ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b) return NGX_HTTP_PARSE_INVALID_REQUEST; } - r->http_minor = r->http_minor * 10 + ch - '0'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; case sw_spaces_after_digit: @@ -1518,7 +1518,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) case sw_quoted_second: if (ch >= '0' && ch <= '9') { - ch = (u_char) ((decoded << 4) + ch - '0'); + ch = (u_char) ((decoded << 4) + (ch - '0')); if (ch == '%' || ch == '#') { state = sw_usual; @@ -1536,7 +1536,7 @@ ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes) c = (u_char) (ch | 0x20); if (c >= 'a' && c <= 'f') { - ch = (u_char) ((decoded << 4) + c - 'a' + 10); + ch = (u_char) ((decoded << 4) + (c - 'a') + 10); if (ch == '?') { state = sw_usual; @@ -1701,7 +1701,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - r->http_major = r->http_major * 10 + ch - '0'; + r->http_major = r->http_major * 10 + (ch - '0'); break; /* the first digit of minor HTTP version */ @@ -1729,7 +1729,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - r->http_minor = r->http_minor * 10 + ch - '0'; + r->http_minor = r->http_minor * 10 + (ch - '0'); break; /* HTTP status code */ @@ -1742,7 +1742,7 @@ ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b, return NGX_ERROR; } - status->code = status->code * 10 + ch - '0'; + status->code = status->code * 10 + (ch - '0'); if (++status->count == 3) { state = sw_space_after_status; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c index cc3722f..de1b202 100644 --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -562,6 +562,14 @@ ngx_http_create_request(ngx_connection_t *c) return NULL; } + if (ngx_list_init(&r->headers_out.trailers, r->pool, 4, + sizeof(ngx_table_elt_t)) + != NGX_OK) + { + ngx_destroy_pool(r->pool); + return NULL; + } + r->ctx = ngx_pcalloc(r->pool, sizeof(void *) * ngx_http_max_module); if (r->ctx == NULL) { ngx_destroy_pool(r->pool); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h index 283c582..421004a 100644 --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -252,6 +252,7 @@ typedef struct { typedef struct { ngx_list_t headers; + ngx_list_t trailers; ngx_uint_t status; ngx_str_t status_line; @@ -514,6 +515,7 @@ struct ngx_http_request_s { unsigned pipeline:1; unsigned chunked:1; unsigned header_only:1; + unsigned expect_trailers:1; unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; @@ -535,6 +537,7 @@ struct ngx_http_request_s { unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; unsigned filter_need_temporary:1; + unsigned preserve_body:1; unsigned allow_ranges:1; unsigned subrequest_ranges:1; unsigned single_range:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 0fc5ab5..6a2b322 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -182,7 +182,9 @@ static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); #if (NGX_HTTP_SSL) static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); -static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c); +static void ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c); +static void ngx_http_upstream_ssl_handshake(ngx_http_request_t *, + ngx_http_upstream_t *u, ngx_connection_t *c); static ngx_int_t ngx_http_upstream_ssl_name(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c); #endif @@ -425,7 +427,7 @@ static ngx_http_variable_t ngx_http_upstream_vars[] = { { ngx_string("upstream_cookie_"), NULL, ngx_http_upstream_cookie_variable, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -1075,6 +1077,10 @@ ngx_http_upstream_cache_background_update(ngx_http_request_t *r, return NGX_OK; } + if (r == r->main) { + r->preserve_body = 1; + } + if (ngx_http_subrequest(r, &r->uri, &r->args, &sr, NULL, NGX_HTTP_SUBREQUEST_CLONE |NGX_HTTP_SUBREQUEST_BACKGROUND) @@ -1143,11 +1149,14 @@ ngx_http_upstream_cache_check_range(ngx_http_request_t *r, static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) { + ngx_uint_t run_posted; ngx_connection_t *c; ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_http_upstream_resolved_t *ur; + run_posted = ctx->async; + r = ctx->data; c = r->connection; @@ -1211,7 +1220,9 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx) failed: - ngx_http_run_posted_requests(c); + if (run_posted) { + ngx_http_run_posted_requests(c); + } } @@ -1662,26 +1673,43 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, ngx_add_timer(c->write, u->conf->connect_timeout); } - c->ssl->handler = ngx_http_upstream_ssl_handshake; + c->ssl->handler = ngx_http_upstream_ssl_handshake_handler; return; } - ngx_http_upstream_ssl_handshake(c); + ngx_http_upstream_ssl_handshake(r, u, c); } static void -ngx_http_upstream_ssl_handshake(ngx_connection_t *c) +ngx_http_upstream_ssl_handshake_handler(ngx_connection_t *c) { - long rc; ngx_http_request_t *r; ngx_http_upstream_t *u; r = c->data; + u = r->upstream; + c = r->connection; ngx_http_set_log_request(c->log, r); + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, + "http upstream ssl handshake: \"%V?%V\"", + &r->uri, &r->args); + + ngx_http_upstream_ssl_handshake(r, u, u->peer.connection); + + ngx_http_run_posted_requests(c); +} + + +static void +ngx_http_upstream_ssl_handshake(ngx_http_request_t *r, ngx_http_upstream_t *u, + ngx_connection_t *c) +{ + long rc; + if (c->ssl->handshaked) { if (u->conf->ssl_verify) { @@ -1709,28 +1737,19 @@ ngx_http_upstream_ssl_handshake(ngx_connection_t *c) c->write->handler = ngx_http_upstream_handler; c->read->handler = ngx_http_upstream_handler; - c = r->connection; - ngx_http_upstream_send_request(r, u, 1); - ngx_http_run_posted_requests(c); return; } if (c->write->timedout) { - c = r->connection; ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_TIMEOUT); - ngx_http_run_posted_requests(c); return; } failed: - c = r->connection; - ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR); - - ngx_http_run_posted_requests(c); } @@ -2729,7 +2748,7 @@ ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r, rev = c->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http upstream process body on memory"); + "http upstream process body in memory"); if (rev->timedout) { ngx_connection_error(c, NGX_ETIMEDOUT, "upstream timed out"); @@ -2842,7 +2861,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u) u->pipe->downstream_error = 1; } - if (r->request_body && r->request_body->temp_file) { + if (r->request_body && r->request_body->temp_file + && r == r->main && !r->preserve_body) + { ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd); r->request_body->temp_file->file.fd = NGX_INVALID_FILE; } @@ -4488,7 +4509,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4516,7 +4537,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } @@ -4539,7 +4560,7 @@ ngx_http_upstream_process_cache_control(ngx_http_request_t *r, } if (*p >= '0' && *p <= '9') { - n = n * 10 + *p - '0'; + n = n * 10 + (*p - '0'); continue; } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c index 6138819..afeb4ce 100644 --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -38,6 +38,8 @@ static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r, @@ -365,13 +367,16 @@ static ngx_http_variable_t ngx_http_core_variables[] = { { ngx_string("sent_http_"), NULL, ngx_http_variable_unknown_header_out, 0, NGX_HTTP_VAR_PREFIX, 0 }, + { ngx_string("sent_trailer_"), NULL, ngx_http_variable_unknown_trailer_out, + 0, NGX_HTTP_VAR_PREFIX, 0 }, + { ngx_string("cookie_"), NULL, ngx_http_variable_cookie, 0, NGX_HTTP_VAR_PREFIX, 0 }, { ngx_string("arg_"), NULL, ngx_http_variable_argument, 0, NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_PREFIX, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; @@ -934,6 +939,16 @@ ngx_http_variable_unknown_header_out(ngx_http_request_t *r, } +static ngx_int_t +ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, + &r->headers_out.trailers.part, + sizeof("sent_trailer_") - 1); +} + + ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var, ngx_list_part_t *part, size_t prefix) @@ -1448,17 +1463,15 @@ static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - if (r->args.len == 0) { - v->len = 0; - v->data = NULL; + *v = ngx_http_variable_null_value; return NGX_OK; } v->len = 1; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; v->data = (u_char *) "?"; return NGX_OK; @@ -1975,11 +1988,7 @@ ngx_http_variable_request_completion(ngx_http_request_t *r, return NGX_OK; } - v->len = 0; - v->valid = 1; - v->no_cacheable = 0; - v->not_found = 0; - v->data = (u_char *) ""; + *v = ngx_http_variable_null_value; return NGX_OK; } diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h index df337de..f3f7f3c 100644 --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -43,6 +43,8 @@ struct ngx_http_variable_s { ngx_uint_t index; }; +#define ngx_http_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags); diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c index ed78638..7725616 100644 --- a/src/http/v2/ngx_http_v2.c +++ b/src/http/v2/ngx_http_v2.c @@ -28,6 +28,7 @@ #define NGX_HTTP_V2_HTTP_1_1_REQUIRED 0xd /* frame sizes */ +#define NGX_HTTP_V2_SETTINGS_ACK_SIZE 0 #define NGX_HTTP_V2_RST_STREAM_SIZE 4 #define NGX_HTTP_V2_PRIORITY_SIZE 5 #define NGX_HTTP_V2_PING_SIZE 8 @@ -128,8 +129,7 @@ static ngx_http_v2_node_t *ngx_http_v2_get_closed_node( #define ngx_http_v2_index_size(h2scf) (h2scf->streams_index_mask + 1) #define ngx_http_v2_index(h2scf, sid) ((sid >> 1) & h2scf->streams_index_mask) -static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, - ngx_uint_t ack); +static ngx_int_t ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c); static ngx_int_t ngx_http_v2_settings_frame_handler( ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); static ngx_int_t ngx_http_v2_send_window_update(ngx_http_v2_connection_t *h2c, @@ -269,7 +269,7 @@ ngx_http_v2_init(ngx_event_t *rev) return; } - if (ngx_http_v2_send_settings(h2c, 0) == NGX_ERROR) { + if (ngx_http_v2_send_settings(h2c) == NGX_ERROR) { ngx_http_close_connection(c); return; } @@ -1568,6 +1568,10 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, rc = ngx_http_v2_pseudo_header(r, header); if (rc == NGX_OK) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 pseudo-header: \":%V: %V\"", + &header->name, &header->value); + return ngx_http_v2_state_header_complete(h2c, pos, end); } @@ -1609,36 +1613,40 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_INTERNAL_ERROR); } - return ngx_http_v2_state_header_complete(h2c, pos, end); - } + } else { + h = ngx_list_push(&r->headers_in.headers); + if (h == NULL) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } - h = ngx_list_push(&r->headers_in.headers); - if (h == NULL) { - return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); - } + h->key.len = header->name.len; + h->key.data = header->name.data; - h->key.len = header->name.len; - h->key.data = header->name.data; + /* + * TODO Optimization: precalculate hash + * and handler for indexed headers. + */ + h->hash = ngx_hash_key(h->key.data, h->key.len); - /* TODO Optimization: precalculate hash and handler for indexed headers. */ - h->hash = ngx_hash_key(h->key.data, h->key.len); + h->value.len = header->value.len; + h->value.data = header->value.data; - h->value.len = header->value.len; - h->value.data = header->value.data; + h->lowcase_key = h->key.data; - h->lowcase_key = h->key.data; + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); - cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, + h->lowcase_key, h->key.len); - hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash, - h->lowcase_key, h->key.len); - - if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { - goto error; + if (hh && hh->handler(r, h, hh->offset) != NGX_OK) { + goto error; + } } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http2 http header: \"%V: %V\"", &h->key, &h->value); + "http2 http header: \"%V: %V\"", + &header->name, &header->value); return ngx_http_v2_state_header_complete(h2c, pos, end); @@ -1951,8 +1959,6 @@ 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_http_v2_send_settings(h2c, 1); - return ngx_http_v2_state_settings_params(h2c, pos, end); } @@ -1961,7 +1967,11 @@ static u_char * ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end) { - ngx_uint_t id, value; + ssize_t window_delta; + ngx_uint_t id, value; + ngx_http_v2_out_frame_t *frame; + + window_delta = 0; while (h2c->state.length) { if (end - pos < NGX_HTTP_V2_SETTINGS_PARAM_SIZE) { @@ -1987,12 +1997,7 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, NGX_HTTP_V2_FLOW_CTRL_ERROR); } - if (ngx_http_v2_adjust_windows(h2c, value - h2c->init_window) - != NGX_OK) - { - return ngx_http_v2_connection_error(h2c, - NGX_HTTP_V2_INTERNAL_ERROR); - } + window_delta = value - h2c->init_window; h2c->init_window = value; break; @@ -2020,6 +2025,22 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, pos += NGX_HTTP_V2_SETTINGS_PARAM_SIZE; } + frame = ngx_http_v2_get_frame(h2c, NGX_HTTP_V2_SETTINGS_ACK_SIZE, + NGX_HTTP_V2_SETTINGS_FRAME, + NGX_HTTP_V2_ACK_FLAG, 0); + if (frame == NULL) { + return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_INTERNAL_ERROR); + } + + ngx_http_v2_queue_ordered_frame(h2c, frame); + + if (window_delta) { + if (ngx_http_v2_adjust_windows(h2c, window_delta) != NGX_OK) { + return ngx_http_v2_connection_error(h2c, + NGX_HTTP_V2_INTERNAL_ERROR); + } + } + return ngx_http_v2_state_complete(h2c, pos, end); } @@ -2463,7 +2484,7 @@ ngx_http_v2_parse_int(ngx_http_v2_connection_t *h2c, u_char **pos, u_char *end, static ngx_int_t -ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) +ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c) { size_t len; ngx_buf_t *buf; @@ -2471,8 +2492,8 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) ngx_http_v2_srv_conf_t *h2scf; ngx_http_v2_out_frame_t *frame; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, - "http2 send SETTINGS frame ack:%ui", ack); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 send SETTINGS frame"); frame = ngx_palloc(h2c->pool, sizeof(ngx_http_v2_out_frame_t)); if (frame == NULL) { @@ -2484,7 +2505,7 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) return NGX_ERROR; } - len = ack ? 0 : (sizeof(uint16_t) + sizeof(uint32_t)) * 3; + len = NGX_HTTP_V2_SETTINGS_PARAM_SIZE * 3; buf = ngx_create_temp_buf(h2c->pool, NGX_HTTP_V2_FRAME_HEADER_SIZE + len); if (buf == NULL) { @@ -2508,28 +2529,26 @@ ngx_http_v2_send_settings(ngx_http_v2_connection_t *h2c, ngx_uint_t ack) buf->last = ngx_http_v2_write_len_and_type(buf->last, len, NGX_HTTP_V2_SETTINGS_FRAME); - *buf->last++ = ack ? NGX_HTTP_V2_ACK_FLAG : NGX_HTTP_V2_NO_FLAG; + *buf->last++ = NGX_HTTP_V2_NO_FLAG; buf->last = ngx_http_v2_write_sid(buf->last, 0); - if (!ack) { - h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, - ngx_http_v2_module); + h2scf = ngx_http_get_module_srv_conf(h2c->http_connection->conf_ctx, + ngx_http_v2_module); - buf->last = ngx_http_v2_write_uint16(buf->last, - NGX_HTTP_V2_MAX_STREAMS_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - h2scf->concurrent_streams); + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_STREAMS_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + h2scf->concurrent_streams); - buf->last = ngx_http_v2_write_uint16(buf->last, + buf->last = ngx_http_v2_write_uint16(buf->last, NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); + buf->last = ngx_http_v2_write_uint32(buf->last, h2scf->preread_size); - buf->last = ngx_http_v2_write_uint16(buf->last, - NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); - buf->last = ngx_http_v2_write_uint32(buf->last, - NGX_HTTP_V2_MAX_FRAME_SIZE); - } + buf->last = ngx_http_v2_write_uint16(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); + buf->last = ngx_http_v2_write_uint32(buf->last, + NGX_HTTP_V2_MAX_FRAME_SIZE); ngx_http_v2_queue_blocked_frame(h2c, frame); @@ -3313,6 +3332,7 @@ ngx_http_v2_construct_request_line(ngx_http_request_t *r) static const u_char ending[] = " HTTP/2.0"; if (r->method_name.len == 0 + || r->schema_start == NULL || r->unparsed_uri.len == 0) { ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h index be34a09..4804658 100644 --- a/src/http/v2/ngx_http_v2.h +++ b/src/http/v2/ngx_http_v2.h @@ -261,6 +261,15 @@ ngx_http_v2_queue_blocked_frame(ngx_http_v2_connection_t *h2c, } +static ngx_inline void +ngx_http_v2_queue_ordered_frame(ngx_http_v2_connection_t *h2c, + ngx_http_v2_out_frame_t *frame) +{ + frame->next = h2c->last_out; + h2c->last_out = frame; +} + + void ngx_http_v2_init(ngx_event_t *rev); void ngx_http_v2_request_headers_init(void); diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 7276531..8621e7a 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c @@ -50,13 +50,17 @@ #define NGX_HTTP_V2_SERVER_INDEX 54 #define NGX_HTTP_V2_VARY_INDEX 59 +#define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 + 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_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_trailers_frame( + ngx_http_request_t *r); static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit); @@ -612,7 +616,7 @@ 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); + frame = ngx_http_v2_create_headers_frame(r, start, pos, r->header_only); if (frame == NULL) { return NGX_ERROR; } @@ -636,6 +640,118 @@ ngx_http_v2_header_filter(ngx_http_request_t *r) } +static ngx_http_v2_out_frame_t * +ngx_http_v2_create_trailers_frame(ngx_http_request_t *r) +{ + u_char *pos, *start, *tmp; + size_t len, tmp_len; + ngx_uint_t i; + ngx_list_part_t *part; + ngx_table_elt_t *header; + + len = 0; + tmp_len = 0; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + + if (header[i].key.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response trailer name: \"%V\"", + &header[i].key); + return NULL; + } + + if (header[i].value.len > NGX_HTTP_V2_MAX_FIELD) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0, + "too long response trailer value: \"%V: %V\"", + &header[i].key, &header[i].value); + return NULL; + } + + len += 1 + NGX_HTTP_V2_INT_OCTETS + header[i].key.len + + NGX_HTTP_V2_INT_OCTETS + header[i].value.len; + + if (header[i].key.len > tmp_len) { + tmp_len = header[i].key.len; + } + + if (header[i].value.len > tmp_len) { + tmp_len = header[i].value.len; + } + } + + if (len == 0) { + return NGX_HTTP_V2_NO_TRAILERS; + } + + tmp = ngx_palloc(r->pool, tmp_len); + pos = ngx_pnalloc(r->pool, len); + + if (pos == NULL || tmp == NULL) { + return NULL; + } + + start = pos; + + part = &r->headers_out.trailers.part; + header = part->elts; + + for (i = 0; /* void */; i++) { + + if (i >= part->nelts) { + if (part->next == NULL) { + break; + } + + part = part->next; + header = part->elts; + i = 0; + } + + if (header[i].hash == 0) { + continue; + } + +#if (NGX_DEBUG) + if (r->connection->log->log_level & NGX_LOG_DEBUG_HTTP) { + ngx_strlow(tmp, header[i].key.data, header[i].key.len); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http2 output trailer: \"%*s: %V\"", + header[i].key.len, tmp, &header[i].value); + } +#endif + + *pos++ = 0; + + pos = ngx_http_v2_write_name(pos, header[i].key.data, + header[i].key.len, tmp); + + pos = ngx_http_v2_write_value(pos, header[i].value.data, + header[i].value.len, tmp); + } + + return ngx_http_v2_create_headers_frame(r, start, pos, 1); +} + + static u_char * ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, ngx_uint_t lower) @@ -686,7 +802,7 @@ 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) + u_char *end, ngx_uint_t fin) { u_char type, flags; size_t rest, frame_size; @@ -707,12 +823,12 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, frame->stream = stream; frame->length = rest; frame->blocked = 1; - frame->fin = r->header_only; + frame->fin = fin; ll = &frame->first; type = NGX_HTTP_V2_HEADERS_FRAME; - flags = r->header_only ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; + flags = fin ? NGX_HTTP_V2_END_STREAM_FLAG : NGX_HTTP_V2_NO_FLAG; frame_size = stream->connection->frame_size; for ( ;; ) { @@ -776,7 +892,7 @@ ngx_http_v2_create_headers_frame(ngx_http_request_t *r, u_char *pos, continue; } - b->last_buf = r->header_only; + b->last_buf = fin; cl->next = NULL; frame->last = cl; @@ -798,7 +914,7 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) ngx_http_request_t *r; ngx_http_v2_stream_t *stream; ngx_http_v2_loc_conf_t *h2lcf; - ngx_http_v2_out_frame_t *frame; + ngx_http_v2_out_frame_t *frame, *trailers; ngx_http_v2_connection_t *h2c; r = fc->data; @@ -872,6 +988,8 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) frame_size = (h2lcf->chunk_size < h2c->frame_size) ? h2lcf->chunk_size : h2c->frame_size; + trailers = NGX_HTTP_V2_NO_TRAILERS; + #if (NGX_SUPPRESS_WARN) cl = NULL; #endif @@ -934,19 +1052,39 @@ ngx_http_v2_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) size -= rest; } - frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, out, cl); - if (frame == NULL) { - return NGX_CHAIN_ERROR; + if (cl->buf->last_buf) { + trailers = ngx_http_v2_create_trailers_frame(r); + if (trailers == NULL) { + return NGX_CHAIN_ERROR; + } + + if (trailers != NGX_HTTP_V2_NO_TRAILERS) { + cl->buf->last_buf = 0; + } } - ngx_http_v2_queue_frame(h2c, frame); + if (frame_size || cl->buf->last_buf) { + frame = ngx_http_v2_filter_get_data_frame(stream, frame_size, + out, cl); + if (frame == NULL) { + return NGX_CHAIN_ERROR; + } - h2c->send_window -= frame_size; + ngx_http_v2_queue_frame(h2c, frame); - stream->send_window -= frame_size; - stream->queued++; + h2c->send_window -= frame_size; + + stream->send_window -= frame_size; + stream->queued++; + } if (in == NULL) { + + if (trailers != NGX_HTTP_V2_NO_TRAILERS) { + ngx_http_v2_queue_frame(h2c, trailers); + stream->queued++; + } + break; } diff --git a/src/http/v2/ngx_http_v2_module.c b/src/http/v2/ngx_http_v2_module.c index 032abcb..7f7dab2 100644 --- a/src/http/v2/ngx_http_v2_module.c +++ b/src/http/v2/ngx_http_v2_module.c @@ -225,7 +225,7 @@ static ngx_http_variable_t ngx_http_v2_vars[] = { { ngx_string("http2"), NULL, ngx_http_v2_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_http_null_variable }; diff --git a/src/misc/ngx_google_perftools_module.c b/src/misc/ngx_google_perftools_module.c index f2f8221..381f3d1 100644 --- a/src/misc/ngx_google_perftools_module.c +++ b/src/misc/ngx_google_perftools_module.c @@ -36,7 +36,7 @@ static ngx_command_t ngx_google_perftools_commands[] = { offsetof(ngx_google_perftools_conf_t, profiles), NULL }, - ngx_null_command + ngx_null_command }; diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c index 5f1cfa5..5399c79 100644 --- a/src/os/unix/ngx_udp_sendmsg_chain.c +++ b/src/os/unix/ngx_udp_sendmsg_chain.c @@ -206,13 +206,13 @@ ngx_sendmsg(ngx_connection_t *c, ngx_iovec_t *vec) #if (NGX_HAVE_MSGHDR_MSG_CONTROL) #if (NGX_HAVE_IP_SENDSRCADDR) - u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; + u_char msg_control[CMSG_SPACE(sizeof(struct in_addr))]; #elif (NGX_HAVE_IP_PKTINFO) - u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; + u_char msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))]; #endif #if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO) - u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; + u_char msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))]; #endif #endif diff --git a/src/stream/ngx_stream_geoip_module.c b/src/stream/ngx_stream_geoip_module.c index f694033..6507b71 100644 --- a/src/stream/ngx_stream_geoip_module.c +++ b/src/stream/ngx_stream_geoip_module.c @@ -210,7 +210,7 @@ static ngx_stream_variable_t ngx_stream_geoip_vars[] = { ngx_stream_geoip_city_int_variable, offsetof(GeoIPRecord, area_code), 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_realip_module.c b/src/stream/ngx_stream_realip_module.c index 1266605..57b1ac2 100644 --- a/src/stream/ngx_stream_realip_module.c +++ b/src/stream/ngx_stream_realip_module.c @@ -89,7 +89,7 @@ static ngx_stream_variable_t ngx_stream_realip_vars[] = { { ngx_string("realip_remote_port"), NULL, ngx_stream_realip_remote_port_variable, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c index da26a41..010b98b 100644 --- a/src/stream/ngx_stream_ssl_module.c +++ b/src/stream/ngx_stream_ssl_module.c @@ -273,7 +273,7 @@ static ngx_stream_variable_t ngx_stream_ssl_vars[] = { { ngx_string("ssl_client_v_remain"), NULL, ngx_stream_ssl_variable, (uintptr_t) ngx_ssl_get_client_v_remain, NGX_STREAM_VAR_CHANGEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_ssl_preread_module.c b/src/stream/ngx_stream_ssl_preread_module.c index 2040b4f..e3d11fd 100644 --- a/src/stream/ngx_stream_ssl_preread_module.c +++ b/src/stream/ngx_stream_ssl_preread_module.c @@ -85,7 +85,7 @@ 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_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream.c b/src/stream/ngx_stream_upstream.c index c9e1784..7feac43 100644 --- a/src/stream/ngx_stream_upstream.c +++ b/src/stream/ngx_stream_upstream.c @@ -100,7 +100,7 @@ static ngx_stream_variable_t ngx_stream_upstream_vars[] = { ngx_stream_upstream_bytes_variable, 1, NGX_STREAM_VAR_NOCACHEABLE, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_upstream_zone_module.c b/src/stream/ngx_stream_upstream_zone_module.c index 07ab88d..4f72188 100644 --- a/src/stream/ngx_stream_upstream_zone_module.c +++ b/src/stream/ngx_stream_upstream_zone_module.c @@ -16,6 +16,8 @@ static ngx_int_t ngx_stream_upstream_init_zone(ngx_shm_zone_t *shm_zone, void *data); static ngx_stream_upstream_rr_peers_t *ngx_stream_upstream_zone_copy_peers( ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf); +static ngx_stream_upstream_rr_peer_t *ngx_stream_upstream_zone_copy_peer( + ngx_stream_upstream_rr_peers_t *peers, ngx_stream_upstream_rr_peer_t *src); static ngx_command_t ngx_stream_upstream_zone_commands[] = { @@ -182,6 +184,7 @@ static ngx_stream_upstream_rr_peers_t * ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_stream_upstream_srv_conf_t *uscf) { + ngx_str_t *name; ngx_stream_upstream_rr_peer_t *peer, **peerp; ngx_stream_upstream_rr_peers_t *peers, *backup; @@ -192,18 +195,30 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(peers, uscf->peer.data, sizeof(ngx_stream_upstream_rr_peers_t)); + name = ngx_slab_alloc(shpool, sizeof(ngx_str_t)); + if (name == NULL) { + return NULL; + } + + name->data = ngx_slab_alloc(shpool, peers->name->len); + if (name->data == NULL) { + return NULL; + } + + ngx_memcpy(name->data, peers->name->data, peers->name->len); + name->len = peers->name->len; + + peers->name = name; + peers->shpool = shpool; for (peerp = &peers->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(peers, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -218,18 +233,17 @@ ngx_stream_upstream_zone_copy_peers(ngx_slab_pool_t *shpool, ngx_memcpy(backup, peers->next, sizeof(ngx_stream_upstream_rr_peers_t)); + backup->name = name; + backup->shpool = shpool; for (peerp = &backup->peer; *peerp; peerp = &peer->next) { /* pool is unlocked */ - peer = ngx_slab_calloc_locked(shpool, - sizeof(ngx_stream_upstream_rr_peer_t)); + peer = ngx_stream_upstream_zone_copy_peer(backup, *peerp); if (peer == NULL) { return NULL; } - ngx_memcpy(peer, *peerp, sizeof(ngx_stream_upstream_rr_peer_t)); - *peerp = peer; } @@ -241,3 +255,68 @@ done: return peers; } + + +static ngx_stream_upstream_rr_peer_t * +ngx_stream_upstream_zone_copy_peer(ngx_stream_upstream_rr_peers_t *peers, + ngx_stream_upstream_rr_peer_t *src) +{ + ngx_slab_pool_t *pool; + ngx_stream_upstream_rr_peer_t *dst; + + pool = peers->shpool; + + dst = ngx_slab_calloc_locked(pool, sizeof(ngx_stream_upstream_rr_peer_t)); + if (dst == NULL) { + return NULL; + } + + if (src) { + ngx_memcpy(dst, src, sizeof(ngx_stream_upstream_rr_peer_t)); + dst->sockaddr = NULL; + dst->name.data = NULL; + dst->server.data = NULL; + } + + dst->sockaddr = ngx_slab_calloc_locked(pool, NGX_SOCKADDRLEN); + if (dst->sockaddr == NULL) { + goto failed; + } + + dst->name.data = ngx_slab_calloc_locked(pool, NGX_SOCKADDR_STRLEN); + if (dst->name.data == NULL) { + goto failed; + } + + if (src) { + ngx_memcpy(dst->sockaddr, src->sockaddr, src->socklen); + ngx_memcpy(dst->name.data, src->name.data, src->name.len); + + dst->server.data = ngx_slab_alloc_locked(pool, src->server.len); + if (dst->server.data == NULL) { + goto failed; + } + + ngx_memcpy(dst->server.data, src->server.data, src->server.len); + } + + return dst; + +failed: + + if (dst->server.data) { + ngx_slab_free_locked(pool, dst->server.data); + } + + if (dst->name.data) { + ngx_slab_free_locked(pool, dst->name.data); + } + + if (dst->sockaddr) { + ngx_slab_free_locked(pool, dst->sockaddr); + } + + ngx_slab_free_locked(pool, dst); + + return NULL; +} diff --git a/src/stream/ngx_stream_variables.c b/src/stream/ngx_stream_variables.c index 5d15f3a..45d6e60 100644 --- a/src/stream/ngx_stream_variables.c +++ b/src/stream/ngx_stream_variables.c @@ -111,7 +111,7 @@ static ngx_stream_variable_t ngx_stream_core_variables[] = { { ngx_string("protocol"), NULL, ngx_stream_variable_protocol, 0, 0, 0 }, - { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_null_variable }; diff --git a/src/stream/ngx_stream_variables.h b/src/stream/ngx_stream_variables.h index 8155111..4ead2a6 100644 --- a/src/stream/ngx_stream_variables.h +++ b/src/stream/ngx_stream_variables.h @@ -43,6 +43,8 @@ struct ngx_stream_variable_s { ngx_uint_t index; }; +#define ngx_stream_null_variable { ngx_null_string, NULL, NULL, 0, 0, 0 } + ngx_stream_variable_t *ngx_stream_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags);