# HG changeset patch # User Igor Sysoev # Date 1214769600 -14400 # Node ID 12defd37f57883e4d59ef36837d03c9b68c3c3ad # Parent 6ee3ada01457755c804515ebbc862df12b540a06 nginx 0.7.4 *) Feature: variables support in the "access_log" directive. *) Feature: the "open_log_file_cache" directive. *) Feature: the -g switch. *) Feature: the "Expect" request header line support. *) Bugfix: large SSI inclusions might be truncated. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,17 @@ +Changes with nginx 0.7.4 30 Jun 2008 + + *) Feature: variables support in the "access_log" directive. + + *) Feature: the "open_log_file_cache" directive. + + *) Feature: the -g switch. + + *) Feature: the "Expect" request header line support. + + *) Bugfix: large SSI inclusions might be truncated. + + Changes with nginx 0.7.3 23 Jun 2008 *) Change: the "rss" extension MIME type has been changed to @@ -912,13 +925,13 @@ Changes with nginx 0.5.13 send timeout only. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc and ppc; the bug had appeared in 0.5.8. + amd64, sparc, and ppc; the bug had appeared in 0.5.8. Changes with nginx 0.5.12 12 Feb 2007 *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc и ppc; the bug had appeared in 0.5.8. + amd64, sparc, and ppc; the bug had appeared in 0.5.8. *) Bugfix: a segmentation fault might occur in worker process if the temporarily files were used while working with FastCGI server; the @@ -1624,7 +1637,8 @@ Changes with nginx 0.3.45 *) Change: the ° symbol codes were changed in koi-win conversion table. - *) Feature: the euro и N symbols were added to koi-win conversion table. + *) Feature: the euro and N symbols were added to koi-win conversion + table. *) Bugfix: if nginx distributed the requests among several backends and some backend failed, then requests intended for this backend was @@ -2231,7 +2245,7 @@ Changes with nginx 0.3.7 *) Feature: the "access_log" supports the "buffer=" parameter. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc и ppc; the bug had appeared in 0.3.2. + amd64, sparc, and ppc; the bug had appeared in 0.3.2. Changes with nginx 0.3.6 24 Oct 2005 @@ -2920,7 +2934,7 @@ Changes with nginx 0.1.23 server name of the "server_name" directive. *) Bugfix: nginx could not be built on platforms different from i386, - amd64, sparc и ppc; the bug had appeared in 0.1.22. + amd64, sparc, and ppc; the bug had appeared in 0.1.22. *) Bugfix: the ngx_http_autoindex_module now shows the information not about the symlink, but about file or directory it points to. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,17 @@ +Изменения в nginx 0.7.4 30.06.2008 + + *) Добавление: директива access_log поддерживает переменные. + + *) Добавление: директива open_log_file_cache. + + *) Добавление: ключ -g. + + *) Добавление: поддержка строки "Expect" в заголовке запроса. + + *) Исправление: большие включения в SSI могли передавались не полностью. + + Изменения в nginx 0.7.3 23.06.2008 *) Изменение: MIME-тип для расширения rss изменён на diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -637,8 +637,7 @@ ngx_getopt(ngx_cycle_t *cycle, int argc, case 'c': if (argv[i + 1] == NULL) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, - "the option: \"%s\" requires file name", - argv[i]); + "the option \"-c\" requires file name"); return NGX_ERROR; } @@ -646,6 +645,17 @@ ngx_getopt(ngx_cycle_t *cycle, int argc, cycle->conf_file.len = ngx_strlen(cycle->conf_file.data); break; + case 'g': + if (argv[i + 1] == NULL) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, + "the option \"-g\" requires parameter"); + return NGX_ERROR; + } + + cycle->conf_param.data = (u_char *) argv[++i]; + cycle->conf_param.len = ngx_strlen(cycle->conf_param.data); + break; + default: ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "invalid option: \"%s\"", argv[i]); 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_VERSION "0.7.3" +#define NGINX_VERSION "0.7.4" #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 @@ -58,14 +58,52 @@ static int argument_number[] = { char * +ngx_conf_param(ngx_conf_t *cf) +{ + ngx_str_t *param; + ngx_buf_t b; + ngx_conf_file_t conf_file; + + param = &cf->cycle->conf_param; + + if (param->len == 0) { + return NGX_CONF_OK; + } + + ngx_memzero(&conf_file, sizeof(ngx_conf_file_t)); + + ngx_memzero(&b, sizeof(ngx_buf_t)); + + b.start = param->data; + b.pos = param->data; + b.last = param->data + param->len; + b.end = b.last; + b.temporary = 1; + + conf_file.file.fd = NGX_INVALID_FILE; + conf_file.file.name.data = (u_char *) "command line"; + conf_file.line = 1; + + cf->conf_file = &conf_file; + cf->conf_file->buffer = &b; + + return ngx_conf_parse(cf, NULL); +} + + +char * ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename) { char *rv; ngx_fd_t fd; ngx_int_t rc; ngx_buf_t *b; - ngx_uint_t block; ngx_conf_file_t *prev; + enum { + parse_file = 0, + parse_block, + parse_param + } type; #if (NGX_SUPPRESS_WARN) fd = NGX_INVALID_FILE; @@ -120,10 +158,14 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t cf->conf_file->file.log = cf->log; cf->conf_file->line = 1; - block = 0; + type = parse_file; + + } else if (cf->conf_file->file.fd != NGX_INVALID_FILE) { + + type = parse_block; } else { - block = 1; + type = parse_param; } @@ -145,24 +187,38 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t } if (rc == NGX_CONF_BLOCK_DONE) { - if (!block) { + + if (type != parse_block) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected \"}\""); goto failed; } - block = 0; + goto done; } - if (rc == NGX_CONF_FILE_DONE && block) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unexpected end of file, expecting \"}\""); - goto failed; + if (rc == NGX_CONF_FILE_DONE) { + + if (type == parse_block) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of file, expecting \"}\""); + goto failed; + } + + goto done; } - if (rc != NGX_OK && rc != NGX_CONF_BLOCK_START) { - goto done; + if (rc == NGX_CONF_BLOCK_START) { + + if (type == parse_param) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "block directives are not supported " + "in -g option"); + goto failed; + } } + /* rc == NGX_OK || rc == NGX_CONF_BLOCK_START */ + if (cf->handler) { /* @@ -398,10 +454,19 @@ ngx_conf_read_token(ngx_conf_t *cf) for ( ;; ) { if (b->pos >= b->last) { + if (cf->conf_file->file.offset >= ngx_file_size(&cf->conf_file->file.info)) { if (cf->args->nelts > 0) { + + if (cf->conf_file->file.fd == NGX_INVALID_FILE) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unexpected end of parameter, " + "expecting \";\""); + return NGX_ERROR; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "unexpected end of file, " "expecting \";\" or \"}\""); diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -317,6 +317,7 @@ char *ngx_conf_check_num_bounds(ngx_conf #define addressof(addr) ((int) &addr) +char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); 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 @@ -90,6 +90,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) old_cycle->conf_file.len + 1); + cycle->conf_param.len = old_cycle->conf_param.len; + cycle->conf_param.data = ngx_pnalloc(pool, old_cycle->conf_param.len); + if (cycle->conf_param.data == NULL) { + ngx_destroy_pool(pool); + return NULL; + } + ngx_memcpy(cycle->conf_param.data, old_cycle->conf_param.data, + old_cycle->conf_param.len); + + n = old_cycle->pathes.nelts ? old_cycle->pathes.nelts : 10; cycle->pathes.elts = ngx_pcalloc(pool, n * sizeof(ngx_path_t *)); @@ -238,6 +248,11 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) log->log_level = NGX_LOG_DEBUG_ALL; #endif + if (ngx_conf_param(&conf) != NGX_CONF_OK) { + ngx_destroy_cycle_pools(&conf); + return NULL; + } + if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) { ngx_destroy_cycle_pools(&conf); return NULL; 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 @@ -60,6 +60,7 @@ struct ngx_cycle_s { ngx_cycle_t *old_cycle; ngx_str_t conf_file; + ngx_str_t conf_param; ngx_str_t root; ngx_str_t lock_file; ngx_str_t hostname; 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 @@ -135,6 +135,7 @@ ngx_open_cached_file(ngx_open_file_cache ngx_pool_cleanup_file_t *clnf; ngx_open_file_cache_cleanup_t *ofcln; + of->fd = NGX_INVALID_FILE; of->err = 0; if (cache == NULL) { @@ -188,8 +189,10 @@ ngx_open_cached_file(ngx_open_file_cache goto add_event; } - if ((file->event && file->use_event) - || (file->event == NULL && now - file->created < of->valid)) + if (file->use_event + || (file->event == NULL + && (of->uniq == 0 || of->uniq == file->uniq) + && now - file->created < of->valid)) { if (file->err == 0) { @@ -230,6 +233,9 @@ ngx_open_cached_file(ngx_open_file_cache of->test_dir = 1; } + of->fd = file->fd; + of->uniq = file->uniq; + rc = ngx_open_and_stat_file(name->data, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { @@ -250,26 +256,14 @@ ngx_open_cached_file(ngx_open_file_cache goto add_event; } - if (of->uniq == file->uniq - && of->mtime == file->mtime - && of->size == file->size) - { - if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - name->data); - } + if (of->uniq == file->uniq) { - of->fd = file->fd; file->count++; if (file->event) { file->use_event = 1; - goto renew; } - ngx_open_file_add_event(cache, file, of, pool->log); - goto renew; } @@ -344,7 +338,6 @@ create: file->uses = 1; file->count = 0; - file->use_event = 0; file->event = NULL; add_event: @@ -446,34 +439,38 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_fd_t fd; ngx_file_info_t fi; - of->fd = NGX_INVALID_FILE; - - if (of->test_dir) { + if (of->fd != NGX_INVALID_FILE) { if (ngx_file_info(name, &fi) == -1) { - of->err = ngx_errno; - - return NGX_ERROR; + goto failed; } - of->uniq = ngx_file_uniq(&fi); - of->mtime = ngx_file_mtime(&fi); - of->size = ngx_file_size(&fi); - of->is_dir = ngx_is_dir(&fi); - of->is_file = ngx_is_file(&fi); - of->is_link = ngx_is_link(&fi); - of->is_exec = ngx_is_exec(&fi); + if (of->uniq == ngx_file_uniq(&fi)) { + goto done; + } + + } else if (of->test_dir) { + + if (ngx_file_info(name, &fi) == -1) { + goto failed; + } if (of->is_dir) { - return NGX_OK; + goto done; } } - fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (!of->log) { + fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + + } else { + fd = ngx_open_file(name, NGX_FILE_RDWR, + NGX_FILE_CREATE_OR_OPEN|NGX_FILE_APPEND, + NGX_FILE_DEFAULT_ACCESS); + } if (fd == NGX_INVALID_FILE) { - of->err = ngx_errno; - return NGX_ERROR; + goto failed; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { @@ -485,6 +482,8 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_close_file_n " \"%s\" failed", name); } + of->fd = NGX_INVALID_FILE; + return NGX_ERROR; } @@ -494,10 +493,14 @@ ngx_open_and_stat_file(u_char *name, ngx ngx_close_file_n " \"%s\" failed", name); } - fd = NGX_INVALID_FILE; + of->fd = NGX_INVALID_FILE; + + } else { + of->fd = fd; } - of->fd = fd; +done: + of->uniq = ngx_file_uniq(&fi); of->mtime = ngx_file_mtime(&fi); of->size = ngx_file_size(&fi); @@ -507,6 +510,13 @@ ngx_open_and_stat_file(u_char *name, ngx of->is_exec = ngx_is_exec(&fi); return NGX_OK; + +failed: + + of->fd = NGX_INVALID_FILE; + of->err = ngx_errno; + + return NGX_ERROR; } @@ -530,6 +540,8 @@ ngx_open_file_add_event(ngx_open_file_ca return; } + file->use_event = 0; + file->event = ngx_calloc(sizeof(ngx_event_t), log); if (file->event== NULL) { return; @@ -567,9 +579,10 @@ ngx_open_file_add_event(ngx_open_file_ca } /* - * we do not file->use_event here because there may be a race - * condition between opening file and adding event, so we rely - * upon event notification only after first file revalidation + * we do not set file->use_event here because there may be a race + * condition: a file may be deleted between opening the file and + * adding event, so we rely upon event notification only after + * one file revalidation on next file access */ return; @@ -807,6 +820,7 @@ ngx_open_file_cache_remove(ngx_event_t * /* NGX_ONESHOT_EVENT was already deleted */ file->event = NULL; + file->use_event = 0; file->close = 1; diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -24,6 +24,7 @@ typedef struct { ngx_uint_t min_uses; unsigned test_dir:1; + unsigned log:1; unsigned errors:1; unsigned events:1; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- a/src/event/modules/ngx_epoll_module.c +++ b/src/event/modules/ngx_epoll_module.c @@ -143,15 +143,12 @@ ngx_module_t ngx_epoll_module = { static ngx_int_t ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer) { - ngx_event_conf_t *ecf; ngx_epoll_conf_t *epcf; - ecf = ngx_event_get_conf(cycle->conf_ctx, ngx_event_core_module); - epcf = ngx_event_get_conf(cycle->conf_ctx, ngx_epoll_module); if (ep == -1) { - ep = epoll_create(ecf->connections / 2); + ep = epoll_create(cycle->connection_n / 2); if (ep == -1) { ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno, 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 @@ -436,10 +436,10 @@ ngx_select_init_conf(ngx_cycle_t *cycle, #if !(NGX_WIN32) - if ((unsigned) ecf->connections > FD_SETSIZE) { + if (cycle->connection_n > FD_SETSIZE) { ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "the maximum number of files " - "supported by select() is " ngx_value(FD_SETSIZE)); + "supported by select() is %ud", FD_SETSIZE); return NGX_CONF_ERROR; } 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 @@ -596,22 +596,23 @@ ngx_event_process_init(ngx_cycle_t *cycl return NGX_ERROR; } - cycle->connection_n = ecf->connections; - for (m = 0; ngx_modules[m]; m++) { if (ngx_modules[m]->type != NGX_EVENT_MODULE) { continue; } - if (ngx_modules[m]->ctx_index == ecf->use) { - module = ngx_modules[m]->ctx; - if (module->actions.init(cycle, ngx_timer_resolution) == NGX_ERROR) - { - /* fatal */ - exit(2); - } - break; + if (ngx_modules[m]->ctx_index != ecf->use) { + continue; } + + module = ngx_modules[m]->ctx; + + if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) { + /* fatal */ + exit(2); + } + + break; } #if !(NGX_WIN32) @@ -661,15 +662,15 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif - cycle->connections = ngx_alloc(sizeof(ngx_connection_t) * ecf->connections, - cycle->log); + cycle->connections = + ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log); if (cycle->connections == NULL) { return NGX_ERROR; } c = cycle->connections; - cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->read_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->read_events == NULL) { return NGX_ERROR; @@ -685,7 +686,7 @@ ngx_event_process_init(ngx_cycle_t *cycl #endif } - cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * ecf->connections, + cycle->write_events = ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n, cycle->log); if (cycle->write_events == NULL) { return NGX_ERROR; @@ -719,7 +720,7 @@ ngx_event_process_init(ngx_cycle_t *cycl } while (i); cycle->free_connections = next; - cycle->free_connection_n = ecf->connections; + cycle->free_connection_n = cycle->connection_n; /* for each listening socket */ @@ -1137,11 +1138,10 @@ ngx_event_init_conf(ngx_cycle_t *cycle, ngx_uint_t rtsig; ngx_core_conf_t *ccf; #endif - ngx_int_t i, connections; + ngx_int_t i; ngx_module_t *module; ngx_event_module_t *event_module; - connections = NGX_CONF_UNSET_UINT; module = NULL; #if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL) @@ -1150,11 +1150,9 @@ ngx_event_init_conf(ngx_cycle_t *cycle, if (fd != -1) { close(fd); - connections = DEFAULT_CONNECTIONS; module = &ngx_epoll_module; } else if (ngx_errno != NGX_ENOSYS) { - connections = DEFAULT_CONNECTIONS; module = &ngx_epoll_module; } @@ -1163,7 +1161,6 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_RTSIG) if (module == NULL) { - connections = DEFAULT_CONNECTIONS; module = &ngx_rtsig_module; rtsig = 1; @@ -1175,14 +1172,12 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_DEVPOLL) - connections = DEFAULT_CONNECTIONS; module = &ngx_devpoll_module; #endif #if (NGX_HAVE_KQUEUE) - connections = DEFAULT_CONNECTIONS; module = &ngx_kqueue_module; #endif @@ -1190,12 +1185,6 @@ ngx_event_init_conf(ngx_cycle_t *cycle, #if (NGX_HAVE_SELECT) if (module == NULL) { - -#if (NGX_WIN32 || FD_SETSIZE >= DEFAULT_CONNECTIONS) - connections = DEFAULT_CONNECTIONS; -#else - connections = FD_SETSIZE; -#endif module = &ngx_select_module; } @@ -1203,18 +1192,20 @@ ngx_event_init_conf(ngx_cycle_t *cycle, if (module == NULL) { for (i = 0; ngx_modules[i]; i++) { - if (ngx_modules[i]->type == NGX_EVENT_MODULE) { - event_module = ngx_modules[i]->ctx; + + if (ngx_modules[i]->type != NGX_EVENT_MODULE) { + continue; + } + + event_module = ngx_modules[i]->ctx; - if (ngx_strcmp(event_module->name->data, event_core_name.data) - == 0) - { - continue; - } + if (ngx_strcmp(event_module->name->data, event_core_name.data) == 0) + { + continue; + } - module = ngx_modules[i]; - break; - } + module = ngx_modules[i]; + break; } } @@ -1223,7 +1214,7 @@ ngx_event_init_conf(ngx_cycle_t *cycle, return NGX_CONF_ERROR; } - ngx_conf_init_uint_value(ecf->connections, connections); + ngx_conf_init_uint_value(ecf->connections, DEFAULT_CONNECTIONS); cycle->connection_n = ecf->connections; ngx_conf_init_uint_value(ecf->use, module->ctx_index); diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -105,7 +105,8 @@ ngx_http_flv_handler(ngx_http_request_t clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -119,7 +119,8 @@ ngx_http_gzip_static_handler(ngx_http_re clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -208,7 +208,8 @@ ngx_http_index_handler(ngx_http_request_ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path); - of.test_dir = 0; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; @@ -291,9 +292,10 @@ ngx_http_index_test_dir(ngx_http_request ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http index check dir: \"%V\"", &dir); + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.test_dir = 1; of.valid = clcf->open_file_cache_valid; - of.min_uses = 0; of.errors = clcf->open_file_cache_errors; if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -40,7 +40,14 @@ typedef struct { typedef struct { + ngx_array_t *lengths; + ngx_array_t *values; +} ngx_http_log_script_t; + + +typedef struct { ngx_open_file_t *file; + ngx_http_log_script_t *script; time_t disk_full_time; time_t error_log_time; ngx_array_t *ops; /* array of ngx_http_log_op_t */ @@ -49,6 +56,11 @@ typedef struct { typedef struct { ngx_array_t *logs; /* array of ngx_http_log_t */ + + ngx_open_file_cache_t *open_file_cache; + time_t open_file_cache_valid; + ngx_uint_t open_file_cache_min_uses; + ngx_uint_t off; /* unsigned off:1 */ } ngx_http_log_loc_conf_t; @@ -62,6 +74,8 @@ typedef struct { static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, size_t len); +static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, + ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); @@ -101,6 +115,8 @@ static char *ngx_http_log_set_format(ngx void *conf); static char *ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s); +static char *ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_int_t ngx_http_log_init(ngx_conf_t *cf); @@ -121,6 +137,13 @@ static ngx_command_t ngx_http_log_comma 0, NULL }, + { ngx_string("open_log_file_cache"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, + ngx_http_log_open_file_cache, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -235,7 +258,7 @@ ngx_http_log_handler(ngx_http_request_t file = log[l].file; - if (file->buffer) { + if (file && file->buffer) { if (len > (size_t) (file->last - file->pos)) { @@ -285,11 +308,19 @@ static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, size_t len) { - time_t now; - ssize_t n; - ngx_err_t err; + u_char *name; + time_t now; + ssize_t n; + ngx_err_t err; - n = ngx_write_fd(log->file->fd, buf, len); + if (log->script == NULL) { + name = log->file->name.data; + n = ngx_write_fd(log->file->fd, buf, len); + + } else { + name = NULL; + n = ngx_http_log_script_write(r, log->script, &name, buf, len); + } if (n == (ssize_t) len) { return; @@ -306,8 +337,7 @@ ngx_http_log_write(ngx_http_request_t *r if (now - log->error_log_time > 59) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, err, - ngx_write_fd_n " to \"%V\" failed", - &log->file->name); + ngx_write_fd_n " to \"%s\" failed", name); log->error_log_time = now; } @@ -317,14 +347,93 @@ ngx_http_log_write(ngx_http_request_t *r if (now - log->error_log_time > 59) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_write_fd_n " to \"%V\" was incomplete: %z of %uz", - &log->file->name, n, len); + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + name, n, len); log->error_log_time = now; } } +static ssize_t +ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script, + u_char **name, u_char *buf, size_t len) +{ + size_t root; + ssize_t n; + ngx_str_t log, path; + ngx_open_file_info_t of; + ngx_http_log_loc_conf_t *llcf; + ngx_http_core_loc_conf_t *clcf; + + if (r->err_status == NGX_HTTP_NOT_FOUND) { + + /* test root directory existance */ + + if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { + /* simulate successfull logging */ + return len; + } + + path.data[root] = '\0'; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) + != NGX_OK + || !of.is_dir) + { + /* no root directory: simulate successfull logging */ + return len; + } + } + + if (ngx_http_script_run(r, &log, script->lengths->elts, 1, + script->values->elts) + == NULL) + { + /* simulate successfull logging */ + return len; + } + + log.data[log.len - 1] = '\0'; + *name = log.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http log \"%s\"", log.data); + + llcf = ngx_http_get_module_loc_conf(r, ngx_http_log_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.log = 1; + of.valid = llcf->open_file_cache_valid; + of.min_uses = llcf->open_file_cache_min_uses; + + if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) + != NGX_OK) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", log.data); + return -1; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http log #%d", of.fd); + + n = ngx_write_fd(of.fd, buf, len); + + return n; +} + + static u_char * ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) @@ -620,6 +729,8 @@ ngx_http_log_create_loc_conf(ngx_conf_t return NGX_CONF_ERROR; } + conf->open_file_cache = NGX_CONF_UNSET_PTR; + return conf; } @@ -634,6 +745,17 @@ ngx_http_log_merge_loc_conf(ngx_conf_t * ngx_http_log_fmt_t *fmt; ngx_http_log_main_conf_t *lmcf; + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + + conf->open_file_cache = prev->open_file_cache; + conf->open_file_cache_valid = prev->open_file_cache_valid; + conf->open_file_cache_min_uses = prev->open_file_cache_min_uses; + + if (conf->open_file_cache == NGX_CONF_UNSET_PTR) { + conf->open_file_cache = NULL; + } + } + if (conf->logs || conf->off) { return NGX_CONF_OK; } @@ -678,12 +800,13 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx { ngx_http_log_loc_conf_t *llcf = conf; - ssize_t buf; - ngx_uint_t i; - ngx_str_t *value, name; - ngx_http_log_t *log; - ngx_http_log_fmt_t *fmt; - ngx_http_log_main_conf_t *lmcf; + ssize_t buf; + ngx_uint_t i, n; + ngx_str_t *value, name; + ngx_http_log_t *log; + ngx_http_log_fmt_t *fmt; + ngx_http_log_main_conf_t *lmcf; + ngx_http_script_compile_t sc; value = cf->args->elts; @@ -706,14 +829,41 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - log->file = ngx_conf_open_file(cf->cycle, &value[1]); - if (log->file == NULL) { - return NGX_CONF_ERROR; + ngx_memzero(log, sizeof(ngx_http_log_t)); + + n = ngx_http_script_variables_count(&value[1]); + + if (n == 0) { + log->file = ngx_conf_open_file(cf->cycle, &value[1]); + if (log->file == NULL) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_conf_full_name(cf->cycle, &value[1], 0) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + log->script = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_script_t)); + if (log->script == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[1]; + sc.lengths = &log->script->lengths; + sc.values = &log->script->values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } } - log->disk_full_time = 0; - log->error_log_time = 0; - if (cf->args->nelts >= 3) { name = value[2]; @@ -750,6 +900,12 @@ buffer: return NGX_CONF_ERROR; } + if (log->script) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "buffered logs can not have variables in name"); + return NGX_CONF_ERROR; + } + name.len = value[3].len - 7; name.data = value[3].data + 7; @@ -992,6 +1148,114 @@ invalid: } +static char * +ngx_http_log_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_log_loc_conf_t *llcf = conf; + + time_t inactive, valid; + ngx_str_t *value, s; + ngx_int_t max, min_uses; + ngx_uint_t i; + + if (llcf->open_file_cache != NGX_CONF_UNSET_PTR) { + return "is duplicate"; + } + + value = cf->args->elts; + + max = 0; + inactive = 10; + valid = 60; + min_uses = 1; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "max=", 4) == 0) { + + max = ngx_atoi(value[i].data + 4, value[i].len - 4); + if (max == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "inactive=", 9) == 0) { + + s.len = value[i].len - 9; + s.data = value[i].data + 9; + + inactive = ngx_parse_time(&s, 1); + if (inactive < 0) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "min_uses=", 9) == 0) { + + min_uses = ngx_atoi(value[i].data + 9, value[i].len - 9); + if (min_uses == NGX_ERROR) { + goto failed; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "valid=", 6) == 0) { + + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + valid = ngx_parse_time(&s, 1); + if (valid < 0) { + goto failed; + } + + continue; + } + + if (ngx_strcmp(value[i].data, "off") == 0) { + + llcf->open_file_cache = NULL; + + continue; + } + + failed: + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid \"open_log_file_cache\" parameter \"%V\"", + &value[i]); + return NGX_CONF_ERROR; + } + + if (llcf->open_file_cache == NULL) { + return NGX_CONF_OK; + } + + if (max == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"open_log_file_cache\" must have \"max\" parameter"); + return NGX_CONF_ERROR; + } + + llcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive); + + if (llcf->open_file_cache) { + + llcf->open_file_cache_valid = valid; + llcf->open_file_cache_min_uses = min_uses; + + return NGX_CONF_OK; + } + + return NGX_CONF_ERROR; +} + + static ngx_int_t ngx_http_log_init(ngx_conf_t *cf) { 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 @@ -402,6 +402,7 @@ static ngx_keyval_t ngx_http_proxy_head { ngx_string("Host"), ngx_string("$proxy_host") }, { ngx_string("Connection"), ngx_string("close") }, { ngx_string("Keep-Alive"), ngx_string("") }, + { ngx_string("Expect"), ngx_string("") }, { ngx_null_string, ngx_null_string } }; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -96,7 +96,8 @@ ngx_http_static_handler(ngx_http_request clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; 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.3'; +our $VERSION = '0.7.4'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -639,23 +639,24 @@ sendfile(r, filename, offset = -1, bytes XSRETURN_EMPTY; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - - of.test_dir = 0; - of.valid = clcf->open_file_cache_valid; - of.min_uses = clcf->open_file_cache_min_uses; - of.errors = clcf->open_file_cache_errors; - of.events = clcf->open_file_cache_events; - path.len = ngx_strlen(filename); - path.data = ngx_pcalloc(r->pool, path.len + 1); + path.data = ngx_pnalloc(r->pool, path.len + 1); if (path.data == NULL) { XSRETURN_EMPTY; } (void) ngx_cpystrn(path.data, filename, path.len + 1); + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { 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 @@ -25,6 +25,7 @@ typedef struct { static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r); static ngx_int_t ngx_http_core_find_static_location(ngx_http_request_t *r, ngx_http_location_tree_node_t *node); +static ngx_int_t ngx_http_core_send_continue(ngx_http_request_t *r); static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf); static void *ngx_http_core_create_main_conf(ngx_conf_t *cf); @@ -771,7 +772,7 @@ ngx_http_core_find_config_phase(ngx_http { u_char *p; size_t len; - ngx_int_t rc; + ngx_int_t rc, expect; ngx_http_core_loc_conf_t *clcf; r->content_handler = NULL; @@ -815,6 +816,15 @@ ngx_http_core_find_config_phase(ngx_http return NGX_OK; } + if (r->headers_in.expect) { + expect = ngx_http_core_send_continue(r); + + if (expect != NGX_OK) { + ngx_http_finalize_request(r, expect); + return NGX_OK; + } + } + if (rc == NGX_DONE) { r->headers_out.location = ngx_list_push(&r->headers_out.headers); if (r->headers_out.location == NULL) { @@ -1244,6 +1254,45 @@ ngx_http_core_find_static_location(ngx_h } +static ngx_int_t +ngx_http_core_send_continue(ngx_http_request_t *r) +{ + ngx_int_t n; + ngx_str_t *expect; + + if (r->expect_tested) { + return NGX_OK; + } + + r->expect_tested = 1; + + expect = &r->headers_in.expect->value; + + if (expect->len != sizeof("100-continue") - 1 + || ngx_strncasecmp(expect->data, (u_char *) "100-continue", + sizeof("100-continue") - 1) + != 0) + { + return NGX_OK; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "send 100 Continue"); + + n = r->connection->send(r->connection, + (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF, + sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1); + + if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) { + return NGX_OK; + } + + /* we assume that such small packet should be send successfully */ + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r) { diff --git a/src/http/ngx_http_postpone_filter_module.c b/src/http/ngx_http_postpone_filter_module.c --- a/src/http/ngx_http_postpone_filter_module.c +++ b/src/http/ngx_http_postpone_filter_module.c @@ -168,7 +168,7 @@ ngx_http_postpone_filter_output_postpone pr = r->postponed; if (pr == NULL) { - return NGX_OK; + break; } if (pr->request) { @@ -196,7 +196,7 @@ ngx_http_postpone_filter_output_postpone } if (pr == NULL) { - return NGX_OK; + break; } out = pr->out; @@ -215,6 +215,17 @@ ngx_http_postpone_filter_output_postpone r->postponed = r->postponed->next; } + + if (r->out) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http postpone filter out again \"%V?%V\"", + &r->uri, &r->args); + + r->connection->data = r; + return NGX_AGAIN; + } + + return NGX_OK; } 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 @@ -106,6 +106,10 @@ ngx_http_header_t ngx_http_headers_in[] offsetof(ngx_http_headers_in_t, transfer_encoding), ngx_http_process_header_line }, + { ngx_string("Expect"), + offsetof(ngx_http_headers_in_t, expect), + ngx_http_process_unique_header_line }, + #if (NGX_HTTP_GZIP) { ngx_string("Accept-Encoding"), offsetof(ngx_http_headers_in_t, accept_encoding), 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 @@ -171,6 +171,7 @@ typedef struct { ngx_table_elt_t *if_range; ngx_table_elt_t *transfer_encoding; + ngx_table_elt_t *expect; #if (NGX_HTTP_GZIP) ngx_table_elt_t *accept_encoding; @@ -467,6 +468,7 @@ struct ngx_http_request_s { unsigned request_complete:1; unsigned request_output:1; unsigned header_sent:1; + unsigned expect_tested:1; unsigned done:1; unsigned utf8:1; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -994,7 +994,8 @@ ngx_http_script_file_code(ngx_http_scrip clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - of.test_dir = 0; + ngx_memzero(&of, sizeof(ngx_open_file_info_t)); + of.valid = clcf->open_file_cache_valid; of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -528,7 +528,7 @@ ngx_mail_auth_http_process_headers(ngx_m continue; } - p = ngx_pcalloc(s->connection->pool, size); + p = ngx_pnalloc(s->connection->pool, size); if (p == NULL) { ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool);