# HG changeset patch # User Igor Sysoev # Date 1241121600 -14400 # Node ID ed5e10fb40fc02b64d6c5719141e33f74cccd02a # Parent 0a2f4b42ddad8c24ebba02e140a94765d909eb39 nginx 0.7.54 *) Feature: the ngx_http_image_filter_module. *) Feature: the "proxy_ignore_headers" and "fastcgi_ignore_headers" directives. *) Bugfix: a segmentation fault might occur in worker process, if an "open_file_cache_errors off" directive was used; the bug had appeared in 0.7.53. *) Bugfix: the "port_in_redirect off" directive did not work; the bug had appeared in 0.7.39. *) Bugfix: improve handling of "select" method errors. *) Bugfix: of "select() failed (10022: ...)" error in nginx/Windows. *) Bugfix: in error text descriptions in nginx/Windows; the bug had appeared in 0.7.53. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,26 @@ +Changes with nginx 0.7.54 01 May 2009 + + *) Feature: the ngx_http_image_filter_module. + + *) Feature: the "proxy_ignore_headers" and "fastcgi_ignore_headers" + directives. + + *) Bugfix: a segmentation fault might occur in worker process, if an + "open_file_cache_errors off" directive was used; the bug had + appeared in 0.7.53. + + *) Bugfix: the "port_in_redirect off" directive did not work; the bug + had appeared in 0.7.39. + + *) Bugfix: improve handling of "select" method errors. + + *) Bugfix: of "select() failed (10022: ...)" error in nginx/Windows. + + *) Bugfix: in error text descriptions in nginx/Windows; the bug had + appeared in 0.7.53. + + Changes with nginx 0.7.53 27 Apr 2009 *) Change: now a log set by --error-log-path is created from the very diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,25 @@ +Изменения в nginx 0.7.54 01.05.2009 + + *) Добавление: модуль ngx_http_image_filter_module. + + *) Добавление: директивы proxy_ignore_headers и fastcgi_ignore_headers. + + *) Исправление: при использовании переменных "open_file_cache_errors + on" в рабочем процессе мог произойти segmentation fault; ошибка + появилась в 0.7.53. + + *) Исправление: директива "port_in_redirect off" не работала; ошибка + появилась в 0.7.39. + + *) Исправление: улучшение обработки ошибок метода select. + + *) Исправление: ошибки "select() failed (10022: ...)" в nginx/Windows. + + *) Исправление: в текстовых сообщениях об ошибках в nginx/Windows; + ошибка появилась в 0.7.53. + + Изменения в nginx 0.7.53 27.04.2009 *) Изменение: теперь лог, указанный в --error-log-path, создаётся с diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -45,6 +45,10 @@ if [ $USE_LIBXSLT = YES ]; then . auto/lib/libxslt/conf fi +if [ $USE_LIBGD = YES ]; then + . auto/lib/libgd/conf +fi + if [ $USE_PERL = YES ]; then . auto/lib/perl/conf fi diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf new file mode 100644 --- /dev/null +++ b/auto/lib/libgd/conf @@ -0,0 +1,81 @@ + +# Copyright (C) Igor Sysoev + + + ngx_feature="GD library" + ngx_feature_name= + ngx_feature_run=no + ngx_feature_incs="#include " + ngx_feature_path= + ngx_feature_libs="-lgd" + ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);" + . auto/feature + + +if [ $ngx_found = no ]; then + + # FreeBSD port + + ngx_feature="GD library in /usr/local/" + ngx_feature_path="/usr/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lgd" + else + ngx_feature_libs="-L/usr/local/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # NetBSD port + + ngx_feature="GD library in /usr/pkg/" + ngx_feature_path="/usr/pkg/include/" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lgd" + else + ngx_feature_libs="-L/usr/pkg/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = no ]; then + + # MacPorts + + ngx_feature="GD library in /opt/local/" + ngx_feature_path="/opt/local/include" + + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lgd" + else + ngx_feature_libs="-L/opt/local/lib -lgd" + fi + + . auto/feature +fi + + +if [ $ngx_found = yes ]; then + + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" + +else + +cat << END + +$0: error: the HTTP image filter module requires the GD library. +You can either do not enable the module or install the libraries. + +END + + exit 1 + +fi diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -104,6 +104,7 @@ fi # ngx_http_charset_filter # ngx_http_ssi_filter # ngx_http_xslt_filter +# ngx_http_image_filter_filter # ngx_http_sub_filter # ngx_http_addition_filter # ngx_http_userid_filter @@ -148,6 +149,12 @@ if [ $HTTP_XSLT = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_XSLT_SRCS" fi +if [ $HTTP_IMAGE_FILTER = YES ]; then + USE_LIBGD=YES + HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_IMAGE_FILTER_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_IMAGE_SRCS" +fi + if [ $HTTP_SUB = YES ]; then HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES $HTTP_SUB_FILTER_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_SUB_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -60,6 +60,7 @@ HTTP_SSI=YES HTTP_POSTPONE=NO HTTP_REALIP=NO HTTP_XSLT=NO +HTTP_IMAGE_FILTER=NO HTTP_SUB=NO HTTP_ADDITION=NO HTTP_DAV=NO @@ -123,6 +124,7 @@ USE_PERL=NO NGX_PERL=perl USE_LIBXSLT=NO +USE_LIBGD=NO NGX_GOOGLE_PERFTOOLS=NO NGX_CPP_TEST=NO @@ -181,6 +183,7 @@ do --with-http_realip_module) HTTP_REALIP=YES ;; --with-http_addition_module) HTTP_ADDITION=YES ;; --with-http_xslt_module) HTTP_XSLT=YES ;; + --with-http_image_filter_module) HTTP_IMAGE_FILTER=YES ;; --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -328,6 +328,10 @@ HTTP_XSLT_FILTER_MODULE=ngx_http_xslt_fi HTTP_XSLT_SRCS=src/http/modules/ngx_http_xslt_filter_module.c +HTTP_IMAGE_FILTER_MODULE=ngx_http_image_filter_module +HTTP_IMAGE_SRCS=src/http/modules/ngx_http_image_filter_module.c + + HTTP_SUB_FILTER_MODULE=ngx_http_sub_filter_module HTTP_SUB_SRCS=src/http/modules/ngx_http_sub_filter_module.c diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -213,7 +213,7 @@ main(int argc, char *const *argv) if (ngx_show_help) { ngx_log_stderr(0, "Usage: nginx [-?hvVt] [-s signal] [-c filename] " - "[-g directives]" CRLF CRLF + "[-p prefix] [-g directives]" CRLF CRLF "Options:" CRLF " -?,-h : this help" CRLF " -v : show version and exit" CRLF diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 7053 -#define NGINX_VERSION "0.7.53" +#define nginx_version 7054 +#define NGINX_VERSION "0.7.54" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -61,6 +61,7 @@ static ngx_uint_t argument_number[] = { char * ngx_conf_param(ngx_conf_t *cf) { + char *rv; ngx_str_t *param; ngx_buf_t b; ngx_conf_file_t conf_file; @@ -82,13 +83,17 @@ ngx_conf_param(ngx_conf_t *cf) b.temporary = 1; conf_file.file.fd = NGX_INVALID_FILE; - conf_file.file.name.data = (u_char *) "command line"; - conf_file.line = 1; + conf_file.file.name.data = NULL; + conf_file.line = 0; cf->conf_file = &conf_file; cf->conf_file->buffer = &b; - return ngx_conf_parse(cf, NULL); + rv = ngx_conf_parse(cf, NULL); + + cf->conf_file = NULL; + + return rv; } @@ -853,7 +858,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n full.data = NULL; #endif - if (name && name->len) { + if (name->len) { full = *name; if (ngx_conf_full_name(cycle, &full, 0) != NGX_OK) { @@ -889,14 +894,13 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n return NULL; } - if (name && name->len) { + if (name->len) { file->fd = NGX_INVALID_FILE; file->name = full; } else { file->fd = ngx_stderr; - file->name.len = 0; - file->name.data = NULL; + file->name = *name; } file->buffer = NULL; @@ -961,31 +965,11 @@ ngx_conf_log_error(ngx_uint_t level, ngx last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); - p = ngx_vsnprintf(errstr, last - errstr, fmt, args); + p = ngx_vslprintf(errstr, last, fmt, args); va_end(args); if (err) { - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } - -#if (NGX_WIN32) - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); -#else - p = ngx_snprintf(p, last - p, " (%d: ", err); -#endif - - p = ngx_strerror_r(err, p, last - p); - - *p++ = ')'; + p = ngx_log_errno(p, last, err); } if (cf->conf_file == NULL) { @@ -993,6 +977,12 @@ ngx_conf_log_error(ngx_uint_t level, ngx return; } + if (cf->conf_file->file.fd == NGX_INVALID_FILE) { + ngx_log_error(level, cf->log, 0, "%*s in command line", + p - errstr, errstr); + return; + } + ngx_log_error(level, cf->log, 0, "%*s in %s:%ui", p - errstr, errstr, cf->conf_file->file.name.data, cf->conf_file->line); diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -248,6 +248,8 @@ ngx_open_listening_sockets(ngx_cycle_t * continue; } + ls[i].log = *ls[i].logp; + if (ls[i].inherited) { /* TODO: close on exit */ @@ -801,7 +803,14 @@ ngx_connection_error(ngx_connection_t *c { ngx_uint_t level; - if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) { + /* Winsock may return NGX_ECONNABORTED instead of NGX_ECONNRESET */ + + if ((err == NGX_ECONNRESET +#if (NGX_WIN32) + || err == NGX_ECONNABORTED +#endif + ) && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) + { return 0; } @@ -813,7 +822,9 @@ ngx_connection_error(ngx_connection_t *c if (err == 0 || err == NGX_ECONNRESET -#if !(NGX_WIN32) +#if (NGX_WIN32) + || err == NGX_ECONNABORTED +#else || err == NGX_EPIPE #endif || err == NGX_ENOTCONN diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -34,6 +34,7 @@ struct ngx_listening_s { void *servers; /* array of ngx_http_in_addr_t, for example */ ngx_log_t log; + ngx_log_t *logp; size_t pool_size; /* should be here because of the AcceptEx() preread */ diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -82,6 +82,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) cycle->pool = pool; cycle->log = log; + cycle->new_log.log_level = NGX_LOG_ERR; cycle->old_cycle = old_cycle; cycle->conf_prefix.len = old_cycle->conf_prefix.len; @@ -165,14 +166,6 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) return NULL; } - - cycle->new_log = ngx_log_create_errlog(cycle, &error_log); - if (cycle->new_log == NULL) { - ngx_destroy_pool(pool); - return NULL; - } - - n = old_cycle->listening.nelts ? old_cycle->listening.nelts : 10; cycle->listening.elts = ngx_pcalloc(pool, n * sizeof(ngx_listening_t)); @@ -336,6 +329,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) } + if (cycle->new_log.file == NULL) { + cycle->new_log.file = ngx_conf_open_file(cycle, &error_log); + if (cycle->new_log.file == NULL) { + goto failed; + } + } + /* open the new files */ part = &cycle->open_files.part; @@ -382,12 +382,8 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) #endif } - cycle->log = cycle->new_log; - pool->log = cycle->new_log; - - if (cycle->log->log_level == 0) { - cycle->log->log_level = NGX_LOG_ERR; - } + cycle->log = &cycle->new_log; + pool->log = &cycle->new_log; /* create shared memory */ @@ -1126,7 +1122,9 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx 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) == -1) { + if (ngx_file_info((const char *) 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_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -38,7 +38,7 @@ struct ngx_cycle_s { ngx_pool_t *pool; ngx_log_t *log; - ngx_log_t *new_log; + ngx_log_t new_log; ngx_connection_t **files; ngx_connection_t *free_connections; 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 @@ -489,7 +489,9 @@ ngx_create_pathes(ngx_cycle_t *cycle, ng { ngx_file_info_t fi; - if (ngx_file_info((const char *) path[i]->name.data, &fi) == -1) { + if (ngx_file_info((const char *) 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_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -8,14 +8,14 @@ #include -static char *ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static ngx_command_t ngx_errlog_commands[] = { {ngx_string("error_log"), NGX_MAIN_CONF|NGX_CONF_1MORE, - ngx_set_error_log, + ngx_error_log, 0, 0, NULL}, @@ -53,7 +53,7 @@ ngx_uint_t ngx_use_stderr = static ngx_str_t err_levels[] = { - ngx_string("stderr"), + ngx_null_string, ngx_string("emerg"), ngx_string("alert"), ngx_string("crit"), @@ -101,14 +101,14 @@ ngx_log_error_core(ngx_uint_t level, ngx p = errstr + ngx_cached_err_log_time.len; - p = ngx_snprintf(p, last - p, " [%V] ", &err_levels[level]); + p = ngx_slprintf(p, last, " [%V] ", &err_levels[level]); /* pid#tid */ - p = ngx_snprintf(p, last - p, "%P#" NGX_TID_T_FMT ": ", + p = ngx_slprintf(p, last, "%P#" NGX_TID_T_FMT ": ", ngx_log_pid, ngx_log_tid); if (log->connection) { - p = ngx_snprintf(p, last - p, "*%uA ", log->connection); + p = ngx_slprintf(p, last, "*%uA ", log->connection); } msg = p; @@ -116,39 +116,17 @@ ngx_log_error_core(ngx_uint_t level, ngx #if (NGX_HAVE_VARIADIC_MACROS) va_start(args, fmt); - p = ngx_vsnprintf(p, last - p, fmt, args); + p = ngx_vslprintf(p, last, fmt, args); va_end(args); #else - p = ngx_vsnprintf(p, last - p, fmt, args); + p = ngx_vslprintf(p, last, fmt, args); #endif if (err) { - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } - -#if (NGX_WIN32) - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); -#else - p = ngx_snprintf(p, last - p, " (%d: ", err); -#endif - - p = ngx_strerror_r(err, p, last - p); - - if (p < last) { - *p++ = ')'; - } + p = ngx_log_errno(p, last, err); } if (level != NGX_LOG_DEBUG && log->handler) { @@ -174,7 +152,7 @@ ngx_log_error_core(ngx_uint_t level, ngx (void) ngx_sprintf(msg, "[%V]: ", &err_levels[level]); - (void) ngx_write_fd(ngx_stderr, msg, p - msg); + (void) ngx_write_console(ngx_stderr, msg, p - msg); } @@ -230,45 +208,53 @@ ngx_log_stderr(ngx_err_t err, const char va_list args; u_char errstr[NGX_MAX_ERROR_STR]; - va_start(args, fmt); - p = ngx_vsnprintf(errstr, NGX_MAX_ERROR_STR, fmt, args); - va_end(args); + last = errstr + NGX_MAX_ERROR_STR; - if (p > errstr + NGX_MAX_ERROR_STR - NGX_LINEFEED_SIZE) { - p = errstr + NGX_MAX_ERROR_STR - NGX_LINEFEED_SIZE; - } + va_start(args, fmt); + p = ngx_vslprintf(errstr, last, fmt, args); + va_end(args); if (err) { - - last = errstr + NGX_MAX_ERROR_STR; - - if (p > last - 50) { - - /* leave a space for an error code */ - - p = last - 50; - *p++ = '.'; - *p++ = '.'; - *p++ = '.'; - } + p = ngx_log_errno(p, last, err); + } -#if (NGX_WIN32) - p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000) - ? " (%d: " : " (%Xd: ", err); -#else - p = ngx_snprintf(p, last - p, " (%d: ", err); -#endif - - p = ngx_strerror_r(err, p, last - p); - - if (p < last) { - *p++ = ')'; - } + if (p > last - NGX_LINEFEED_SIZE) { + p = last - NGX_LINEFEED_SIZE; } ngx_linefeed(p); - (void) ngx_write_fd(ngx_stderr, errstr, p - errstr); + (void) ngx_write_console(ngx_stderr, errstr, p - errstr); +} + + +u_char * +ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err) +{ + if (buf > last - 50) { + + /* leave a space for an error code */ + + buf = last - 50; + *buf++ = '.'; + *buf++ = '.'; + *buf++ = '.'; + } + +#if (NGX_WIN32) + buf = ngx_slprintf(buf, last, ((unsigned) err < 0x80000000) + ? " (%d: " : " (%Xd: ", err); +#else + buf = ngx_slprintf(buf, last, " (%d: ", err); +#endif + + buf = ngx_strerror_r(err, buf, last - buf); + + if (buf < last) { + *buf++ = ')'; + } + + return buf; } @@ -302,15 +288,16 @@ ngx_log_init(u_char *prefix) #else if (name[0] != '/') { #endif - plen = 0; if (prefix) { plen = ngx_strlen(prefix); + } else { #ifdef NGX_PREFIX - } else { prefix = (u_char *) NGX_PREFIX; plen = ngx_strlen(prefix); +#else + plen = 0; #endif } @@ -358,7 +345,7 @@ ngx_log_init(u_char *prefix) ngx_log_t * -ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_str_t *name) +ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name) { ngx_log_t *log; @@ -377,7 +364,7 @@ ngx_log_create_errlog(ngx_cycle_t *cycle char * -ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log) +ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log) { ngx_uint_t i, n, d; ngx_str_t *value; @@ -422,10 +409,7 @@ ngx_set_error_log_levels(ngx_conf_t *cf, } } - if (log->log_level == 0) { - log->log_level = NGX_LOG_ERR; - - } else if (log->log_level == NGX_LOG_DEBUG) { + if (log->log_level == NGX_LOG_DEBUG) { log->log_level = NGX_LOG_DEBUG_ALL; } @@ -434,26 +418,35 @@ ngx_set_error_log_levels(ngx_conf_t *cf, static char * -ngx_set_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +ngx_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_str_t *value; + ngx_str_t *value, name; + + if (cf->cycle->new_log.file) { + return "is duplicate"; + } value = cf->args->elts; - if (value[1].len == 6 && ngx_strcmp(value[1].data, "stderr") == 0) { - cf->cycle->new_log->file->fd = ngx_stderr; - cf->cycle->new_log->file->name.len = 0; - cf->cycle->new_log->file->name.data = NULL; + if (ngx_strcmp(value[1].data, "stderr") == 0) { + name.len = 0; + name.data = NULL; } else { - cf->cycle->new_log->file->name = value[1]; + name = value[1]; + } - if (ngx_conf_full_name(cf->cycle, &cf->cycle->new_log->file->name, 0) - != NGX_OK) - { - return NGX_CONF_ERROR; - } + cf->cycle->new_log.file = ngx_conf_open_file(cf->cycle, &name); + if (cf->cycle->new_log.file == NULL) { + return NULL; } - return ngx_set_error_log_levels(cf, cf->cycle->new_log); + if (cf->args->nelts == 2) { + cf->cycle->new_log.log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + + cf->cycle->new_log.log_level = 0; + + return ngx_log_set_levels(cf, &cf->cycle->new_log); } diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -196,10 +196,11 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo /*********************************/ ngx_log_t *ngx_log_init(u_char *prefix); -ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_str_t *name); -char *ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log); +ngx_log_t *ngx_log_create(ngx_cycle_t *cycle, ngx_str_t *name); +char *ngx_log_set_levels(ngx_conf_t *cf, ngx_log_t *log); void ngx_cdecl ngx_log_abort(ngx_err_t err, const char *fmt, ...); void ngx_cdecl ngx_log_stderr(ngx_err_t err, const char *fmt, ...); +u_char *ngx_log_errno(u_char *buf, u_char *last, ngx_err_t err); extern ngx_module_t ngx_errlog_module; diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -143,7 +143,7 @@ ngx_open_cached_file(ngx_open_file_cache if (of->test_only) { - if (ngx_file_info(name->data, &fi) == -1) { + if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { of->err = ngx_errno; of->failed = ngx_file_info_n; return NGX_ERROR; @@ -234,6 +234,7 @@ ngx_open_cached_file(ngx_open_file_cache } else { of->err = file->err; + of->failed = ngx_open_file_n; } goto found; @@ -463,7 +464,7 @@ ngx_open_and_stat_file(u_char *name, ngx if (of->fd != NGX_INVALID_FILE) { - if (ngx_file_info(name, &fi) == -1) { + if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { of->failed = ngx_file_info_n; goto failed; } @@ -474,7 +475,7 @@ ngx_open_and_stat_file(u_char *name, ngx } else if (of->test_dir) { - if (ngx_file_info(name, &fi) == -1) { + if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { of->failed = ngx_file_info_n; goto failed; } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -131,14 +131,14 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ r->event->handler = ngx_resolver_resend_handler; r->event->data = r; - r->event->log = cf->cycle->new_log; + r->event->log = &cf->cycle->new_log; r->ident = -1; r->resend_timeout = 5; r->expire = 30; r->valid = 300; - r->log = cf->cycle->new_log; + r->log = &cf->cycle->new_log; r->log_level = NGX_LOG_ALERT; if (addr) { @@ -152,7 +152,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ uc->sockaddr = addr->sockaddr; uc->socklen = addr->socklen; uc->server = addr->name; - uc->log = cf->cycle->new_log; + uc->log = &cf->cycle->new_log; } return r; diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -99,7 +99,7 @@ ngx_sprintf(u_char *buf, const char *fmt va_list args; va_start(args, fmt); - p = ngx_vsnprintf(buf, /* STUB */ 65536, fmt, args); + p = ngx_vslprintf(buf, (void *) -1, fmt, args); va_end(args); return p; @@ -113,7 +113,21 @@ ngx_snprintf(u_char *buf, size_t max, co va_list args; va_start(args, fmt); - p = ngx_vsnprintf(buf, max, fmt, args); + p = ngx_vslprintf(buf, buf + max, fmt, args); + va_end(args); + + return p; +} + + +u_char * ngx_cdecl +ngx_slprintf(u_char *buf, u_char *last, const char *fmt, ...) +{ + u_char *p; + va_list args; + + va_start(args, fmt); + p = ngx_vslprintf(buf, last, fmt, args); va_end(args); return p; @@ -121,9 +135,9 @@ ngx_snprintf(u_char *buf, size_t max, co u_char * -ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args) +ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args) { - u_char *p, zero, *last; + u_char *p, zero; int d; float f, scale; size_t len, slen; @@ -134,12 +148,6 @@ ngx_vsnprintf(u_char *buf, size_t max, c ngx_str_t *v; ngx_variable_value_t *vv; - if (max == 0) { - return buf; - } - - last = buf + max; - while (*fmt && buf < last) { /* diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -140,7 +140,11 @@ u_char *ngx_cpystrn(u_char *dst, u_char u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src); u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...); u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...); -u_char *ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args); +u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt, + ...); +u_char *ngx_vslprintf(u_char *buf, u_char *last, const char *fmt, va_list args); +#define ngx_vsnprintf(buf, max, fmt, args) \ + ngx_vslprintf(buf, buf + (max), fmt, args) ngx_int_t ngx_strcasecmp(u_char *s1, u_char *s2); ngx_int_t ngx_strncasecmp(u_char *s1, u_char *s2, size_t n); diff --git a/src/event/modules/ngx_select_module.c b/src/event/modules/ngx_select_module.c --- a/src/event/modules/ngx_select_module.c +++ b/src/event/modules/ngx_select_module.c @@ -18,6 +18,7 @@ static ngx_int_t ngx_select_del_event(ng ngx_uint_t flags); static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags); +static void ngx_select_repair_fd_sets(ngx_cycle_t *cycle); static char *ngx_select_init_conf(ngx_cycle_t *cycle, void *conf); @@ -248,12 +249,12 @@ static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags) { - int ready, nready; - ngx_uint_t i, found; - ngx_err_t err; - ngx_event_t *ev, **queue; - ngx_connection_t *c; - struct timeval tv, *tp; + int ready, nready; + ngx_err_t err; + ngx_uint_t i, found; + ngx_event_t *ev, **queue; + struct timeval tv, *tp; + ngx_connection_t *c; #if !(NGX_WIN32) @@ -302,19 +303,23 @@ ngx_select_process_events(ngx_cycle_t *c work_read_fd_set = master_read_fd_set; work_write_fd_set = master_write_fd_set; -#if 1 - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, - /* - * (void *) disables "dereferencing type-punned - * pointer will break strict-aliasing rules - */ - "select read fd_set: %08Xd", - *(int *) (void *) &work_read_fd_set); -#endif - #if (NGX_WIN32) - ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + if (max_read || max_write) { + ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp); + + } else { + + /* + * Winsock select() requires that at least one descriptor set must be + * be non-null, and any non-null descriptor set must contain at least + * one handle to a socket. Otherwise select() returns WSAEINVAL. + */ + + ngx_msleep(timer); + + ready = 0; + } #else @@ -339,6 +344,11 @@ ngx_select_process_events(ngx_cycle_t *c if (err) { ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed"); + + if (err == WSAENOTSOCK) { + ngx_select_repair_fd_sets(cycle); + } + return NGX_ERROR; } @@ -361,6 +371,11 @@ ngx_select_process_events(ngx_cycle_t *c } ngx_log_error(level, cycle->log, err, "select() failed"); + + if (err == EBADF) { + ngx_select_repair_fd_sets(cycle); + } + return NGX_ERROR; } @@ -414,13 +429,101 @@ ngx_select_process_events(ngx_cycle_t *c ngx_mutex_unlock(ngx_posted_events_mutex); if (ready != nready) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events"); + ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, + "select ready != events: %d:%d", ready, nready); + + ngx_select_repair_fd_sets(cycle); } return NGX_OK; } +static void +ngx_select_repair_fd_sets(ngx_cycle_t *cycle) +{ + int n; + socklen_t len; + ngx_err_t err; + ngx_socket_t s; + +#if (NGX_WIN32) + u_int i; + + for (i = 0; i < master_read_fd_set.fd_count; i++) { + + s = master_read_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in read fd_set", s); + + FD_CLR(s, &master_read_fd_set); + } + } + + for (i = 0; i < master_write_fd_set.fd_count; i++) { + + s = master_write_fd_set.fd_array[i]; + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, (char *) &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in write fd_set", s); + + FD_CLR(s, &master_write_fd_set); + } + } + +#else + + for (s = 0; s <= max_fd; s++) { + + if (FD_ISSET(s, &master_read_fd_set) == 0) { + continue; + } + + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in read fd_set", s); + + FD_CLR(s, &master_read_fd_set); + } + } + + for (s = 0; s <= max_fd; s++) { + + if (FD_ISSET(s, &master_write_fd_set) == 0) { + continue; + } + + len = sizeof(int); + + if (getsockopt(s, SOL_SOCKET, SO_TYPE, &n, &len) == -1) { + err = ngx_socket_errno; + + ngx_log_error(NGX_LOG_ALERT, cycle->log, err, + "invalid descriptor #%d in write fd_set", s); + + FD_CLR(s, &master_write_fd_set); + } + } + + max_fd = -1; + +#endif +} + + static char * ngx_select_init_conf(ngx_cycle_t *cycle, void *conf) { diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -776,6 +776,10 @@ ngx_event_process_init(ngx_cycle_t *cycl rev->handler = ngx_event_acceptex; + if (ngx_use_accept_mutex) { + continue; + } + if (ngx_add_event(rev, 0, NGX_IOCP_ACCEPT) == NGX_ERROR) { return NGX_ERROR; } @@ -792,6 +796,10 @@ ngx_event_process_init(ngx_cycle_t *cycl } else { rev->handler = ngx_event_accept; + if (ngx_use_accept_mutex) { + continue; + } + if (ngx_add_event(rev, NGX_READ_EVENT, 0) == NGX_ERROR) { return NGX_ERROR; } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -1306,7 +1306,7 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_ last = errstr + NGX_MAX_CONF_ERRSTR; va_start(args, fmt); - p = ngx_vsnprintf(errstr, sizeof(errstr) - 1, fmt, args); + p = ngx_vslprintf(errstr, last - 1, fmt, args); va_end(args); p = ngx_cpystrn(p, (u_char *) " (SSL:", last - p); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -221,7 +221,7 @@ ngx_http_dav_put_handler(ngx_http_reques temp = &r->request_body->temp_file->file.name; - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { status = NGX_HTTP_CREATED; } else { @@ -326,7 +326,7 @@ ok: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http delete filename: \"%s\"", path.data); - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; rc = (err == NGX_ENOTDIR) ? NGX_HTTP_CONFLICT : NGX_HTTP_NOT_FOUND; @@ -678,7 +678,7 @@ overwrite_done: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http copy to: \"%s\"", copy.path.data); - if (ngx_file_info(copy.path.data, &fi) == -1) { + if (ngx_file_info(copy.path.data, &fi) == NGX_FILE_ERROR) { err = ngx_errno; if (err != NGX_ENOENT) { @@ -712,7 +712,7 @@ overwrite_done: dir = ngx_is_dir(&fi); } - if (ngx_file_info(path.data, &fi) == -1) { + if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) { return ngx_http_dav_error(r->connection->log, ngx_errno, NGX_HTTP_NOT_FOUND, ngx_file_info_n, path.data); 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 @@ -183,6 +183,15 @@ static ngx_conf_bitmask_t ngx_http_fast }; +static ngx_conf_bitmask_t ngx_http_fastcgi_ignore_headers_masks[] = { + { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT }, + { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES }, + { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, + { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, + { ngx_null_string, 0 } +}; + + ngx_module_t ngx_http_fastcgi_module; @@ -409,6 +418,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers), NULL }, + { ngx_string("fastcgi_ignore_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_headers), + &ngx_http_fastcgi_ignore_headers_masks }, + { ngx_string("fastcgi_catch_stderr"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_str_array_slot, @@ -1817,6 +1833,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * set by ngx_pcalloc(): * * conf->upstream.bufs.num = 0; + * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; * conf->upstream.use_stale_cache = 0; * conf->upstream.temp_path = NULL; @@ -2012,6 +2029,11 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf } + ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, + prev->upstream.ignore_headers, + NGX_CONF_BITMASK_SET); + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, prev->upstream.next_upstream, (NGX_CONF_BITMASK_SET diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -0,0 +1,1026 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include "gd.h" + + +#define NGX_HTTP_IMAGE_OFF 0 +#define NGX_HTTP_IMAGE_TEST 1 +#define NGX_HTTP_IMAGE_SIZE 2 +#define NGX_HTTP_IMAGE_RESIZE 3 +#define NGX_HTTP_IMAGE_CROP 4 + + +#define NGX_HTTP_IMAGE_START 0 +#define NGX_HTTP_IMAGE_READ 1 +#define NGX_HTTP_IMAGE_PROCESS 2 +#define NGX_HTTP_IMAGE_DONE 3 + + +#define NGX_HTTP_IMAGE_NONE 0 +#define NGX_HTTP_IMAGE_JPEG 1 +#define NGX_HTTP_IMAGE_GIF 2 +#define NGX_HTTP_IMAGE_PNG 3 + + +#define NGX_HTTP_IMAGE_BUFFERED 0x08 + + +typedef struct { + ngx_uint_t filter; + ngx_uint_t width; + ngx_uint_t height; + + size_t buffer_size; +} ngx_http_image_filter_conf_t; + + +typedef struct { + u_char *image; + u_char *last; + + size_t length; + + ngx_uint_t width; + ngx_uint_t height; + + ngx_uint_t phase; + ngx_uint_t type; +} ngx_http_image_filter_ctx_t; + + +static ngx_uint_t ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in); +static ngx_int_t ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in); +static ngx_buf_t *ngx_http_image_process(ngx_http_request_t *r); +static ngx_buf_t *ngx_http_image_json(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static ngx_buf_t *ngx_http_image_asis(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static void ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b); +static ngx_int_t ngx_http_image_size(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); + +static ngx_buf_t *ngx_http_image_resize(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static gdImagePtr ngx_http_image_source(ngx_http_request_t *r, + ngx_http_image_filter_ctx_t *ctx); +static gdImagePtr ngx_http_image_new(ngx_http_request_t *r, int w, int h, + int colors); +static u_char *ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, + gdImagePtr img, int *size); +static void ngx_http_image_cleanup(void *data); + + +static void *ngx_http_image_filter_create_conf(ngx_conf_t *cf); +static char *ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static ngx_int_t ngx_http_image_filter_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_image_filter_commands[] = { + + { ngx_string("image_filter"), + NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13, + ngx_http_image_filter, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("image_filter_buffer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_image_filter_conf_t, buffer_size), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_image_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_image_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_image_filter_create_conf, /* create location configuration */ + ngx_http_image_filter_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_image_filter_module = { + NGX_MODULE_V1, + &ngx_http_image_filter_module_ctx, /* module context */ + ngx_http_image_filter_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_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_str_t ngx_http_image_types[] = { + ngx_string("image/jpeg"), + ngx_string("image/gif"), + ngx_string("image/png") +}; + + +static ngx_int_t +ngx_http_image_header_filter(ngx_http_request_t *r) +{ + off_t len; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + if (r->headers_out.status == NGX_HTTP_NOT_MODIFIED) { + return ngx_http_next_header_filter(r); + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (conf->filter == NGX_HTTP_IMAGE_OFF) { + return ngx_http_next_header_filter(r); + } + + if (r->headers_out.content_type.len + >= sizeof("multipart/x-mixed-replace") - 1 + && ngx_strncasecmp(r->headers_out.content_type.data, + (u_char *) "multipart/x-mixed-replace", + sizeof("multipart/x-mixed-replace") - 1) + == 0) + { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "image filter: multipart/x-mixed-replace response"); + + return NGX_ERROR; + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_image_filter_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_image_filter_module); + + len = r->headers_out.content_length_n; + + if (len != -1 && len > conf->buffer_size) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "image filter: too big response: %O", len); + + return NGX_ERROR; + } + + if (len == -1) { + ctx->length = conf->buffer_size; + + } else { + ctx->length = (size_t) len; + } + + if (r->headers_out.refresh) { + r->headers_out.refresh->hash = 0; + } + + r->main_filter_need_in_memory = 1; + r->allow_ranges = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_image_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_str_t *ct; + ngx_chain_t out; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "image filter"); + + if (in == NULL) { + return ngx_http_next_body_filter(r, in); + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + switch (ctx->phase) { + + case NGX_HTTP_IMAGE_START: + + ctx->type = ngx_http_image_test(r, in); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (ctx->type == NGX_HTTP_IMAGE_NONE) { + + if (conf->filter == NGX_HTTP_IMAGE_SIZE) { + out.buf = ngx_http_image_json(r, NULL); + + if (out.buf) { + out.next = NULL; + in = &out; + + break; + } + } + + return ngx_http_filter_finalize_request(r, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + /* override content type */ + + ct = &ngx_http_image_types[ctx->type - 1]; + r->headers_out.content_type_len = ct->len; + r->headers_out.content_type = *ct; + + if (conf->filter == NGX_HTTP_IMAGE_TEST) { + break; + } + + ctx->phase = NGX_HTTP_IMAGE_READ; + + /* fall through */ + + case NGX_HTTP_IMAGE_READ: + + rc = ngx_http_image_read(r, in); + + if (rc == NGX_AGAIN) { + return NGX_OK; + } + + if (rc == NGX_ERROR) { + return ngx_http_filter_finalize_request(r, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + /* fall through */ + + case NGX_HTTP_IMAGE_PROCESS: + + out.buf = ngx_http_image_process(r); + + if (out.buf == NULL) { + return ngx_http_filter_finalize_request(r, + NGX_HTTP_UNSUPPORTED_MEDIA_TYPE); + } + + out.next = NULL; + in = &out; + + break; + + default: /* NGX_HTTP_IMAGE_DONE */ + + return ngx_http_next_body_filter(r, in); + } + + ctx->phase = NGX_HTTP_IMAGE_DONE; + + rc = ngx_http_next_header_filter(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return ngx_http_next_body_filter(r, in); +} + + +static ngx_uint_t +ngx_http_image_test(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *p; + + p = in->buf->pos; + + if (in->buf->last - p < 16) { + return NGX_HTTP_IMAGE_NONE; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image filter: \"%c%c\"", p[0], p[1]); + + if (p[0] == 0xff && p[1] == 0xd8) { + + /* JPEG */ + + return NGX_HTTP_IMAGE_JPEG; + + } else if (p[0] == 'G' && p[1] == 'I' && p[2] == 'F' && p[3] == '8' + && p[4] == '9' && p[5] == 'a') + { + /* GIF */ + + return NGX_HTTP_IMAGE_GIF; + + } else if (p[0] == 0x89 && p[1] == 'P' && p[2] == 'N' && p[3] == 'G' + && p[4] == 0x0d && p[5] == 0x0a && p[6] == 0x1a && p[7] == 0x0a) + { + /* PNG */ + + return NGX_HTTP_IMAGE_PNG; + } + + return NGX_HTTP_IMAGE_NONE; +} + + +static ngx_int_t +ngx_http_image_read(ngx_http_request_t *r, ngx_chain_t *in) +{ + u_char *p; + size_t size, rest; + ngx_buf_t *b; + ngx_chain_t *cl; + ngx_http_image_filter_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + if (ctx->image == NULL) { + ctx->image = ngx_palloc(r->pool, ctx->length); + if (ctx->image == NULL) { + return NGX_ERROR; + } + + ctx->last = ctx->image; + } + + p = ctx->last; + + for (cl = in; cl; cl = cl->next) { + + b = cl->buf; + size = b->last - b->pos; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image buf: %uz", size); + + rest = ctx->image + ctx->length - p; + size = (rest < size) ? rest : size; + + p = ngx_cpymem(p, b->pos, size); + b->pos += size; + + if (b->last_buf) { + ctx->last = p; + return NGX_OK; + } + } + + ctx->last = p; + r->connection->buffered |= NGX_HTTP_IMAGE_BUFFERED; + + return NGX_AGAIN; +} + + +static ngx_buf_t * +ngx_http_image_process(ngx_http_request_t *r) +{ + ngx_buf_t *b; + ngx_int_t rc; + ngx_http_image_filter_ctx_t *ctx; + ngx_http_image_filter_conf_t *conf; + + r->connection->buffered &= ~NGX_HTTP_IMAGE_BUFFERED; + + ctx = ngx_http_get_module_ctx(r, ngx_http_image_filter_module); + + rc = ngx_http_image_size(r, ctx); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if (conf->filter == NGX_HTTP_IMAGE_SIZE) { + + b = ngx_http_image_json(r, rc == NGX_OK ? ctx : NULL); + + } else if (rc == NGX_OK + && ctx->width <= conf->width + && ctx->height <= conf->height) + { + b = ngx_http_image_asis(r, ctx); + + } else { + b = ngx_http_image_resize(r, ctx); + } + + return b; +} + + +static ngx_buf_t * +ngx_http_image_json(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + size_t len; + ngx_buf_t *b; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + + b->memory = 1; + b->last_buf = 1; + + ngx_http_clean_header(r); + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_type.len = sizeof("text/plain") - 1; + r->headers_out.content_type.data = (u_char *) "text/plain"; + + if (ctx == NULL) { + b->pos = (u_char *) "{}" CRLF; + b->last = b->pos + sizeof("{}" CRLF) - 1; + + ngx_http_image_length(r, b); + + return b; + } + + len = sizeof("{ \"img\" : " + "{ \"width\": , \"height\": , \"type\": \"jpeg\" } }" CRLF) - 1 + + 2 * NGX_SIZE_T_LEN; + + b->pos = ngx_pnalloc(r->pool, len); + if (b->pos == NULL) { + return NULL; + } + + b->last = ngx_sprintf(b->pos, + "{ \"img\" : " + "{ \"width\": %uz," + " \"height\": %uz," + " \"type\": \"%s\" } }" CRLF, + ctx->width, ctx->height, + ngx_http_image_types[ctx->type - 1].data + 6); + + ngx_http_image_length(r, b); + + return b; +} + + +static ngx_buf_t * +ngx_http_image_asis(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + ngx_buf_t *b; + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NULL; + } + + b->pos = ctx->image; + b->last = ctx->last; + b->memory = 1; + b->last_buf = 1; + + ngx_http_image_length(r, b); + + return b; +} + + +static void +ngx_http_image_length(ngx_http_request_t *r, ngx_buf_t *b) +{ + r->headers_out.content_length_n = b->last - b->pos; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + } + + r->headers_out.content_length = NULL; +} + + +static ngx_int_t +ngx_http_image_size(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + u_char *p, *last; + ngx_uint_t width, height; + + p = ctx->image; + + switch (ctx->type) { + + case NGX_HTTP_IMAGE_JPEG: + + p += 2; + last = ctx->image + ctx->length - 10; + + while (p < last) { + + if (p[0] == 0xff && p[1] != 0xff) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "JPEG: %02xd %02xd", *p, *(p + 1)); + + p++; + + if (*p == 0xc0 || *p == 0xc1 || *p == 0xc2 || *p == 0xc3 + || *p == 0xc9 || *p == 0xca || *p == 0xcb) + { + goto found; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "JPEG: %02xd %02xd", p[1], p[2]); + + p += p[1] * 256 + p[2]; + + continue; + } + + p++; + } + + return NGX_DECLINED; + + found: + + width = p[6] * 256 + p[7]; + height = p[4] * 256 + p[5]; + + break; + + case NGX_HTTP_IMAGE_GIF: + + if (ctx->length < 10) { + return NGX_DECLINED; + } + + width = p[7] * 256 + p[6]; + height = p[9] * 256 + p[8]; + + break; + + case NGX_HTTP_IMAGE_PNG: + + if (ctx->length < 24) { + return NGX_DECLINED; + } + + width = p[18] * 256 + p[19]; + height = p[22] * 256 + p[23]; + + break; + + default: + + return NGX_DECLINED; + } + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image size: %d x %d", width, height); + + ctx->width = width; + ctx->height = height; + + return NGX_OK; +} + + +static ngx_buf_t * +ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + int sx, sy, dx, dy, ox, oy, + colors, transparent, size; + u_char *out; + ngx_buf_t *b; + ngx_uint_t resize; + gdImagePtr src, dst; + ngx_pool_cleanup_t *cln; + ngx_http_image_filter_conf_t *conf; + + src = ngx_http_image_source(r, ctx); + + if (src == NULL) { + return NULL; + } + + sx = gdImageSX(src); + sy = gdImageSY(src); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_image_filter_module); + + if ((ngx_uint_t) sx <= conf->width && (ngx_uint_t) sy <= conf->height) { + gdImageDestroy(src); + return ngx_http_image_asis(r, ctx); + } + + colors = gdImageColorsTotal(src); + transparent = gdImageGetTransparent(src); + + dx = sx; + dy = sy; + + if (conf->filter == NGX_HTTP_IMAGE_RESIZE) { + + if ((ngx_uint_t) dx > conf->width) { + dy = dy * conf->width / dx; + dy = dy ? dy : 1; + dx = conf->width; + } + + if ((ngx_uint_t) dy > conf->height) { + dx = dx * conf->height / dy; + dx = dx ? dx : 1; + dy = conf->height; + } + + resize = 1; + + } else { /* NGX_HTTP_IMAGE_CROP */ + + resize = 0; + + if ((ngx_uint_t) (dx * 100 / dy) < conf->width * 100 / conf->height) { + + if ((ngx_uint_t) dx > conf->width) { + dy = dy * conf->width / dx; + dy = dy ? dy : 1; + dx = conf->width; + resize = 1; + } + + } else { + if ((ngx_uint_t) dy > conf->height) { + dx = dx * conf->height / dy; + dx = dx ? dx : 1; + dy = conf->height; + resize = 1; + } + } + } + + if (resize) { + dst = ngx_http_image_new(r, dx, dy, colors); + if (dst == NULL) { + gdImageDestroy(src); + return NULL; + } + + gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy); + + gdImageDestroy(src); + + } else { + dst = src; + } + + if (conf->filter == NGX_HTTP_IMAGE_CROP) { + + src = dst; + + if ((ngx_uint_t) dx > conf->width) { + ox = dx - conf->width; + + } else { + ox = 0; + } + + if ((ngx_uint_t) dy > conf->height) { + oy = dy - conf->height; + + } else { + oy = 0; + } + + if (ox || oy) { + + dst = ngx_http_image_new(r, dx - ox, dy - oy, colors); + + if (dst == NULL) { + gdImageDestroy(src); + return NULL; + } + + ox /= 2; + oy /= 2; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image crop: %d x %d @ %d x %d", + dx, dy, ox, oy); + + gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy); + + gdImageDestroy(src); + } + } + + gdImageColorTransparent(dst, transparent); + + out = ngx_http_image_out(r, ctx->type, dst, &size); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "image: %d x %d %d", sx, sy, colors); + + gdImageDestroy(dst); + ngx_pfree(r->pool, ctx->image); + + if (out == NULL) { + return NULL; + } + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + gdFree(out); + return NULL; + } + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + gdFree(out); + return NULL; + } + + cln->handler = ngx_http_image_cleanup; + cln->data = out; + + b->pos = out; + b->last = out + size; + b->memory = 1; + b->last_buf = 1; + + ngx_http_image_length(r, b); + + return b; +} + + +static gdImagePtr +ngx_http_image_source(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx) +{ + char *failed; + gdImagePtr img; + + img = NULL; + + switch (ctx->type) { + + case NGX_HTTP_IMAGE_JPEG: + img = gdImageCreateFromJpegPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromJpegPtr() failed"; + break; + + case NGX_HTTP_IMAGE_GIF: + img = gdImageCreateFromGifPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromGifPtr() failed"; + break; + + case NGX_HTTP_IMAGE_PNG: + img = gdImageCreateFromPngPtr(ctx->length, ctx->image); + failed = "gdImageCreateFromPngPtr() failed"; + break; + + default: + failed = "unknown image type"; + break; + } + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed); + } + + return img; +} + + +static gdImagePtr +ngx_http_image_new(ngx_http_request_t *r, int w, int h, int colors) +{ + gdImagePtr img; + + if (colors == 0) { + img = gdImageCreateTrueColor(w, h); + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "gdImageCreateTrueColor() failed"); + return NULL; + } + + } else { + img = gdImageCreate(w, h); + + if (img == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "gdImageCreate() failed"); + return NULL; + } + } + + return img; +} + + +static u_char * +ngx_http_image_out(ngx_http_request_t *r, ngx_uint_t type, gdImagePtr img, + int *size) +{ + char *failed; + u_char *out; + + out = NULL; + + switch (type) { + + case NGX_HTTP_IMAGE_JPEG: + out = gdImageJpegPtr(img, size, /* default quality */ -1); + failed = "gdImageJpegPtr() failed"; + break; + + case NGX_HTTP_IMAGE_GIF: + out = gdImageGifPtr(img, size); + failed = "gdImageGifPtr() failed"; + break; + + case NGX_HTTP_IMAGE_PNG: + out = gdImagePngPtr(img, size); + failed = "gdImagePngPtr() failed"; + break; + + default: + failed = "unknown image type"; + break; + } + + if (out == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, failed); + } + + return out; +} + + +static void +ngx_http_image_cleanup(void *data) +{ + gdFree(data); +} + + +static void * +ngx_http_image_filter_create_conf(ngx_conf_t *cf) +{ + ngx_http_image_filter_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_image_filter_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->filter = NGX_CONF_UNSET_UINT; + conf->buffer_size = NGX_CONF_UNSET_SIZE; + + return conf; +} + + +static char * +ngx_http_image_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_image_filter_conf_t *prev = parent; + ngx_http_image_filter_conf_t *conf = child; + + if (conf->filter == NGX_CONF_UNSET_UINT) { + + if (prev->filter == NGX_CONF_UNSET_UINT) { + conf->filter = NGX_HTTP_IMAGE_OFF; + + } else { + conf->filter = prev->filter; + conf->width = prev->width; + conf->height = prev->height; + } + } + + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, + 1 * 1024 * 1024); + + return NGX_CONF_OK; +} + + +static char * +ngx_http_image_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_image_filter_conf_t *imcf = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + + value = cf->args->elts; + + i = 1; + + if (cf->args->nelts == 2) { + if (ngx_strcmp(value[i].data, "off") == 0) { + imcf->filter = NGX_HTTP_IMAGE_OFF; + + } else if (ngx_strcmp(value[i].data, "test") == 0) { + imcf->filter = NGX_HTTP_IMAGE_TEST; + + } else if (ngx_strcmp(value[i].data, "size") == 0) { + imcf->filter = NGX_HTTP_IMAGE_SIZE; + + } else { + goto failed; + } + + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[i].data, "resize") == 0) { + imcf->filter = NGX_HTTP_IMAGE_RESIZE; + + } else if (ngx_strcmp(value[i].data, "crop") == 0) { + imcf->filter = NGX_HTTP_IMAGE_CROP; + + } else { + goto failed; + } + + i++; + + if (value[i].len == 1 && value[i].data[0] == '-') { + imcf->width = (ngx_uint_t) -1; + + } else { + n = ngx_atoi(value[i].data, value[i].len); + if (n == NGX_ERROR) { + goto failed; + } + + imcf->width = (ngx_uint_t) n; + } + + i++; + + if (value[i].len == 1 && value[i].data[0] == '-') { + imcf->height = (ngx_uint_t) -1; + + } else { + n = ngx_atoi(value[i].data, value[i].len); + if (n == NGX_ERROR) { + goto failed; + } + + imcf->height = (ngx_uint_t) n; + } + + return NGX_CONF_OK; + +failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", + &value[i]); + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_http_image_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_image_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_image_body_filter; + + return NGX_OK; +} 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 @@ -172,6 +172,15 @@ static ngx_conf_bitmask_t ngx_http_prox }; +static ngx_conf_bitmask_t ngx_http_proxy_ignore_headers_masks[] = { + { ngx_string("X-Accel-Redirect"), NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT }, + { ngx_string("X-Accel-Expires"), NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES }, + { ngx_string("Expires"), NGX_HTTP_UPSTREAM_IGN_EXPIRES }, + { ngx_string("Cache-Control"), NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL }, + { ngx_null_string, 0 } +}; + + ngx_module_t ngx_http_proxy_module; @@ -426,6 +435,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.hide_headers), NULL }, + { ngx_string("proxy_ignore_headers"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_headers), + &ngx_http_proxy_ignore_headers_masks }, + #if (NGX_HTTP_SSL) { ngx_string("proxy_ssl_session_reuse"), @@ -1867,6 +1883,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * set by ngx_pcalloc(): * * conf->upstream.bufs.num = 0; + * conf->upstream.ignore_headers = 0; * conf->upstream.next_upstream = 0; * conf->upstream.use_stale_cache = 0; * conf->upstream.temp_path = NULL; @@ -2072,6 +2089,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } + ngx_conf_merge_bitmask_value(conf->upstream.ignore_headers, + prev->upstream.ignore_headers, + NGX_CONF_BITMASK_SET); + + ngx_conf_merge_bitmask_value(conf->upstream.next_upstream, prev->upstream.next_upstream, (NGX_CONF_BITMASK_SET @@ -2675,10 +2697,26 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, value = cf->args->elts; - if (ngx_strcmp(value[1].data, "off") == 0) { - plcf->redirect = 0; - plcf->redirects = NULL; - return NGX_CONF_OK; + if (cf->args->nelts == 2) { + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->redirect = 0; + plcf->redirects = NULL; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "false") == 0) { + ngx_conf_log_error(NGX_LOG_ERR, cf, 0, + "invalid parameter \"false\", use \"off\" instead"); + plcf->redirect = 0; + plcf->redirects = NULL; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "default") != 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } } if (plcf->redirects == NULL) { @@ -2694,7 +2732,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, return NGX_CONF_ERROR; } - if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "default") == 0) { + if (ngx_strcmp(value[1].data, "default") == 0) { if (plcf->url.data == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "\"proxy_rewrite_location default\" must go " diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -64,7 +64,6 @@ typedef struct { static ngx_int_t ngx_http_xslt_send(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); -static ngx_int_t ngx_http_xslt_filter_internal_error(ngx_http_request_t *r); static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b); @@ -320,14 +319,15 @@ ngx_http_xslt_send(ngx_http_request_t *r ctx->done = 1; if (b == NULL) { - return ngx_http_xslt_filter_internal_error(r); + return ngx_http_filter_finalize_request(r, + NGX_HTTP_INTERNAL_SERVER_ERROR); } cln = ngx_pool_cleanup_add(r->pool, 0); if (cln == NULL) { ngx_free(b->pos); - return ngx_http_special_response_handler(r, + return ngx_http_filter_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); } @@ -360,22 +360,6 @@ ngx_http_xslt_send(ngx_http_request_t *r static ngx_int_t -ngx_http_xslt_filter_internal_error(ngx_http_request_t *r) -{ - ngx_int_t rc; - - /* clear the modules contexts */ - ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); - - rc = ngx_http_special_response_handler(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - - /* NGX_ERROR resets any pending data */ - - return (rc == NGX_OK) ? NGX_ERROR : rc; -} - - -static ngx_int_t ngx_http_xslt_add_chunk(ngx_http_request_t *r, ngx_http_xslt_filter_ctx_t *ctx, ngx_buf_t *b) { diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.53'; +our $VERSION = '0.7.54'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1746,7 +1746,7 @@ ngx_http_add_listening(ngx_conf_t *cf, n clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; - ls->log = *clcf->err_log; + ls->logp = clcf->error_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -103,6 +103,9 @@ ngx_int_t ngx_http_read_client_request_b ngx_int_t ngx_http_send_header(ngx_http_request_t *r); ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error); +ngx_int_t ngx_http_filter_finalize_request(ngx_http_request_t *r, + ngx_int_t error); +void ngx_http_clean_header(ngx_http_request_t *r); time_t ngx_http_parse_time(u_char *value, size_t len); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -1292,10 +1292,10 @@ ngx_http_update_location_config(ngx_http } if (r == r->main) { - r->connection->log->file = clcf->err_log->file; + r->connection->log->file = clcf->error_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->err_log->log_level; + r->connection->log->log_level = clcf->error_log->log_level; } } @@ -2929,7 +2929,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t * lcf->post_action = { 0, NULL }; * lcf->types = NULL; * lcf->default_type = { 0, NULL }; - * lcf->err_log = NULL; + * lcf->error_log = NULL; * lcf->error_pages = NULL; * lcf->try_files = NULL; * lcf->client_body_path = NULL; @@ -3109,11 +3109,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t } } - if (conf->err_log == NULL) { - if (prev->err_log) { - conf->err_log = prev->err_log; + if (conf->error_log == NULL) { + if (prev->error_log) { + conf->error_log = prev->error_log; } else { - conf->err_log = cf->cycle->new_log; + conf->error_log = &cf->cycle->new_log; } } @@ -4104,14 +4104,23 @@ ngx_http_core_error_log(ngx_conf_t *cf, ngx_str_t *value; + if (lcf->error_log) { + return "is duplicate"; + } + value = cf->args->elts; - lcf->err_log = ngx_log_create_errlog(cf->cycle, &value[1]); - if (lcf->err_log == NULL) { + lcf->error_log = ngx_log_create(cf->cycle, &value[1]); + if (lcf->error_log == NULL) { return NGX_CONF_ERROR; } - return ngx_set_error_log_levels(cf, lcf->err_log); + if (cf->args->nelts == 2) { + lcf->error_log->log_level = NGX_LOG_ERR; + return NGX_CONF_OK; + } + + return ngx_log_set_levels(cf, lcf->error_log); } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -377,7 +377,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t open_file_cache_errors; ngx_flag_t open_file_cache_events; - ngx_log_t *err_log; + ngx_log_t *error_log; ngx_uint_t types_hash_max_size; ngx_uint_t types_hash_bucket_size; diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -357,6 +357,9 @@ ngx_http_header_filter(ngx_http_request_ else #endif port = (port == 80) ? 0 : port; + + } else { + port = 0; } if (port) { 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 @@ -420,9 +420,9 @@ ngx_http_init_request(ngx_event_t *rev) #endif clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - c->log->file = clcf->err_log->file; + c->log->file = clcf->error_log->file; if (!(c->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - c->log->log_level = clcf->err_log->log_level; + c->log->log_level = clcf->error_log->log_level; } if (c->buffer == NULL) { @@ -1704,10 +1704,10 @@ found: r->loc_conf = cscf->ctx->loc_conf; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - r->connection->log->file = clcf->err_log->file; + r->connection->log->file = clcf->error_log->file; if (!(r->connection->log->log_level & NGX_LOG_DEBUG_CONNECTION)) { - r->connection->log->log_level = clcf->err_log->log_level; + r->connection->log->log_level = clcf->error_log->log_level; } return NGX_OK; diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -445,6 +445,40 @@ ngx_http_special_response_handler(ngx_ht } +ngx_int_t +ngx_http_filter_finalize_request(ngx_http_request_t *r, ngx_int_t error) +{ + ngx_int_t rc; + + ngx_http_clean_header(r); + + /* clear the modules contexts */ + ngx_memzero(r->ctx, sizeof(void *) * ngx_http_max_module); + + rc = ngx_http_special_response_handler(r, error); + + /* NGX_ERROR resets any pending data */ + + return (rc == NGX_OK) ? NGX_ERROR : rc; +} + + +void +ngx_http_clean_header(ngx_http_request_t *r) +{ + ngx_memzero(&r->headers_out.status, + sizeof(ngx_http_headers_out_t) + - offsetof(ngx_http_headers_out_t, status)); + + r->headers_out.headers.part.nelts = 0; + r->headers_out.headers.part.next = NULL; + r->headers_out.headers.last = &r->headers_out.headers.part; + + r->headers_out.content_length_n = -1; + r->headers_out.last_modified_time = -1; +} + + static ngx_int_t ngx_http_send_error_page(ngx_http_request_t *r, ngx_http_err_page_t *err_page) { 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 @@ -1623,8 +1623,9 @@ ngx_http_upstream_process_headers(ngx_ht umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); - if (u->headers_in.x_accel_redirect) { - + if (u->headers_in.x_accel_redirect + && !(u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT)) + { ngx_http_upstream_finalize_request(r, u, NGX_DECLINED); part = &u->headers_in.headers.part; @@ -2845,10 +2846,12 @@ static ngx_int_t ngx_http_upstream_process_cache_control(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - ngx_array_t *pa; - ngx_table_elt_t **ph; - - pa = &r->upstream->headers_in.cache_control; + ngx_array_t *pa; + ngx_table_elt_t **ph; + ngx_http_upstream_t *u; + + u = r->upstream; + pa = &u->headers_in.cache_control; if (pa->elts == NULL) { if (ngx_array_init(pa, r->pool, 2, sizeof(ngx_table_elt_t *)) != NGX_OK) @@ -2869,6 +2872,10 @@ ngx_http_upstream_process_cache_control( u_char *p, *last; ngx_int_t n; + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL) { + return NGX_OK; + } + if (r->cache == NULL) { return NGX_OK; } @@ -2882,7 +2889,7 @@ ngx_http_upstream_process_cache_control( if (ngx_strlcasestrn(h->value.data, last, (u_char *) "no-cache", 8 - 1) != NULL) { - r->upstream->cacheable = 0; + u->cacheable = 0; return NGX_OK; } @@ -2904,12 +2911,12 @@ ngx_http_upstream_process_cache_control( continue; } - r->upstream->cacheable = 0; + u->cacheable = 0; return NGX_OK; } if (n == 0) { - r->upstream->cacheable = 0; + u->cacheable = 0; return NGX_OK; } @@ -2925,12 +2932,19 @@ static ngx_int_t ngx_http_upstream_process_expires(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - r->upstream->headers_in.expires = h; + ngx_http_upstream_t *u; + + u = r->upstream; + u->headers_in.expires = h; #if (NGX_HTTP_CACHE) { time_t expires; + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_EXPIRES) { + return NGX_OK; + } + if (r->cache == NULL) { return NGX_OK; } @@ -2942,7 +2956,7 @@ ngx_http_upstream_process_expires(ngx_ht expires = ngx_http_parse_time(h->value.data, h->value.len); if (expires == NGX_ERROR || expires < ngx_time()) { - r->upstream->cacheable = 0; + u->cacheable = 0; return NGX_OK; } @@ -2958,7 +2972,10 @@ static ngx_int_t ngx_http_upstream_process_accel_expires(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - r->upstream->headers_in.x_accel_expires = h; + ngx_http_upstream_t *u; + + u = r->upstream; + u->headers_in.x_accel_expires = h; #if (NGX_HTTP_CACHE) { @@ -2966,6 +2983,10 @@ ngx_http_upstream_process_accel_expires( size_t len; ngx_int_t n; + if (u->conf->ignore_headers & NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES) { + return NGX_OK; + } + if (r->cache == NULL) { return NGX_OK; } @@ -2978,7 +2999,7 @@ ngx_http_upstream_process_accel_expires( switch (n) { case 0: - r->upstream->cacheable = 0; + u->cacheable = 0; case NGX_ERROR: return NGX_OK; 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 @@ -38,6 +38,12 @@ #define NGX_HTTP_UPSTREAM_INVALID_HEADER 40 +#define NGX_HTTP_UPSTREAM_IGN_XA_REDIRECT 0x00000002 +#define NGX_HTTP_UPSTREAM_IGN_XA_EXPIRES 0x00000004 +#define NGX_HTTP_UPSTREAM_IGN_EXPIRES 0x00000008 +#define NGX_HTTP_UPSTREAM_IGN_CACHE_CONTROL 0x00000010 + + typedef struct { ngx_msec_t bl_time; ngx_uint_t bl_state; @@ -128,6 +134,7 @@ typedef struct { ngx_bufs_t bufs; + ngx_uint_t ignore_headers; ngx_uint_t next_upstream; ngx_uint_t store_access; ngx_flag_t buffering; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -313,11 +313,10 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma ls->handler = ngx_mail_init_connection; ls->pool_size = 256; - /* STUB */ - ls->log = *cf->cycle->new_log; + /* TODO: error_log directive */ + ls->logp = &cf->cycle->new_log; ls->log.data = &ls->addr_text; ls->log.handler = ngx_accept_log_error; - /**/ imip = ngx_palloc(cf->pool, sizeof(ngx_mail_in_port_t)); if (imip == NULL) { diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -113,6 +113,10 @@ ngx_write_fd(ngx_fd_t fd, void *buf, siz #define ngx_write_fd_n "write()" + +#define ngx_write_console ngx_write_fd + + #define ngx_linefeed(p) *p++ = LF; #define NGX_LINEFEED_SIZE 1