# HG changeset patch # User Igor Sysoev # Date 1144180800 -14400 # Node ID 87699398f95521c2f7cdc2095611eed2ef08d47b # Parent 4a3ddd7582223a3d84e571f49d486c53d81b5f8b nginx 0.3.36 *) Feature: the ngx_http_addition_filter_module. *) Feature: the "proxy_pass" and "fastcgi_pass" directives may be used inside the "if" block. *) Feature: the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives. *) Feature: the "$request_completion" variable. *) Feature: the ngx_http_perl_module supports the $r->request_method and $r->remote_addr. *) Feature: the ngx_http_ssi_module supports the "elif" command. *) Bugfix: the "\/" string in the expression of the "if" command of the ngx_http_ssi_module was treated incorrectly. *) Bugfix: in the regular expressions in the "if" command of the ngx_http_ssi_module. *) Bugfix: if the relative path was specified in the "client_body_temp_path", "proxy_temp_path", "fastcgi_temp_path", and "perl_modules" directives, then the directory was used relatively to a current path but not to a server prefix. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,32 @@ + +Changes with nginx 0.3.36 05 Apr 2006 + + *) Feature: the ngx_http_addition_filter_module. + + *) Feature: the "proxy_pass" and "fastcgi_pass" directives may be used + inside the "if" block. + + *) Feature: the "proxy_ignore_client_abort" and + "fastcgi_ignore_client_abort" directives. + + *) Feature: the "$request_completion" variable. + + *) Feature: the ngx_http_perl_module supports the $r->request_method + and $r->remote_addr. + + *) Feature: the ngx_http_ssi_module supports the "elif" command. + + *) Bugfix: the "\/" string in the expression of the "if" command of the + ngx_http_ssi_module was treated incorrectly. + + *) Bugfix: in the regular expressions in the "if" command of the + ngx_http_ssi_module. + + *) Bugfix: if the relative path was specified in the + "client_body_temp_path", "proxy_temp_path", "fastcgi_temp_path", and + "perl_modules" directives, then the directory was used relatively to + a current path but not to a server prefix. + Changes with nginx 0.3.35 22 Mar 2006 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,32 @@ + +Изменения в nginx 0.3.36 05.04.2006 + + *) Добавление: модуль ngx_http_addition_filter_module. + + *) Добавление: директивы proxy_pass и fastcgi_pass можно использовать + внутри блока if. + + *) Добавление: директивы proxy_ignore_client_abort и + fastcgi_ignore_client_abort. + + *) Добавление: переменная $request_completion. + + *) Добавление: модуль ngx_http_perl_module поддерживает методы + $r->request_method и $r->remote_addr. + + *) Добавление: модуль ngx_http_ssi_module поддерживает команду elif. + + *) Исправление: строка "\/" в начале выражения команды if модуля + ngx_http_ssi_module воспринималась неверно. + + *) Исправление: в использовании регулярных выражениях в команде if + модуля ngx_http_ssi_module. + + *) Исправление: при задании относительного пути в директивах + client_body_temp_path, proxy_temp_path, fastcgi_temp_path и + perl_modules использовался каталог относительно текущего каталога, а + не относительно префикса сервера. + Изменения в nginx 0.3.35 22.03.2006 @@ -19,7 +48,7 @@ fastcgi_next_upstream. *) Исправление: ngx_http_perl_module не работал со встроенным в - конфигурацинный файл кодом, если он не начинался сразу же с "sub". + конфигурационный файл кодом, если он не начинался сразу же с "sub". *) Исправление: в директиве post_action. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -78,6 +78,7 @@ fi # ngx_http_postpone_filter # ngx_http_charset_filter # ngx_http_ssi_filter +# ngx_http_addition_filter # ngx_http_userid_filter # ngx_http_headers_filter # ngx_http_copy_filter @@ -114,6 +115,11 @@ if [ $HTTP_SSI = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_SSI_SRCS" fi +if [ $HTTP_ADDITION = YES ]; then + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_ADDITION_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_ADDITION_SRCS" +fi + if [ $HTTP_USERID = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_USERID_FILTER_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_USERID_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -52,6 +52,7 @@ HTTP_SSL=NO HTTP_SSI=YES HTTP_POSTPONE=NO HTTP_REALIP=NO +HTTP_ADDITION=NO HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_USERID=YES @@ -139,6 +140,7 @@ do --with-http_ssl_module) HTTP_SSL=YES ;; --with-http_realip_module) HTTP_REALIP=YES ;; + --with-http_addition_module) HTTP_ADDITION=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; --without-http_ssi_module) HTTP_SSI=NO ;; diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -59,7 +59,7 @@ fi # sendfile() -CC_AUX_FLAGS="-D_GNU_SOURCE" +CC_AUX_FLAGS="$CC_AUX_FLAGS -D_GNU_SOURCE" ngx_feature="sendfile()" ngx_feature_name="NGX_HAVE_SENDFILE" ngx_feature_run=yes @@ -79,7 +79,7 @@ fi # sendfile64() -CC_AUX_FLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" +CC_AUX_FLAGS="$CC_AUX_FLAGS -D_FILE_OFFSET_BITS=64" ngx_feature="sendfile64()" ngx_feature_name="NGX_HAVE_SENDFILE64" ngx_feature_run=yes diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -319,6 +319,10 @@ HTTP_REALIP_MODULE=ngx_http_realip_modul HTTP_REALIP_SRCS=src/http/modules/ngx_http_realip_module.c +HTTP_ADDITION_FILTER_MODULE=ngx_http_addition_filter_module +HTTP_ADDITION_SRCS=src/http/modules/ngx_http_addition_filter_module.c + + HTTP_ACCESS_MODULE=ngx_http_access_module HTTP_ACCESS_SRCS=src/http/modules/ngx_http_access_module.c diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.3.35" +#define NGINX_VER "nginx/0.3.36" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -63,6 +63,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t char *rv; ngx_fd_t fd; ngx_int_t rc; + ngx_buf_t *b; ngx_uint_t block; ngx_conf_file_t *prev; @@ -95,11 +96,23 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t ngx_fd_info_n " \"%s\" failed", filename->data); } - cf->conf_file->buffer = ngx_create_temp_buf(cf->pool, ngx_pagesize); - if (cf->conf_file->buffer == NULL) { + b = ngx_calloc_buf(cf->pool); + if (b == NULL) { return NGX_CONF_ERROR; } + cf->conf_file->buffer = b; + + b->start = ngx_alloc(ngx_pagesize, cf->log); + if (b->start == NULL) { + return NGX_CONF_ERROR; + } + + b->pos = b->start; + b->last = b->start; + b->end = b->last + ngx_pagesize; + b->temporary = 1; + cf->conf_file->file.fd = fd; cf->conf_file->file.name.len = filename->len; cf->conf_file->file.name.data = filename->data; @@ -183,7 +196,7 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t if (filename) { - ngx_pfree(cf->pool, cf->conf_file->buffer->start); + ngx_free(cf->conf_file->buffer->start); cf->conf_file = prev; diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -211,8 +211,8 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n char *p = conf; ssize_t level; + ngx_str_t *value; ngx_uint_t i, n; - ngx_str_t *value; ngx_path_t *path, **slot; slot = (ngx_path_t **) (p + cmd->offset); @@ -229,6 +229,11 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, n value = cf->args->elts; path->name = value[1]; + + if (ngx_conf_full_name(cf->cycle, &path->name) == NGX_ERROR) { + return NULL; + } + path->len = 0; path->cleaner = (ngx_gc_handler_pt) cmd->post; path->conf_file = cf->conf_file->file.name.data; diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c --- a/src/core/ngx_palloc.c +++ b/src/core/ngx_palloc.c @@ -86,7 +86,7 @@ ngx_palloc(ngx_pool_t *pool, size_t size { u_char *m; ngx_pool_t *p, *n; - ngx_pool_large_t *large, *last; + ngx_pool_large_t *large; if (size <= (size_t) NGX_MAX_ALLOC_FROM_POOL && size <= (size_t) (pool->end - (u_char *) pool) @@ -134,34 +134,6 @@ ngx_palloc(ngx_pool_t *pool, size_t size return m; } - /* allocate a large block */ - - large = NULL; - last = NULL; - - if (pool->large) { - for (last = pool->large; /* void */ ; last = last->next) { - if (last->alloc == NULL) { - large = last; - last = NULL; - break; - } - - if (last->next == NULL) { - break; - } - } - } - - if (large == NULL) { - large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); - if (large == NULL) { - return NULL; - } - - large->next = NULL; - } - #if 0 p = ngx_memalign(ngx_pagesize, size, pool->log); if (p == NULL) { @@ -174,14 +146,14 @@ ngx_palloc(ngx_pool_t *pool, size_t size } #endif - if (pool->large == NULL) { - pool->large = large; - - } else if (last) { - last->next = large; + large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); + if (large == NULL) { + return NULL; } large->alloc = p; + large->next = pool->large; + pool->large = large; return p; } diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -0,0 +1,228 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_str_t before_body; + ngx_str_t after_body; +} ngx_http_addition_conf_t; + + +typedef struct { + unsigned before_body_sent:1; + unsigned after_body_sent:1; +} ngx_http_addition_ctx_t; + + +static ngx_int_t ngx_http_addition_filter_init(ngx_cycle_t *cycle); +static void *ngx_http_addition_create_conf(ngx_conf_t *cf); +static char *ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, + void *child); + + +static ngx_command_t ngx_http_addition_commands[] = { + + { ngx_string("add_before_body"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_addition_conf_t, before_body), + NULL }, + + { ngx_string("add_after_body"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_addition_conf_t, after_body), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_addition_filter_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_addition_create_conf, /* create location configuration */ + ngx_http_addition_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_addition_filter_module = { + NGX_MODULE_V1, + &ngx_http_addition_filter_module_ctx, /* module context */ + ngx_http_addition_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + ngx_http_addition_filter_init, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +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 +ngx_http_addition_header_filter(ngx_http_request_t *r) +{ + ngx_http_addition_ctx_t *ctx; + ngx_http_addition_conf_t *conf; + + if (r->headers_out.status != NGX_HTTP_OK || r != r->main) { + return ngx_http_next_header_filter(r); + } + + if (ngx_strncasecmp(r->headers_out.content_type.data, "text/html", + sizeof("text/html") - 1) + != 0) + { + return ngx_http_next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module); + + if (conf->before_body.len == 0 && conf->after_body.len == 0) { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_addition_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_addition_filter_module); + + ngx_http_clear_content_length(r); + ngx_http_clear_accept_ranges(r); + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_addition_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_uint_t last; + ngx_chain_t *cl; + ngx_http_addition_ctx_t *ctx; + ngx_http_addition_conf_t *conf; + + if (in == NULL || r->header_only) { + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_addition_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_addition_filter_module); + + if (!ctx->before_body_sent) { + ctx->before_body_sent = 1; + + if (conf->before_body.len) { + if (ngx_http_subrequest(r, &conf->before_body, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + } + } + + last = 0; + + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf) { + cl->buf->last_buf = 0; + last = 1; + } + } + + rc = ngx_http_next_body_filter(r, in); + + if (rc == NGX_ERROR + || !last + || ctx->after_body_sent + || conf->after_body.len == 0) + { + return rc; + } + + if (ngx_http_subrequest(r, &conf->after_body, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + + ctx->after_body_sent = 1; + + return ngx_http_send_special(r, NGX_HTTP_LAST); +} + + +static ngx_int_t +ngx_http_addition_filter_init(ngx_cycle_t *cycle) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_addition_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_addition_body_filter; + + return NGX_OK; +} + + +static void * +ngx_http_addition_create_conf(ngx_conf_t *cf) +{ + ngx_http_addition_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_addition_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->before_body.len = 0; + * conf->before_body.date = NULL; + * conf->after_body.len = 0; + * conf->after_body.date = NULL; + */ + + return conf; +} + + +static char * +ngx_http_addition_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_addition_conf_t *prev = parent; + ngx_http_addition_conf_t *conf = child; + + ngx_conf_merge_str_value(conf->before_body, prev->before_body, ""); + ngx_conf_merge_str_value(conf->after_body, prev->after_body, ""); + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_chunked_filter_module.c b/src/http/modules/ngx_http_chunked_filter_module.c --- a/src/http/modules/ngx_http_chunked_filter_module.c +++ b/src/http/modules/ngx_http_chunked_filter_module.c @@ -23,7 +23,7 @@ static ngx_http_module_t ngx_http_chunk NULL, /* merge server configuration */ NULL, /* create location configuration */ - NULL, /* merge location configuration */ + NULL /* merge location configuration */ }; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -170,7 +170,7 @@ static ngx_conf_bitmask_t ngx_http_fast static ngx_command_t ngx_http_fastcgi_commands[] = { { ngx_string("fastcgi_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_http_fastcgi_pass, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -183,6 +183,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, index), NULL }, + { ngx_string("fastcgi_ignore_client_abort"), + 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_fastcgi_loc_conf_t, upstream.ignore_client_abort), + NULL }, + { ngx_string("fastcgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -1470,6 +1477,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con */ conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.ignore_client_abort = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -1520,6 +1528,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, + prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -1670,6 +1681,7 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf if (conf->peers == NULL) { conf->peers = prev->peers; + conf->upstream.schema = prev->upstream.schema; } if (conf->params_source == NULL) { diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -517,6 +517,8 @@ ngx_http_memcached_create_loc_conf(ngx_c conf->upstream.cyclic_temp_file = 0; /* the hardcoded values */ + conf->upstream.buffering = 0; + conf->upstream.ignore_client_abort = 0; conf->upstream.send_lowat = 0; conf->upstream.bufs.num = 0; conf->upstream.busy_buffers_size = 0; diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -130,7 +130,7 @@ static ngx_conf_bitmask_t ngx_http_prox static ngx_command_t ngx_http_proxy_commands[] = { { ngx_string("proxy_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_http_proxy_pass, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -150,6 +150,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.buffering), NULL }, + { ngx_string("proxy_ignore_client_abort"), + 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_proxy_loc_conf_t, upstream.ignore_client_abort), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -1415,6 +1422,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ */ conf->upstream.buffering = NGX_CONF_UNSET; + conf->upstream.ignore_client_abort = NGX_CONF_UNSET; conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; conf->upstream.send_timeout = NGX_CONF_UNSET_MSEC; @@ -1468,6 +1476,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); + ngx_conf_merge_value(conf->upstream.ignore_client_abort, + prev->upstream.ignore_client_abort, 0); + ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -1654,6 +1665,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t if (conf->peers == NULL) { conf->peers = prev->peers; + + conf->host_header = prev->host_header; + conf->port_text = prev->port_text; + conf->upstream.schema = prev->upstream.schema; } @@ -2057,11 +2072,12 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ #if (NGX_PCRE) - if (clcf->regex) { + if (clcf->regex || clcf->noname) { if (plcf->upstream.uri.len) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_pass\" may not have URI part in " - "location given by regular expression"); + "location given by regular expression or " + "inside the \"if\" statement"); return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -13,6 +13,7 @@ #define NGX_HTTP_SSI_DATE_LEN 2048 #define NGX_HTTP_SSI_ADD_PREFIX 1 +#define NGX_HTTP_SSI_ADD_ZERO 2 typedef struct { @@ -247,8 +248,12 @@ static ngx_http_ssi_command_t ngx_http_ { ngx_string("set"), ngx_http_ssi_set, ngx_http_ssi_set_params, 0, 0 }, { ngx_string("if"), ngx_http_ssi_if, ngx_http_ssi_if_params, 0, 0 }, - { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, 1, 0 }, - { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, 1, 0 }, + { ngx_string("elif"), ngx_http_ssi_if, ngx_http_ssi_if_params, + NGX_HTTP_SSI_COND_IF, 0 }, + { ngx_string("else"), ngx_http_ssi_else, ngx_http_ssi_no_params, + NGX_HTTP_SSI_COND_IF, 0 }, + { ngx_string("endif"), ngx_http_ssi_endif, ngx_http_ssi_no_params, + NGX_HTTP_SSI_COND_ELSE, 0 }, { ngx_null_string, NULL, NULL, 0, 0 } }; @@ -523,7 +528,17 @@ ngx_http_ssi_body_filter(ngx_http_reques continue; } - if (!ctx->output && !cmd->conditional) { + if (cmd->conditional + && (ctx->conditional == 0 + || ctx->conditional > cmd->conditional)) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "invalid context of SSI command: \"%V\"", + &ctx->command); + goto ssi_error; + } + + if (!ctx->output && cmd->conditional == 0) { continue; } @@ -926,6 +941,7 @@ ngx_http_ssi_parse(ngx_http_request_t *r ctx->key = ngx_hash(ctx->key, ch); ctx->params.nelts = 0; + state = ssi_command_state; break; } @@ -1565,7 +1581,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re } } - p = ngx_palloc(r->pool, len); + p = ngx_palloc(r->pool, len + ((flags & NGX_HTTP_SSI_ADD_ZERO) ? 1 : 0)); if (p == NULL) { return NGX_ERROR; } @@ -1809,13 +1825,26 @@ ngx_http_ssi_if(ngx_http_request_t *r, n u_char *p, *last; ngx_str_t *expr, left, right; ngx_int_t rc; - ngx_uint_t negative, noregex; + ngx_uint_t negative, noregex, flags; #if (NGX_PCRE) ngx_str_t err; ngx_regex_t *regex; u_char errstr[NGX_MAX_CONF_ERRSTR]; #endif + if (ctx->command.len == 2) { + if (ctx->conditional) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the \"if\" command inside the \"if\" command"); + return NGX_HTTP_SSI_ERROR; + } + } + + if (ctx->output_chosen) { + ctx->output = 0; + return NGX_OK; + } + expr = params[NGX_HTTP_SSI_IF_EXPR]; left.data = expr->data; @@ -1857,11 +1886,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, n if (p == last) { if (left.len) { ctx->output = 1; + ctx->output_chosen = 1; } else { ctx->output = 0; } + ctx->conditional = NGX_HTTP_SSI_COND_IF; + return NGX_OK; } @@ -1887,11 +1919,17 @@ ngx_http_ssi_if(ngx_http_request_t *r, n } noregex = 0; + flags = NGX_HTTP_SSI_ADD_ZERO; last--; p++; } else { noregex = 1; + flags = 0; + + if (p < last - 1 && p[0] == '\\' && p[1] == '/') { + p++; + } } right.len = last - p; @@ -1900,7 +1938,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "right: \"%V\"", &right); - if (ngx_http_ssi_evaluate_string(r, ctx, &right, 0) != NGX_OK) { + if (ngx_http_ssi_evaluate_string(r, ctx, &right, flags) != NGX_OK) { return NGX_HTTP_SSI_ERROR; } @@ -1948,11 +1986,14 @@ ngx_http_ssi_if(ngx_http_request_t *r, n if ((rc == 0 && !negative) || (rc != 0 && negative)) { ctx->output = 1; + ctx->output_chosen = 1; } else { ctx->output = 0; } + ctx->conditional = NGX_HTTP_SSI_COND_IF; + return NGX_OK; invalid_expression: @@ -1968,7 +2009,13 @@ static ngx_int_t ngx_http_ssi_else(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx, ngx_str_t **params) { - ctx->output = !ctx->output; + if (ctx->output_chosen) { + ctx->output = 0; + } else { + ctx->output = 1; + } + + ctx->conditional = NGX_HTTP_SSI_COND_ELSE; return NGX_OK; } @@ -1979,6 +2026,8 @@ ngx_http_ssi_endif(ngx_http_request_t *r ngx_str_t **params) { ctx->output = 1; + ctx->output_chosen = 0; + ctx->conditional = 0; return NGX_OK; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.h b/src/http/modules/ngx_http_ssi_filter_module.h --- a/src/http/modules/ngx_http_ssi_filter_module.h +++ b/src/http/modules/ngx_http_ssi_filter_module.h @@ -20,6 +20,10 @@ #define NGX_HTTP_SSI_PARAMS_N 4 +#define NGX_HTTP_SSI_COND_IF 1 +#define NGX_HTTP_SSI_COND_ELSE 2 + + typedef struct { ngx_hash_t hash; ngx_hash_keys_arrays_t commands; @@ -54,7 +58,9 @@ typedef struct { ngx_array_t variables; - ngx_uint_t output; /* unsigned output:1; */ + unsigned conditional:2; + unsigned output:1; + unsigned output_chosen:1; void *value_buf; ngx_str_t timefmt; @@ -80,7 +86,7 @@ typedef struct { ngx_http_ssi_command_pt handler; ngx_http_ssi_param_t *params; - unsigned conditional:1; + unsigned conditional:2; unsigned flush:1; } ngx_http_ssi_command_t; diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -178,6 +178,35 @@ args(r, ...) char * +request_method(r) + nginx r + + CODE: + + RETVAL = ngx_palloc(r->pool, r->method_name.len + 1); + if (RETVAL == NULL) { + XSRETURN_UNDEF; + } + + ngx_cpystrn((u_char *) RETVAL, r->method_name.data, r->method_name.len + 1); + + OUTPUT: + RETVAL + + +char * +remote_addr(r) + nginx r + + CODE: + + RETVAL = (char *) r->connection->addr_text.data; + + OUTPUT: + RETVAL + + +char * header_in(r, key) nginx r SV *key diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -39,6 +39,7 @@ static ngx_int_t ngx_http_perl_ssi(ngx_h ngx_http_ssi_ctx_t *ssi_ctx, ngx_str_t **params); #endif +static void ngx_http_perl_handle_request(ngx_http_request_t *r); static ngx_int_t ngx_http_perl_get_interpreter(ngx_http_perl_main_conf_t *pmcf, PerlInterpreter **perl, ngx_log_t *log); @@ -174,23 +175,39 @@ ngx_http_perl_xs_init(pTHX) static ngx_int_t ngx_http_perl_handler(ngx_http_request_t *r) { + ngx_int_t rc; + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_HTTP_NOT_FOUND; + } + + rc = ngx_http_read_client_request_body(r, ngx_http_perl_handle_request); + + if (rc >= NGX_HTTP_SPECIAL_RESPONSE) { + return rc; + } + + return NGX_DONE; +} + + +static void +ngx_http_perl_handle_request(ngx_http_request_t *r) +{ ngx_int_t rc; ngx_str_t uri, args; ngx_http_perl_ctx_t *ctx; ngx_http_perl_loc_conf_t *plcf; ngx_http_perl_main_conf_t *pmcf; - /* TODO: Win32 */ - if (r->zero_in_uri) { - return NGX_HTTP_NOT_FOUND; - } - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "perl handler"); /* mod_perl's content handler assumes that content type was already set */ if (ngx_http_set_content_type(r) != NGX_OK) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; } ctx = ngx_http_get_module_ctx(r, ngx_http_perl_module); @@ -198,7 +215,8 @@ ngx_http_perl_handler(ngx_http_request_t if (ctx == NULL) { ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t)); if (ctx == NULL) { - return NGX_ERROR; + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); @@ -209,7 +227,8 @@ ngx_http_perl_handler(ngx_http_request_t rc = ngx_http_perl_get_interpreter(pmcf, &ctx->perl, r->connection->log); if (rc != NGX_OK) { - return rc; + ngx_http_finalize_request(r, rc); + return; } { @@ -235,20 +254,24 @@ ngx_http_perl_handler(ngx_http_request_t if (ctx->redirect_uri.len) { uri = ctx->redirect_uri; args = ctx->redirect_args; + + } else { + uri.len = 0; } ctx->filename = NULL; ctx->redirect_uri.len = 0; if (uri.len) { - return ngx_http_internal_redirect(r, &uri, &args); + ngx_http_internal_redirect(r, &uri, &args); + return; } if (rc == NGX_OK || rc == NGX_HTTP_OK) { - return ngx_http_send_special(r, NGX_HTTP_LAST); + ngx_http_send_special(r, NGX_HTTP_LAST); } - return rc; + ngx_http_finalize_request(r, rc); } @@ -448,6 +471,10 @@ ngx_http_perl_init_interpreter(ngx_conf_ } #endif + if (ngx_conf_full_name(cf->cycle, &pmcf->modules) != NGX_OK) { + return NGX_CONF_ERROR; + } + PERL_SYS_INIT(&ngx_argc, &ngx_argv); pmcf->perl = ngx_http_perl_create_interpreter(pmcf, cf->log); diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1503,6 +1503,10 @@ ngx_http_finalize_request(ngx_http_reque return; } + if (!r->post_action) { + r->request_complete = 1; + } + if (ngx_http_post_action(r) == NGX_OK) { return; } @@ -2254,6 +2258,7 @@ ngx_http_post_action(ngx_http_request_t r->http_version = NGX_HTTP_VERSION_9; r->header_only = 1; + r->post_action = 1; ngx_http_internal_redirect(r, &clcf->post_action, NULL); diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -405,6 +405,8 @@ struct ngx_http_request_s { unsigned lingering_close:1; unsigned discard_body:1; unsigned internal:1; + unsigned post_action:1; + unsigned request_complete:1; unsigned done:1; unsigned utf8:1; diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -277,9 +277,9 @@ ngx_http_upstream_init(ngx_http_request_ ngx_del_timer(c->read); } - if (!(r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) { - /* not a post_action */ - + u = r->upstream; + + if (!r->post_action && !u->conf->ignore_client_abort) { r->read_event_handler = ngx_http_upstream_rd_check_broken_connection; r->write_event_handler = ngx_http_upstream_wr_check_broken_connection; } @@ -296,8 +296,6 @@ ngx_http_upstream_init(ngx_http_request_ } } - u = r->upstream; - if (r->request_body) { u->request_bufs = r->request_body->bufs; } @@ -1208,10 +1206,7 @@ ngx_http_upstream_send_response(ngx_http rc = ngx_http_send_header(r); - if (rc == NGX_ERROR - || rc > NGX_OK - /* post_action */ - || (r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) { + if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) { ngx_http_upstream_finalize_request(r, u, rc); return; } @@ -1947,11 +1942,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; - if (rc == 0 - && r == r->main - /* not a post_action */ - && !(r->http_version == NGX_HTTP_VERSION_9 && r->header_only)) - { + if (rc == 0 && r == r->main && !r->post_action) { rc = ngx_http_send_special(r, NGX_HTTP_LAST); } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -73,6 +73,7 @@ typedef struct { ngx_flag_t pass_request_headers; ngx_flag_t pass_request_body; + ngx_flag_t ignore_client_abort; ngx_flag_t redirect_errors; ngx_flag_t cyclic_temp_file; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -44,6 +44,8 @@ static ngx_int_t ngx_http_variable_remot ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_body_bytes_sent(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_completion(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); /* @@ -135,6 +137,9 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("body_bytes_sent"), ngx_http_variable_body_bytes_sent, 0, 0, 0 }, + { ngx_string("request_completion"), ngx_http_variable_request_completion, + 0, 0, 0 }, + { ngx_null_string, NULL, 0, 0, 0 } }; @@ -798,6 +803,30 @@ ngx_http_variable_body_bytes_sent(ngx_ht } +static ngx_int_t +ngx_http_variable_request_completion(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + if (r->request_complete) { + v->len = 2; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = (u_char *) "OK"; + + return NGX_OK; + } + + v->len = 0; + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + v->data = (u_char *) ""; + + return NGX_OK; +} + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) {