Merge branch 'nginx' (nginx-1.17.2). Change-Id: I207cb57b1e8b5ba29414b601c9d64abf34a1e917 Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags index 10adccb..7f2d14e 100644 --- a/.hgtags +++ b/.hgtags
@@ -440,3 +440,4 @@ 0130ca3d58437b3c7c707cdddd813d530c68da9a release-1.15.12 054c1c46395caff79bb4caf16f40b331f71bb6dd release-1.17.0 7816bd7dabf6ee86c53c073b90a7143161546e06 release-1.17.1 +2fc9f853a6b7cd29dc84e0af2ed3cf78e0da6ca8 release-1.17.2
diff --git a/BUILD b/BUILD index 6d525ff..6aa3098 100644 --- a/BUILD +++ b/BUILD
@@ -1520,5 +1520,5 @@ preinst = "@nginx_pkgoss//:debian_preinst", prerm = "@nginx_pkgoss//:debian_prerm", section = "httpd", - version = "1.17.1", + version = "1.17.2", )
diff --git a/build.bzl b/build.bzl index ab28273..6019d63 100644 --- a/build.bzl +++ b/build.bzl
@@ -673,9 +673,9 @@ name = "nginx_pkgoss", build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) + _PKGOSS_BUILD_FILE_TAIL, - commit = "daeedba4e4b391c95274826cadc8710435c60845", # nginx-1.17.1 + commit = "e76a000ffe16bb7f2abf2bcee40d88071c849dc2", # nginx-1.17.2 remote = "https://nginx.googlesource.com/nginx-pkgoss", - shallow_since = "1561466004 +0300", + shallow_since = "1563882489 +0300", ) def nginx_repositories_zlib(bind):
diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim index 6bee7a2..1a3a7b7 100644 --- a/contrib/vim/syntax/nginx.vim +++ b/contrib/vim/syntax/nginx.vim
@@ -333,6 +333,7 @@ syn keyword ngxDirective contained js_content syn keyword ngxDirective contained js_filter syn keyword ngxDirective contained js_include +syn keyword ngxDirective contained js_path syn keyword ngxDirective contained js_preread syn keyword ngxDirective contained js_set syn keyword ngxDirective contained keepalive @@ -353,6 +354,7 @@ syn keyword ngxDirective contained limit_rate syn keyword ngxDirective contained limit_rate_after syn keyword ngxDirective contained limit_req +syn keyword ngxDirective contained limit_req_dry_run syn keyword ngxDirective contained limit_req_log_level syn keyword ngxDirective contained limit_req_status syn keyword ngxDirective contained limit_req_zone @@ -472,6 +474,7 @@ syn keyword ngxDirective contained proxy_responses syn keyword ngxDirective contained proxy_send_lowat syn keyword ngxDirective contained proxy_send_timeout +syn keyword ngxDirective contained proxy_session_drop syn keyword ngxDirective contained proxy_set_body syn keyword ngxDirective contained proxy_set_header syn keyword ngxDirective contained proxy_socket_keepalive @@ -1325,6 +1328,7 @@ syn keyword ngxDirectiveThirdParty contained lua_code_cache syn keyword ngxDirectiveThirdParty contained lua_fake_shm syn keyword ngxDirectiveThirdParty contained lua_http10_buffering +syn keyword ngxDirectiveThirdParty contained lua_load_resty_core syn keyword ngxDirectiveThirdParty contained lua_malloc_trim syn keyword ngxDirectiveThirdParty contained lua_max_pending_timers syn keyword ngxDirectiveThirdParty contained lua_max_running_timers @@ -1779,6 +1783,7 @@ syn keyword ngxDirectiveThirdParty contained vod_fallback_upstream_location syn keyword ngxDirectiveThirdParty contained vod_force_continuous_timestamps syn keyword ngxDirectiveThirdParty contained vod_force_playlist_type_vod +syn keyword ngxDirectiveThirdParty contained vod_force_sequence_index syn keyword ngxDirectiveThirdParty contained vod_gop_look_ahead syn keyword ngxDirectiveThirdParty contained vod_gop_look_behind syn keyword ngxDirectiveThirdParty contained vod_ignore_edit_list
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml index 5963cd7..416de1f 100644 --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,95 @@ <change_log title="nginx"> +<changes ver="1.17.2" date="2019-07-23"> + +<change type="change"> +<para lang="ru"> +минимальная поддерживаемая версия zlib—1.2.0.4.<br/> +Спасибо Илье Леошкевичу. +</para> +<para lang="en"> +minimum supported zlib version is 1.2.0.4.<br/> +Thanks to Ilya Leoshkevich. +</para> +</change> + +<change type="change"> +<para lang="ru"> +метод $r->internal_redirect() встроенного перла +теперь ожидает закодированный URI. +</para> +<para lang="en"> +the $r->internal_redirect() embedded perl method +now expects escaped URIs. +</para> +</change> + +<change type="feature"> +<para lang="ru"> +теперь с помощью метода $r->internal_redirect() встроенного перла +можно перейти в именованный location. +</para> +<para lang="en"> +it is now possible to switch to a named location +using the $r->internal_redirect() embedded perl method. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в обработке ошибок во встроенном перле. +</para> +<para lang="en"> +in error handling in embedded perl. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +на старте или во время переконфигурации мог произойти segmentation fault, +если в конфигурации использовалось значение hash bucket size больше 64 килобайт. +</para> +<para lang="en"> +a segmentation fault might occur on start or during reconfiguration +if hash bucket size larger than 64 kilobytes was used in the configuration. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +при использовании методов обработки соединений select, poll и /dev/poll +nginx мог нагружать процессор во время небуферизованного проксирования +и при проксировании WebSocket-соединений. +</para> +<para lang="en"> +nginx might hog CPU during unbuffered proxying +and when proxying WebSocket connections +if the select, poll, or /dev/poll methods were used. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в модуле ngx_http_xslt_filter_module. +</para> +<para lang="en"> +in the ngx_http_xslt_filter_module. +</para> +</change> + +<change type="bugfix"> +<para lang="ru"> +в модуле ngx_http_ssi_filter_module. +</para> +<para lang="en"> +in the ngx_http_ssi_filter_module. +</para> +</change> + +</changes> + + <changes ver="1.17.1" date="2019-06-25"> <change type="feature"> @@ -34,7 +123,7 @@ <para lang="ru"> в рабочем процессе мог произойти segmentation fault, если использовалось кэширование и директива image_filter, -а ошибки с кодом 415 перенаправлялись с помощь директивы error_page; +а ошибки с кодом 415 перенаправлялись с помощью директивы error_page; ошибка появилась в 1.11.10. </para> <para lang="en">
diff --git a/src/core/nginx.h b/src/core/nginx.h index ae2eec5..95589d5 100644 --- a/src/core/nginx.h +++ b/src/core/nginx.h
@@ -13,8 +13,8 @@ #define NGINX_NAME "nginx" #endif -#define nginx_version 1017001 -#define NGINX_VERSION "1.17.1" +#define nginx_version 1017002 +#define NGINX_VERSION "1.17.2" #define NGINX_VER NGINX_NAME "/" NGINX_VERSION #ifdef NGX_BUILD
diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c index 1944c7a..d9c157c 100644 --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c
@@ -265,6 +265,14 @@ return NGX_ERROR; } + if (hinit->bucket_size > 65536 - ngx_cacheline_size) { + ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, + "could not build %s, too large " + "%s_bucket_size: %i", + hinit->name, hinit->name, hinit->bucket_size); + return NGX_ERROR; + } + for (n = 0; n < nelts; n++) { if (hinit->bucket_size < NGX_HASH_ELT_SIZE(&names[n]) + sizeof(void *)) { @@ -300,17 +308,19 @@ } key = names[n].key_hash % size; - test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); + len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, - "%ui: %ui %ui \"%V\"", - size, key, test[key], &names[n].key); + "%ui: %ui %uz \"%V\"", + size, key, len, &names[n].key); #endif - if (test[key] > (u_short) bucket_size) { + if (len > bucket_size) { goto next; } + + test[key] = (u_short) len; } goto found; @@ -341,7 +351,18 @@ } key = names[n].key_hash % size; - test[key] = (u_short) (test[key] + NGX_HASH_ELT_SIZE(&names[n])); + len = test[key] + NGX_HASH_ELT_SIZE(&names[n]); + + if (len > 65536 - ngx_cacheline_size) { + ngx_log_error(NGX_LOG_EMERG, hinit->pool->log, 0, + "could not build %s, you should " + "increase %s_max_size: %i", + hinit->name, hinit->name, hinit->max_size); + ngx_free(test); + return NGX_ERROR; + } + + test[key] = (u_short) len; } len = 0;
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c index e4c343c..48f3dd7 100644 --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -55,44 +55,23 @@ unsigned redo:1; unsigned done:1; unsigned nomem:1; - unsigned gzheader:1; unsigned buffering:1; unsigned intel:1; size_t zin; size_t zout; - uint32_t crc32; z_stream zstream; ngx_http_request_t *request; } ngx_http_gzip_ctx_t; -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - -struct gztrailer { - uint32_t crc32; - uint32_t zlen; -}; - -#else /* NGX_HAVE_BIG_ENDIAN || !NGX_HAVE_NONALIGNED */ - -struct gztrailer { - u_char crc32[4]; - u_char zlen[4]; -}; - -#endif - - static void ngx_http_gzip_filter_memory(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_buffer(ngx_http_gzip_ctx_t *ctx, ngx_chain_t *in); static ngx_int_t ngx_http_gzip_filter_deflate_start(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); -static ngx_int_t ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, - ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx); static ngx_int_t ngx_http_gzip_filter_get_buf(ngx_http_request_t *r, @@ -446,12 +425,6 @@ return ctx->busy ? NGX_AGAIN : NGX_OK; } - if (!ctx->gzheader) { - if (ngx_http_gzip_filter_gzheader(r, ctx) != NGX_OK) { - goto failed; - } - } - rc = ngx_http_next_body_filter(r, ctx->out); if (rc == NGX_ERROR) { @@ -643,7 +616,7 @@ ctx->zstream.opaque = ctx; rc = deflateInit2(&ctx->zstream, (int) conf->level, Z_DEFLATED, - - ctx->wbits, ctx->memlevel, Z_DEFAULT_STRATEGY); + ctx->wbits + 16, ctx->memlevel, Z_DEFAULT_STRATEGY); if (rc != Z_OK) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, @@ -652,7 +625,6 @@ } ctx->last_out = &ctx->out; - ctx->crc32 = crc32(0L, Z_NULL, 0); ctx->flush = Z_NO_FLUSH; return NGX_OK; @@ -660,38 +632,6 @@ static ngx_int_t -ngx_http_gzip_filter_gzheader(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) -{ - ngx_buf_t *b; - ngx_chain_t *cl; - static u_char gzheader[10] = - { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; - - b = ngx_calloc_buf(r->pool); - if (b == NULL) { - return NGX_ERROR; - } - - b->memory = 1; - b->pos = gzheader; - b->last = b->pos + 10; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = ctx->out; - ctx->out = cl; - - ctx->gzheader = 1; - - return NGX_OK; -} - - -static ngx_int_t ngx_http_gzip_filter_add_data(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { ngx_chain_t *cl; @@ -743,14 +683,9 @@ } else if (ctx->in_buf->flush) { ctx->flush = Z_SYNC_FLUSH; - } - if (ctx->zstream.avail_in) { - - ctx->crc32 = crc32(ctx->crc32, ctx->zstream.next_in, - ctx->zstream.avail_in); - - } else if (ctx->flush == Z_NO_FLUSH) { + } else if (ctx->zstream.avail_in == 0) { + /* ctx->flush == Z_NO_FLUSH */ return NGX_AGAIN; } @@ -932,13 +867,11 @@ ngx_http_gzip_filter_deflate_end(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { - int rc; - ngx_buf_t *b; - ngx_chain_t *cl; - struct gztrailer *trailer; + int rc; + ngx_chain_t *cl; ctx->zin = ctx->zstream.total_in; - ctx->zout = 10 + ctx->zstream.total_out + 8; + ctx->zout = ctx->zstream.total_out; rc = deflateEnd(&ctx->zstream); @@ -960,50 +893,7 @@ *ctx->last_out = cl; ctx->last_out = &cl->next; - if (ctx->zstream.avail_out >= 8) { - trailer = (struct gztrailer *) ctx->out_buf->last; - ctx->out_buf->last += 8; - ctx->out_buf->last_buf = 1; - - } else { - b = ngx_create_temp_buf(r->pool, 8); - if (b == NULL) { - return NGX_ERROR; - } - - b->last_buf = 1; - - cl = ngx_alloc_chain_link(r->pool); - if (cl == NULL) { - return NGX_ERROR; - } - - cl->buf = b; - cl->next = NULL; - *ctx->last_out = cl; - ctx->last_out = &cl->next; - trailer = (struct gztrailer *) b->pos; - b->last += 8; - } - -#if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) - - trailer->crc32 = ctx->crc32; - trailer->zlen = ctx->zin; - -#else - - trailer->crc32[0] = (u_char) (ctx->crc32 & 0xff); - trailer->crc32[1] = (u_char) ((ctx->crc32 >> 8) & 0xff); - trailer->crc32[2] = (u_char) ((ctx->crc32 >> 16) & 0xff); - trailer->crc32[3] = (u_char) ((ctx->crc32 >> 24) & 0xff); - - trailer->zlen[0] = (u_char) (ctx->zin & 0xff); - trailer->zlen[1] = (u_char) ((ctx->zin >> 8) & 0xff); - trailer->zlen[2] = (u_char) ((ctx->zin >> 16) & 0xff); - trailer->zlen[3] = (u_char) ((ctx->zin >> 24) & 0xff); - -#endif + ctx->out_buf->last_buf = 1; ctx->zstream.avail_in = 0; ctx->zstream.avail_out = 0;
diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c index a6f45b4..4fd36f5 100644 --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1255,9 +1255,9 @@ case '-': state = ssi_error_end0_state; - ctx->param->key.data[ctx->param->key.len++] = ch; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "invalid \"%V\" parameter in \"%V\" SSI command", + "unexpected \"-\" symbol after \"%V\" " + "parameter in \"%V\" SSI command", &ctx->param->key, &ctx->command); break;
diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c index ea7ce2a..b2f107d 100644 --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -628,7 +628,7 @@ ngx_http_xslt_params(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_array_t *params, ngx_uint_t final) { - u_char *p, *last, *value, *dst, *src, **s; + u_char *p, *value, *dst, *src, **s; size_t len; ngx_uint_t i; ngx_str_t string; @@ -698,8 +698,6 @@ ngx_memcpy(p, string.data, string.len + 1); } - last = p + string.len; - while (p && *p) { value = p; @@ -729,7 +727,7 @@ *p++ = '\0'; } else { - len = last - value; + len = ngx_strlen(value); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs index 0867e2a..260f5b7 100644 --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs
@@ -15,8 +15,10 @@ #include "XSUB.h" -#define ngx_http_perl_set_request(r) \ - r = INT2PTR(ngx_http_request_t *, SvIV((SV *) SvRV(ST(0)))) +#define ngx_http_perl_set_request(r, ctx) \ + \ + ctx = INT2PTR(ngx_http_perl_ctx_t *, SvIV((SV *) SvRV(ST(0)))); \ + r = ctx->request #define ngx_http_perl_set_targ(p, len) \ @@ -64,14 +66,12 @@ static ngx_int_t -ngx_http_perl_output(ngx_http_request_t *r, ngx_buf_t *b) +ngx_http_perl_output(ngx_http_request_t *r, ngx_http_perl_ctx_t *ctx, + ngx_buf_t *b) { - ngx_chain_t out; + ngx_chain_t out; #if (NGX_HTTP_SSI) - ngx_chain_t *cl; - ngx_http_perl_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); + ngx_chain_t *cl; if (ctx->ssi) { cl = ngx_alloc_chain_link(r->pool); @@ -105,9 +105,14 @@ status(r, code) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("status(): cannot be used in variable handler"); + } r->headers_out.status = SvIV(ST(1)); @@ -121,10 +126,28 @@ send_http_header(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("send_http_header(): called after error"); + } + + if (ctx->variable) { + croak("send_http_header(): cannot be used in variable handler"); + } + + if (ctx->header_sent) { + croak("send_http_header(): header already sent"); + } + + if (ctx->redirect_uri.len) { + croak("send_http_header(): cannot be used with internal_redirect()"); + } if (r->headers_out.status == 0) { r->headers_out.status = NGX_HTTP_OK; @@ -136,20 +159,30 @@ if (ngx_http_perl_sv2str(aTHX_ r, &r->headers_out.content_type, sv) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } r->headers_out.content_type_len = r->headers_out.content_type.len; } else { if (ngx_http_set_content_type(r) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_content_type() failed"); } } + ctx->header_sent = 1; + r->disable_not_modified = 1; - (void) ngx_http_send_header(r); + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_send_header() failed"); + } void @@ -157,9 +190,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, r->header_only); @@ -172,9 +206,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->uri.data, r->uri.len); ST(0) = TARG; @@ -185,9 +220,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->args.data, r->args.len); ST(0) = TARG; @@ -198,9 +234,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->method_name.data, r->method_name.len); ST(0) = TARG; @@ -211,9 +248,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); ngx_http_perl_set_targ(r->connection->addr_text.data, r->connection->addr_text.len); @@ -226,6 +264,7 @@ dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *key; u_char *p, *lowcase_key, *value, sep; STRLEN len; @@ -237,7 +276,7 @@ ngx_http_header_t *hh; ngx_http_core_main_conf_t *cmcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); key = ST(1); @@ -251,7 +290,8 @@ lowcase_key = ngx_pnalloc(r->pool, len); if (lowcase_key == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase_key, p, len); @@ -311,7 +351,8 @@ value = ngx_pnalloc(r->pool, size); if (value == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } p = value; @@ -373,14 +414,22 @@ dXSTARG; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("has_request_body(): cannot be used in variable handler"); + } + + if (ctx->next) { + croak("has_request_body(): another handler active"); + } if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) { XSRETURN_UNDEF; } - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); ctx->next = SvRV(ST(1)); r->request_body_in_single_buf = 1; @@ -391,7 +440,14 @@ r->request_body_file_log_level = 0; } - ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ctx->error = 1; + ctx->status = rc; + ctx->next = NULL; + croak("ngx_http_read_client_request_body() failed"); + } sv_upgrade(TARG, SVt_IV); sv_setiv(TARG, 1); @@ -404,13 +460,14 @@ CODE: dXSTARG; - ngx_http_request_t *r; - u_char *p, *data; - size_t len; - ngx_buf_t *buf; - ngx_chain_t *cl; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + u_char *p, *data; + size_t len; + ngx_buf_t *buf; + ngx_chain_t *cl; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file @@ -438,7 +495,8 @@ p = ngx_pnalloc(r->pool, len); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } data = p; @@ -465,9 +523,10 @@ CODE: dXSTARG; - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); if (r->request_body == NULL || r->request_body->temp_file == NULL) { XSRETURN_UNDEF; @@ -483,42 +542,66 @@ discard_request_body(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); - ngx_http_discard_request_body(r); + if (ctx->variable) { + croak("discard_request_body(): cannot be used in variable handler"); + } + + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + ctx->error = 1; + ctx->status = rc; + croak("ngx_http_discard_request_body() failed"); + } void header_out(r, key, value) CODE: - ngx_http_request_t *r; - SV *key; - SV *value; - ngx_table_elt_t *header; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *key; + SV *value; + ngx_table_elt_t *header; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("header_out(): called after error"); + } + + if (ctx->variable) { + croak("header_out(): cannot be used in variable handler"); + } key = ST(1); value = ST(2); header = ngx_list_push(&r->headers_out.headers); if (header == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_list_push() failed"); } header->hash = 1; if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) { header->hash = 0; - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } if (header->key.len == sizeof("Content-Length") - 1 @@ -542,19 +625,19 @@ CODE: dXSTARG; - size_t root; ngx_http_request_t *r; ngx_http_perl_ctx_t *ctx; + size_t root; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); if (ctx->filename.data) { goto done; } if (ngx_http_map_uri_to_path(r, &ctx->filename, &root, 0) == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_map_uri_to_path() failed"); } ctx->filename.len--; @@ -571,15 +654,29 @@ print(r, ...) CODE: - ngx_http_request_t *r; - SV *sv; - int i; - u_char *p; - size_t size; - STRLEN len; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *sv; + int i; + u_char *p; + size_t size; + STRLEN len; + ngx_int_t rc; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("print(): called after error"); + } + + if (ctx->variable) { + croak("print(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("print(): header not sent"); + } if (items == 2) { @@ -604,7 +701,8 @@ b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->memory = 1; @@ -644,7 +742,8 @@ b = ngx_create_temp_buf(r->pool, size); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_create_temp_buf() failed"); } for (i = 1; i < items; i++) { @@ -660,7 +759,12 @@ out: - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void @@ -668,15 +772,29 @@ CODE: ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; char *filename; off_t offset; size_t bytes; + ngx_int_t rc; ngx_str_t path; ngx_buf_t *b; ngx_open_file_info_t of; ngx_http_core_loc_conf_t *clcf; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("sendfile(): called after error"); + } + + if (ctx->variable) { + croak("sendfile(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("sendfile(): header not sent"); + } filename = SvPV_nolen(ST(1)); @@ -689,19 +807,22 @@ b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); if (b->file == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pcalloc() failed"); } path.len = ngx_strlen(filename); path.data = ngx_pnalloc(r->pool, path.len + 1); if (path.data == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1); @@ -718,19 +839,23 @@ of.events = clcf->open_file_cache_events; if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_http_set_disable_symlinks() failed"); } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, filename); - XSRETURN_EMPTY; + + ctx->error = 1; + croak("ngx_open_cached_file() failed"); } if (offset == -1) { @@ -750,28 +875,53 @@ b->file->log = r->connection->log; b->file->directio = of.is_directio; - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } void flush(r) CODE: - ngx_http_request_t *r; - ngx_buf_t *b; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + ngx_int_t rc; + ngx_buf_t *b; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->error) { + croak("flush(): called after error"); + } + + if (ctx->variable) { + croak("flush(): cannot be used in variable handler"); + } + + if (!ctx->header_sent) { + croak("flush(): header not sent"); + } b = ngx_calloc_buf(r->pool); if (b == NULL) { - XSRETURN_EMPTY; + ctx->error = 1; + croak("ngx_calloc_buf() failed"); } b->flush = 1; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "$r->flush"); - (void) ngx_http_perl_output(r, b); + rc = ngx_http_perl_output(r, ctx, b); + + if (rc == NGX_ERROR) { + ctx->error = 1; + croak("ngx_http_perl_output() failed"); + } XSRETURN_EMPTY; @@ -781,29 +931,24 @@ CODE: ngx_http_request_t *r; - SV *uri; - ngx_uint_t i; ngx_http_perl_ctx_t *ctx; + SV *uri; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("internal_redirect(): cannot be used in variable handler"); + } + + if (ctx->header_sent) { + croak("internal_redirect(): header already sent"); + } uri = ST(1); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ngx_http_perl_sv2str(aTHX_ r, &ctx->redirect_uri, uri) != NGX_OK) { - XSRETURN_EMPTY; - } - - for (i = 0; i < ctx->redirect_uri.len; i++) { - if (ctx->redirect_uri.data[i] == '?') { - - ctx->redirect_args.len = ctx->redirect_uri.len - (i + 1); - ctx->redirect_args.data = &ctx->redirect_uri.data[i + 1]; - ctx->redirect_uri.len = i; - - XSRETURN_EMPTY; - } + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } @@ -811,9 +956,14 @@ allow_ranges(r) CODE: - ngx_http_request_t *r; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("allow_ranges(): cannot be used in variable handler"); + } r->allow_ranges = 1; @@ -823,13 +973,14 @@ CODE: dXSTARG; - ngx_http_request_t *r; - SV *text; - int type; - u_char *p, *dst, *src; - STRLEN len; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *text; + int type; + u_char *p, *dst, *src; + STRLEN len; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); text = ST(1); @@ -837,7 +988,8 @@ p = ngx_pnalloc(r->pool, len + 1); if (p == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } dst = p; @@ -858,16 +1010,16 @@ dXSTARG; ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; SV *name, *value; u_char *p, *lowcase; STRLEN len; ngx_str_t var, val; ngx_uint_t i, hash; ngx_http_perl_var_t *v; - ngx_http_perl_ctx_t *ctx; ngx_http_variable_value_t *vv; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); name = ST(1); @@ -886,7 +1038,8 @@ } if (ngx_http_perl_sv2str(aTHX_ r, &val, value) != NGX_OK) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_perl_sv2str() failed"); } } @@ -894,7 +1047,8 @@ lowcase = ngx_pnalloc(r->pool, len); if (lowcase == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_pnalloc() failed"); } hash = ngx_hash_strlow(lowcase, p, len); @@ -914,13 +1068,12 @@ vv = ngx_http_get_variable(r, &var, hash); if (vv == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_http_get_variable() failed"); } if (vv->not_found) { - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - if (ctx->variables) { v = ctx->variables->elts; @@ -949,13 +1102,15 @@ ctx->variables = ngx_array_create(r->pool, 1, sizeof(ngx_http_perl_var_t)); if (ctx->variables == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_create() failed"); } } v = ngx_array_push(ctx->variables); if (v == NULL) { - XSRETURN_UNDEF; + ctx->error = 1; + croak("ngx_array_push() failed"); } v->hash = hash; @@ -991,18 +1146,24 @@ CODE: ngx_http_request_t *r; - ngx_msec_t sleep; ngx_http_perl_ctx_t *ctx; + ngx_msec_t sleep; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); + + if (ctx->variable) { + croak("sleep(): cannot be used in variable handler"); + } + + if (ctx->next) { + croak("sleep(): another handler active"); + } sleep = (ngx_msec_t) SvIV(ST(1)); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl sleep: %M", sleep); - ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); - ctx->next = SvRV(ST(2)); r->connection->write->delayed = 1; @@ -1016,13 +1177,14 @@ log_error(r, err, msg) CODE: - ngx_http_request_t *r; - SV *err, *msg; - u_char *p; - STRLEN len; - ngx_err_t e; + ngx_http_request_t *r; + ngx_http_perl_ctx_t *ctx; + SV *err, *msg; + u_char *p; + STRLEN len; + ngx_err_t e; - ngx_http_perl_set_request(r); + ngx_http_perl_set_request(r, ctx); err = ST(1);
diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c index 6d3be91..f3fc629 100644 --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -43,7 +43,8 @@ static ngx_int_t ngx_http_perl_run_requires(pTHX_ ngx_array_t *requires, ngx_log_t *log); static ngx_int_t ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, - HV *nginx, SV *sub, SV **args, ngx_str_t *handler, ngx_str_t *rv); + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv); static void ngx_http_perl_eval_anon_sub(pTHX_ ngx_str_t *handler, SV **sv); static ngx_int_t ngx_http_perl_preconfiguration(ngx_conf_t *cf); @@ -183,6 +184,7 @@ SV *sub; ngx_int_t rc; ngx_str_t uri, args, *handler; + ngx_uint_t flags; ngx_http_perl_ctx_t *ctx; ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_main_conf_t *pmcf; @@ -199,6 +201,8 @@ } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); @@ -220,26 +224,20 @@ ctx->next = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sub, NULL, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sub, NULL, + handler, NULL); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler done: %i", rc); - if (rc == NGX_DONE) { - ngx_http_finalize_request(r, rc); - return; - } - if (rc > 600) { rc = NGX_OK; } if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; - args = ctx->redirect_args; } else { uri.len = 0; @@ -248,13 +246,32 @@ ctx->filename.data = NULL; ctx->redirect_uri.len = 0; + if (rc == NGX_ERROR) { + ngx_http_finalize_request(r, rc); + return; + } + if (ctx->done || ctx->next) { ngx_http_finalize_request(r, NGX_DONE); return; } if (uri.len) { - ngx_http_internal_redirect(r, &uri, &args); + if (uri.data[0] == '@') { + ngx_http_named_location(r, &uri); + + } else { + ngx_str_null(&args); + flags = NGX_HTTP_LOG_UNSAFE; + + if (ngx_http_parse_unsafe_uri(r, &uri, &args, &flags) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + ngx_http_internal_redirect(r, &uri, &args); + } + ngx_http_finalize_request(r, NGX_DONE); return; } @@ -299,6 +316,7 @@ ngx_int_t rc; ngx_str_t value; + ngx_uint_t saved; ngx_http_perl_ctx_t *ctx; ngx_http_perl_main_conf_t *pmcf; @@ -314,8 +332,13 @@ } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } + saved = ctx->variable; + ctx->variable = 1; + pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); value.data = NULL; @@ -326,7 +349,7 @@ PERL_SET_CONTEXT(pmcf->perl); PERL_SET_INTERP(pmcf->perl); - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, pv->sub, NULL, + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, pv->sub, NULL, &pv->handler, &value); } @@ -342,6 +365,7 @@ v->not_found = 1; } + ctx->variable = saved; ctx->filename.data = NULL; ctx->redirect_uri.len = 0; @@ -377,11 +401,14 @@ } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); + + ctx->request = r; } pmcf = ngx_http_get_module_main_conf(r, ngx_http_perl_module); ctx->ssi = ssi_ctx; + ctx->header_sent = 1; handler = params[NGX_HTTP_PERL_SSI_SUB]; handler->data[handler->len] = '\0'; @@ -435,8 +462,8 @@ asv = NULL; } - rc = ngx_http_perl_call_handler(aTHX_ r, pmcf->nginx, sv, asv, handler, - NULL); + rc = ngx_http_perl_call_handler(aTHX_ r, ctx, pmcf->nginx, sv, asv, + handler, NULL); SvREFCNT_dec(sv); @@ -672,8 +699,9 @@ static ngx_int_t -ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, HV *nginx, SV *sub, - SV **args, ngx_str_t *handler, ngx_str_t *rv) +ngx_http_perl_call_handler(pTHX_ ngx_http_request_t *r, + ngx_http_perl_ctx_t *ctx, HV *nginx, SV *sub, SV **args, + ngx_str_t *handler, ngx_str_t *rv) { SV *sv; int n, status; @@ -687,12 +715,15 @@ status = 0; + ctx->error = 0; + ctx->status = NGX_OK; + ENTER; SAVETMPS; PUSHMARK(sp); - sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(r))), nginx)); + sv = sv_2mortal(sv_bless(newRV_noinc(newSViv(PTR2IV(ctx))), nginx)); XPUSHs(sv); if (args) { @@ -736,6 +767,18 @@ FREETMPS; LEAVE; + if (ctx->error) { + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, + "call_sv: error, %d", ctx->status); + + if (ctx->status != NGX_OK) { + return ctx->status; + } + + return NGX_ERROR; + } + /* check $@ */ if (SvTRUE(ERRSV)) { @@ -750,6 +793,12 @@ return NGX_ERROR; } + ctx->redirect_uri.len = 0; + + if (ctx->header_sent) { + return NGX_ERROR; + } + return NGX_HTTP_INTERNAL_SERVER_ERROR; }
diff --git a/src/http/modules/perl/ngx_http_perl_module.h b/src/http/modules/perl/ngx_http_perl_module.h index d15f546..2a008b7 100644 --- a/src/http/modules/perl/ngx_http_perl_module.h +++ b/src/http/modules/perl/ngx_http_perl_module.h
@@ -25,13 +25,19 @@ typedef ngx_http_request_t *nginx; typedef struct { + ngx_http_request_t *request; + ngx_str_t filename; ngx_str_t redirect_uri; - ngx_str_t redirect_args; SV *next; - ngx_uint_t done; /* unsigned done:1; */ + ngx_int_t status; + + unsigned done:1; + unsigned error:1; + unsigned variable:1; + unsigned header_sent:1; ngx_array_t *variables; /* array of ngx_http_perl_var_t */
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c index 05ff9b0..48a0f0f 100644 --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c
@@ -3338,6 +3338,7 @@ size_t size; ssize_t n; ngx_buf_t *b; + ngx_uint_t flags; ngx_connection_t *c, *downstream, *upstream, *dst, *src; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -3476,7 +3477,14 @@ ngx_del_timer(upstream->write); } - if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { + if (upstream->read->eof || upstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -3495,7 +3503,14 @@ return; } - if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { + if (downstream->read->eof || downstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(downstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; } @@ -3567,6 +3582,7 @@ ssize_t n; ngx_buf_t *b; ngx_int_t rc; + ngx_uint_t flags; ngx_connection_t *downstream, *upstream; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -3670,7 +3686,14 @@ ngx_del_timer(downstream->write); } - if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { + if (upstream->read->eof || upstream->read->error) { + flags = NGX_CLOSE_EVENT; + + } else { + flags = 0; + } + + if (ngx_handle_read_event(upstream->read, flags) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_ERROR); return; }
diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c index 9a6b4f3..3a3a31f 100644 --- a/src/http/v2/ngx_http_v2_filter_module.c +++ b/src/http/v2/ngx_http_v2_filter_module.c
@@ -1453,6 +1453,12 @@ if (in == NULL || stream->out_closed) { + if (size) { + ngx_log_error(NGX_LOG_ERR, fc->log, 0, + "output on closed stream"); + return NGX_CHAIN_ERROR; + } + if (stream->queued) { fc->write->active = 1; fc->write->ready = 0;