summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2007-09-03 10:30:19 +0000
committerJonathan Kolb <jon@b0g.us>2007-09-03 10:30:19 +0000
commit43335b39bb438e69c83be786506ec2350bccf21a (patch)
tree15aa3670cfc0e7adf333eda5185048dc75a11d5d
parent650585bcb7e759448160b21047939040b050e98d (diff)
downloadnginx-43335b39bb438e69c83be786506ec2350bccf21a.tar.gz
Changes with nginx 0.6.10 03 Sep 2007v0.6.10
*) Feature: the "open_file_cache", "open_file_cache_retest", and "open_file_cache_errors" directives. *) Bugfix: socket leak; bug appeared in 0.6.7. *) Bugfix: a charset set by the "charset" directive was not appended to the "Content-Type" header set by $r->send_http_header(). *) Bugfix: a segmentation fault might occur in worker process if /dev/poll method was used.
-rw-r--r--CHANGES14
-rw-r--r--CHANGES.ru16
-rw-r--r--auto/sources2
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_conf_file.c2
-rw-r--r--src/core/ngx_conf_file.h4
-rw-r--r--src/core/ngx_connection.c2
-rw-r--r--src/core/ngx_core.h1
-rw-r--r--src/core/ngx_open_file_cache.c733
-rw-r--r--src/core/ngx_open_file_cache.h101
-rw-r--r--src/event/modules/ngx_devpoll_module.c80
-rw-r--r--src/event/modules/ngx_kqueue_module.c30
-rw-r--r--src/event/ngx_event.h52
-rw-r--r--src/event/ngx_event_openssl.c2
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c3
-rw-r--r--src/http/modules/ngx_http_flv_module.c82
-rw-r--r--src/http/modules/ngx_http_index_module.c121
-rw-r--r--src/http/modules/ngx_http_static_module.c156
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/modules/perl/nginx.xs67
-rw-r--r--src/http/ngx_http_core_module.c125
-rw-r--r--src/http/ngx_http_core_module.h5
-rw-r--r--src/http/ngx_http_request.c2
-rw-r--r--src/http/ngx_http_request_body.c5
-rw-r--r--src/http/ngx_http_script.c60
-rw-r--r--src/http/ngx_http_upstream_round_robin.c8
-rw-r--r--src/os/unix/ngx_process_cycle.c39
27 files changed, 1361 insertions, 355 deletions
diff --git a/CHANGES b/CHANGES
index 7765edc6b..ee5c5423c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,18 @@
+Changes with nginx 0.6.10 03 Sep 2007
+
+ *) Feature: the "open_file_cache", "open_file_cache_retest", and
+ "open_file_cache_errors" directives.
+
+ *) Bugfix: socket leak; bug appeared in 0.6.7.
+
+ *) Bugfix: a charset set by the "charset" directive was not appended to
+ the "Content-Type" header set by $r->send_http_header().
+
+ *) Bugfix: a segmentation fault might occur in worker process if
+ /dev/poll method was used.
+
+
Changes with nginx 0.6.9 28 Aug 2007
*) Bugfix: a worker process may got caught in an endless loop, if the
diff --git a/CHANGES.ru b/CHANGES.ru
index 45199805e..3b86d279a 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,19 @@
+Изменения в nginx 0.6.10 03.09.2007
+
+ *) Добавление: директивы open_file_cache, open_file_cache_retest и
+ open_file_cache_errors.
+
+ *) Исправление: утечка сокетов; ошибка появилась в 0.6.7.
+
+ *) Исправление: В строку заголовка ответа "Content-Type", указанную в
+ методе $r->send_http_header(), не добавлялась кодировка, указанная в
+ директиве charset.
+
+ *) Исправление: при использовании метода /dev/poll в рабочем процессе
+ мог произойти segmentation fault.
+
+
Изменения в nginx 0.6.9 28.08.2007
*) Исправление: рабочий процесс мог зациклиться при использовании
@@ -63,7 +78,6 @@
*) Исправление: если в директиве auth_http был задан неправильный
адрес, то в рабочем процессе происходил segmentation fault.
- <br>
*) Исправление: теперь по умолчанию nginx использует значение 511 для
listen backlog на всех платформах, кроме FreeBSD.
diff --git a/auto/sources b/auto/sources
index 44d82ee02..383214dfc 100644
--- a/auto/sources
+++ b/auto/sources
@@ -29,6 +29,7 @@ CORE_DEPS="src/core/nginx.h \
src/core/ngx_connection.h \
src/core/ngx_cycle.h \
src/core/ngx_conf_file.h \
+ src/core/ngx_open_file_cache.h \
src/core/ngx_garbage_collector.h"
@@ -55,6 +56,7 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_spinlock.c \
src/core/ngx_cpuinfo.c \
src/core/ngx_conf_file.c \
+ src/core/ngx_open_file_cache.c \
src/core/ngx_garbage_collector.c"
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 663956a9c..97c8dfb93 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.6.9"
+#define NGINX_VERSION "0.6.10"
#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
index 514d55bad..0e3523dda 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -366,7 +366,7 @@ not_allowed:
invalid:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid number arguments in \"%s\" directive",
+ "invalid number of arguments in \"%s\" directive",
name->data);
return NGX_ERROR;
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index 2e91d0b8c..c3e3e9a91 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -257,8 +257,8 @@ char *ngx_conf_check_num_bounds(ngx_conf_t *cf, void *post, void *data);
}
#define ngx_conf_merge_ptr_value(conf, prev, default) \
- if (conf == NULL) { \
- conf = (prev == NULL) ? default : prev; \
+ if (conf == NGX_CONF_UNSET_PTR) { \
+ conf = (prev == NGX_CONF_UNSET_PTR) ? default : prev; \
}
#define ngx_conf_merge_uint_value(conf, prev, default) \
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index 87219f236..af2f25cd8 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -735,7 +735,7 @@ ngx_close_connection(ngx_connection_t *c)
/* we use ngx_cycle->log because c->log was in c->pool */
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
- ngx_close_socket_n " failed");
+ ngx_close_socket_n " %d failed", fd);
}
}
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index c54884b52..a43599ae7 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -71,6 +71,7 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
#endif
#include <ngx_process_cycle.h>
#include <ngx_conf_file.h>
+#include <ngx_open_file_cache.h>
#include <ngx_os.h>
#include <ngx_connection.h>
diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c
new file mode 100644
index 000000000..dab98b3ff
--- /dev/null
+++ b/src/core/ngx_open_file_cache.c
@@ -0,0 +1,733 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_event.h>
+
+
+/*
+ * open file cache caches
+ * open file handles with stat() info;
+ * directories stat() info;
+ * files and directories errors: not found, access denied, etc.
+ */
+
+
+static void ngx_open_file_cache_cleanup(void *data);
+static void ngx_open_file_cleanup(void *data);
+static void ngx_close_cached_file(ngx_open_file_cache_t *cache,
+ ngx_cached_open_file_t *file, ngx_log_t *log);
+static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of,
+ ngx_log_t *log);
+static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache,
+ ngx_uint_t n, ngx_log_t *log);
+static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static void ngx_open_file_cache_remove(ngx_event_t *ev);
+
+
+ngx_open_file_cache_t *
+ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive)
+{
+ ngx_rbtree_node_t *sentinel;
+ ngx_pool_cleanup_t *cln;
+ ngx_open_file_cache_t *cache;
+
+ cache = ngx_palloc(pool, sizeof(ngx_open_file_cache_t));
+ if (cache == NULL) {
+ return NULL;
+ }
+
+ cache->list_head.prev = NULL;
+ cache->list_head.next = &cache->list_tail;
+
+ cache->list_tail.prev = &cache->list_head;
+ cache->list_tail.next = NULL;
+
+ sentinel = ngx_palloc(pool, sizeof(ngx_rbtree_node_t));
+ if (sentinel == NULL) {
+ return NULL;
+ }
+
+ ngx_rbtree_sentinel_init(sentinel);
+
+ cache->rbtree.root = sentinel;
+ cache->rbtree.sentinel = sentinel;
+ cache->rbtree.insert = ngx_open_file_cache_rbtree_insert_value;
+
+ cache->current = 0;
+ cache->max = max;
+ cache->inactive = inactive;
+
+ cln = ngx_pool_cleanup_add(pool, 0);
+ if (cln == NULL) {
+ return NULL;
+ }
+
+ cln->handler = ngx_open_file_cache_cleanup;
+ cln->data = cache;
+
+ return cache;
+}
+
+
+static void
+ngx_open_file_cache_cleanup(void *data)
+{
+ ngx_open_file_cache_t *cache = data;
+
+ ngx_cached_open_file_t *file;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "open file cache cleanup");
+
+ for ( ;; ) {
+
+ file = cache->list_tail.prev;
+
+ if (file == &cache->list_head) {
+ break;
+ }
+
+ file->next->prev = file->prev;
+ file->prev->next = file->next;
+
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+ "delete cached open file: %s", file->name);
+
+ if (!file->err && !file->is_dir) {
+ file->close = 1;
+ file->count = 0;
+ ngx_close_cached_file(cache, file, ngx_cycle->log);
+
+ } else {
+ ngx_free(file->name);
+ ngx_free(file);
+ }
+ }
+
+ if (cache->current) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%d items still leave in open file cache",
+ cache->current);
+ }
+
+ if (cache->rbtree.root != cache->rbtree.sentinel) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "rbtree still is not empty in open file cache");
+
+ }
+}
+
+
+ngx_int_t
+ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_pool_t *pool)
+{
+ time_t now;
+ uint32_t hash;
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_pool_cleanup_t *cln;
+ ngx_cached_open_file_t *file;
+ ngx_pool_cleanup_file_t *clnf;
+ ngx_open_file_cache_event_t *fev;
+ ngx_open_file_cache_cleanup_t *ofcln;
+
+ of->err = 0;
+
+ if (cache == NULL) {
+
+ cln = ngx_pool_cleanup_add(pool, sizeof(ngx_pool_cleanup_file_t));
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ rc = ngx_open_and_stat_file(name->data, of, pool->log);
+
+ if (rc == NGX_OK && !of->is_dir) {
+ cln->handler = ngx_pool_cleanup_file;
+ clnf = cln->data;
+
+ clnf->fd = of->fd;
+ clnf->name = name->data;
+ clnf->log = pool->log;
+ }
+
+ return rc;
+ }
+
+ cln = ngx_pool_cleanup_add(pool, sizeof(ngx_open_file_cache_cleanup_t));
+ if (cln == NULL) {
+ return NGX_ERROR;
+ }
+
+ hash = ngx_crc32_long(name->data, name->len);
+
+ node = cache->rbtree.root;
+ sentinel = cache->rbtree.sentinel;
+
+ now = ngx_time();
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ do {
+ file = (ngx_cached_open_file_t *) node;
+
+ rc = ngx_strcmp(name->data, file->name);
+
+ if (rc == 0) {
+
+ file->next->prev = file->prev;
+ file->prev->next = file->next;
+
+ if (file->event || now - file->created < of->retest) {
+ if (file->err == 0) {
+ of->fd = file->fd;
+ of->uniq = file->uniq;
+ of->mtime = file->mtime;
+ of->size = file->size;
+
+ of->is_dir = file->is_dir;
+ of->is_file = file->is_file;
+ of->is_link = file->is_link;
+ of->is_exec = file->is_exec;
+
+ if (!file->is_dir) {
+ file->count++;
+ }
+
+ } else {
+ of->err = file->err;
+ }
+
+ goto found;
+ }
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
+ "retest open file: %s, fd:%d, c:%d, e:%d",
+ file->name, file->fd, file->count, file->err);
+
+ if (file->is_dir) {
+
+ /*
+ * chances that directory became file are very small
+ * so test_dir flag allows to use a single ngx_file_info()
+ * syscall instead of three syscalls
+ */
+
+ of->test_dir = 1;
+ }
+
+ rc = ngx_open_and_stat_file(name->data, of, pool->log);
+
+ if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
+ goto failed;
+ }
+
+ if (of->is_dir) {
+ if (file->is_dir || file->err) {
+ goto update;
+ }
+
+ /* file became directory */
+
+ } else if (of->err == 0) { /* file */
+
+ if (file->is_dir || file->err) {
+ goto update;
+ }
+
+ 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);
+ }
+
+ of->fd = file->fd;
+ file->count++;
+
+ goto renew;
+ }
+
+ /* file was changed */
+
+ } else { /* error to cache */
+
+ if (file->err || file->is_dir) {
+ goto update;
+ }
+
+ /* file was removed, etc. */
+ }
+
+ if (file->count == 0) {
+ if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed",
+ name->data);
+ }
+
+ goto update;
+ }
+
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ file->close = 1;
+
+ goto create;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+
+ } while (node != sentinel && hash == node->key);
+
+ break;
+ }
+
+ /* not found */
+
+ file = NULL;
+
+ rc = ngx_open_and_stat_file(name->data, of, pool->log);
+
+ if (rc != NGX_OK && (of->err == 0 || !of->errors)) {
+ goto failed;
+ }
+
+create:
+
+ if (cache->current >= cache->max) {
+ ngx_expire_old_cached_files(cache, 0, pool->log);
+ }
+
+ file = ngx_alloc(sizeof(ngx_cached_open_file_t), pool->log);
+
+ if (file == NULL) {
+ goto failed;
+ }
+
+ file->name = ngx_alloc(name->len + 1, pool->log);
+
+ if (file->name == NULL) {
+ ngx_free(file);
+ file = NULL;
+ goto failed;
+ }
+
+ ngx_cpystrn(file->name, name->data, name->len + 1);
+
+ file->node.key = hash;
+
+ ngx_rbtree_insert(&cache->rbtree, &file->node);
+
+ cache->current++;
+
+ file->count = 0;
+
+update:
+
+ if (of->events
+ && (ngx_event_flags & NGX_USE_VNODE_EVENT)
+ && of->fd != NGX_INVALID_FILE)
+ {
+ file->event = ngx_calloc(sizeof(ngx_event_t), pool->log);
+ if (file->event== NULL) {
+ goto failed;
+ }
+
+ fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), pool->log);
+ if (fev == NULL) {
+ goto failed;
+ }
+
+ fev->fd = of->fd;
+ fev->file = file;
+ fev->cache = cache;
+
+ file->event->handler = ngx_open_file_cache_remove;
+ file->event->data = fev;
+
+ /*
+ * although vnode event may be called while ngx_cycle->poll
+ * destruction; however, cleanup procedures are run before any
+ * memory freeing and events will be canceled.
+ */
+
+ file->event->log = ngx_cycle->log;
+
+ if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT)
+ != NGX_OK)
+ {
+ ngx_free(file->event->data);
+ ngx_free(file->event);
+ goto failed;
+ }
+
+ } else {
+ file->event = NULL;
+ }
+
+ file->fd = of->fd;
+ file->err = of->err;
+
+ if (of->err == 0) {
+ file->uniq = of->uniq;
+ file->mtime = of->mtime;
+ file->size = of->size;
+
+ file->close = 0;
+
+ file->is_dir = of->is_dir;
+ file->is_file = of->is_file;
+ file->is_link = of->is_link;
+ file->is_exec = of->is_exec;
+
+ if (!of->is_dir) {
+ file->count++;
+ }
+ }
+
+renew:
+
+ file->created = now;
+
+found:
+
+ file->accessed = now;
+
+ /* add to the inactive list head */
+
+ file->next = cache->list_head.next;
+ file->next->prev = file;
+ file->prev = &cache->list_head;
+ cache->list_head.next = file;
+
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0,
+ "cached open file: %s, fd:%d, c:%d, e:%d",
+ file->name, file->fd, file->count, file->err);
+
+ if (of->err == 0) {
+
+ if (!of->is_dir) {
+ cln->handler = ngx_open_file_cleanup;
+ ofcln = cln->data;
+
+ ofcln->cache = cache;
+ ofcln->file = file;
+ ofcln->log = pool->log;
+ }
+
+ return NGX_OK;
+ }
+
+ return NGX_ERROR;
+
+failed:
+
+ if (file && file->count == 0) {
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file->name);
+ }
+
+ ngx_free(file->name);
+ ngx_free(file);
+ }
+
+ if (of->fd != NGX_INVALID_FILE) {
+ 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);
+ }
+ }
+
+ return NGX_ERROR;
+}
+
+
+static ngx_int_t
+ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log)
+{
+ ngx_fd_t fd;
+ ngx_file_info_t fi;
+
+ of->fd = NGX_INVALID_FILE;
+
+ if (of->test_dir) {
+
+ if (ngx_file_info(name, &fi) == -1) {
+ of->err = ngx_errno;
+
+ return NGX_ERROR;
+ }
+
+ 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->is_dir) {
+ return NGX_OK;
+ }
+ }
+
+ fd = ngx_open_file(name, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+
+ if (fd == NGX_INVALID_FILE) {
+ of->err = ngx_errno;
+ return NGX_ERROR;
+ }
+
+ if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", name);
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", name);
+ }
+
+ return NGX_ERROR;
+ }
+
+ if (ngx_is_dir(&fi)) {
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", name);
+ }
+
+ fd = NGX_INVALID_FILE;
+ }
+
+ of->fd = fd;
+ 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);
+
+ return NGX_OK;
+}
+
+
+static void
+ngx_open_file_cleanup(void *data)
+{
+ ngx_open_file_cache_cleanup_t *c = data;
+
+ c->file->count--;
+
+ ngx_close_cached_file(c->cache, c->file, c->log);
+
+ /* drop one or two expired open files */
+ ngx_expire_old_cached_files(c->cache, 1, c->log);
+}
+
+
+static void
+ngx_close_cached_file(ngx_open_file_cache_t *cache,
+ ngx_cached_open_file_t *file, ngx_log_t *log)
+{
+ ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0,
+ "close cached open file: %s, fd:%d, c:%d, %d",
+ file->name, file->fd, file->count, file->close);
+
+ if (!file->close) {
+
+ file->accessed = ngx_time();
+
+ if (cache->list_head.next != file) {
+
+ /* delete from inactive list */
+
+ file->next->prev = file->prev;
+ file->prev->next = file->next;
+
+ /* add to the inactive list head */
+
+ file->next = cache->list_head.next;
+ file->next->prev = file;
+ file->prev = &cache->list_head;
+ cache->list_head.next = file;
+ }
+
+ return;
+ }
+
+ if (file->event) {
+ (void) ngx_del_event(file->event, NGX_VNODE_EVENT,
+ file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT);
+
+ ngx_free(file->event->data);
+ ngx_free(file->event);
+ file->event = NULL;
+ }
+
+ if (file->count) {
+ return;
+ }
+
+ if (ngx_close_file(file->fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", file->name);
+ }
+
+ ngx_free(file->name);
+ ngx_free(file);
+}
+
+
+static void
+ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n,
+ ngx_log_t *log)
+{
+ time_t now;
+ ngx_cached_open_file_t *file;
+
+ now = ngx_time();
+
+ /*
+ * n == 1 deletes one or two inactive files
+ * n == 0 deletes least recently used file by force
+ * and one or two inactive files
+ */
+
+ while (n < 3) {
+
+ file = cache->list_tail.prev;
+
+ if (file == &cache->list_head) {
+ return;
+ }
+
+ if (n++ != 0 && now - file->accessed <= cache->inactive) {
+ return;
+ }
+
+ file->next->prev = file->prev;
+ file->prev->next = file->next;
+
+ ngx_rbtree_delete(&cache->rbtree, &file->node);
+
+ cache->current--;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, log, 0,
+ "expire cached open file: %s", file->name);
+
+ if (!file->err && !file->is_dir) {
+ file->close = 1;
+ ngx_close_cached_file(cache, file, log);
+
+ } else {
+ ngx_free(file->name);
+ ngx_free(file);
+ }
+ }
+}
+
+
+static void
+ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_cached_open_file_t *file, *file_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ file = (ngx_cached_open_file_t *) node;
+ file_temp = (ngx_cached_open_file_t *) temp;
+
+ p = (ngx_strcmp(file->name, file_temp->name) < 0)
+ ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+
+static void
+ngx_open_file_cache_remove(ngx_event_t *ev)
+{
+ ngx_cached_open_file_t *file;
+ ngx_open_file_cache_event_t *fev;
+
+ fev = ev->data;
+ file = fev->file;
+
+ file->next->prev = file->prev;
+ file->prev->next = file->next;
+
+ ngx_rbtree_delete(&fev->cache->rbtree, &file->node);
+
+ fev->cache->current--;
+
+ /* NGX_ONESHOT_EVENT was already deleted */
+ file->event = NULL;
+
+ file->close = 1;
+
+ ngx_close_cached_file(fev->cache, file, ev->log);
+
+ /* free memory only when fev->cache and fev->file are already not needed */
+
+ ngx_free(ev->data);
+ ngx_free(ev);
+}
diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h
new file mode 100644
index 000000000..cc0d899a2
--- /dev/null
+++ b/src/core/ngx_open_file_cache.h
@@ -0,0 +1,101 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#ifndef _NGX_OPEN_FILE_CACHE_H_INCLUDED_
+#define _NGX_OPEN_FILE_CACHE_H_INCLUDED_
+
+
+typedef struct {
+ ngx_fd_t fd;
+ ngx_file_uniq_t uniq;
+ time_t mtime;
+ off_t size;
+ ngx_err_t err;
+
+ time_t retest;
+
+ unsigned test_dir:1;
+ unsigned errors:1;
+ unsigned events:1;
+
+ unsigned is_dir:1;
+ unsigned is_file:1;
+ unsigned is_link:1;
+ unsigned is_exec:1;
+} ngx_open_file_info_t;
+
+
+typedef struct ngx_cached_open_file_s ngx_cached_open_file_t;
+
+struct ngx_cached_open_file_s {
+ ngx_rbtree_node_t node;
+ ngx_cached_open_file_t *prev;
+ ngx_cached_open_file_t *next;
+
+ u_char *name;
+ time_t created;
+ time_t accessed;
+
+ ngx_fd_t fd;
+ ngx_file_uniq_t uniq;
+ time_t mtime;
+ off_t size;
+ ngx_err_t err;
+
+ unsigned count:24;
+ unsigned close:1;
+
+ unsigned is_dir:1;
+ unsigned is_file:1;
+ unsigned is_link:1;
+ unsigned is_exec:1;
+
+ ngx_event_t *event;
+};
+
+
+typedef struct {
+ ngx_rbtree_t rbtree;
+ ngx_cached_open_file_t list_head;
+ ngx_cached_open_file_t list_tail;
+
+ ngx_uint_t current;
+ ngx_uint_t max;
+ time_t inactive;
+} ngx_open_file_cache_t;
+
+
+typedef struct {
+ ngx_open_file_cache_t *cache;
+ ngx_cached_open_file_t *file;
+ ngx_log_t *log;
+} ngx_open_file_cache_cleanup_t;
+
+
+typedef struct {
+
+ /* ngx_connection_t stub to allow use c->fd as event ident */
+ void *data;
+ ngx_event_t *read;
+ ngx_event_t *write;
+ ngx_fd_t fd;
+
+ ngx_cached_open_file_t *file;
+ ngx_open_file_cache_t *cache;
+} ngx_open_file_cache_event_t;
+
+
+ngx_open_file_cache_t *ngx_open_file_cache_init(ngx_pool_t *pool,
+ ngx_uint_t max, time_t inactive);
+ngx_int_t ngx_open_cached_file(ngx_open_file_cache_t *cache, ngx_str_t *name,
+ ngx_open_file_info_t *of, ngx_pool_t *pool);
+
+
+#endif /* _NGX_OPEN_FILE_CACHE_H_INCLUDED_ */
diff --git a/src/event/modules/ngx_devpoll_module.c b/src/event/modules/ngx_devpoll_module.c
index be523add9..903efe6b5 100644
--- a/src/event/modules/ngx_devpoll_module.c
+++ b/src/event/modules/ngx_devpoll_module.c
@@ -13,8 +13,9 @@
/* Solaris declarations */
-#define POLLREMOVE 0x0800
-#define DP_POLL 0xD001
+#define POLLREMOVE 0x0800
+#define DP_POLL 0xD001
+#define DP_ISPOLLED 0xD002
struct dvpoll {
struct pollfd *dp_fds;
@@ -255,10 +256,16 @@ ngx_devpoll_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
ev->active = 0;
if (flags & NGX_CLOSE_EVENT) {
+ e = (event == POLLIN) ? c->write : c->read;
+
+ if (e) {
+ e->active = 0;
+ }
+
return NGX_OK;
}
- /* restore the paired event if it exists */
+ /* restore the pair event if it exists */
if (event == POLLIN) {
e = c->write;
@@ -330,13 +337,15 @@ ngx_int_t
ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags)
{
- int events, revents;
+ int events, revents, rc;
size_t n;
+ ngx_fd_t fd;
ngx_err_t err;
ngx_int_t i;
ngx_uint_t level;
ngx_event_t *rev, *wev, **queue;
ngx_connection_t *c;
+ struct pollfd pfd;
struct dvpoll dvp;
/* NGX_TIMER_INFINITE == INFTIM */
@@ -401,34 +410,77 @@ ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_mutex_lock(ngx_posted_events_mutex);
for (i = 0; i < events; i++) {
- c = ngx_cycle->files[event_list[i].fd];
- if (c->fd == -1) {
- if (c->read->closed) {
- continue;
+ fd = event_list[i].fd;
+ revents = event_list[i].revents;
+
+ c = ngx_cycle->files[fd];
+
+ if (c == NULL || c->fd == -1) {
+
+ pfd.fd = fd;
+ pfd.events = 0;
+ pfd.revents = 0;
+
+ rc = ioctl(dp, DP_ISPOLLED, &pfd);
+
+ switch (rc) {
+
+ case -1:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "ioctl(DP_ISPOLLED) failed for socket %d, event",
+ fd, revents);
+ break;
+
+ case 0:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "phantom event %04Xd for closed and removed socket %d",
+ revents, fd);
+ break;
+
+ default:
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+ "unexpected event %04Xd for closed and removed socket %d, ",
+ "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
+ revents, fd, rc, pfd.fd, pfd.revents);
+
+ pfd.fd = fd;
+ pfd.events = POLLREMOVE;
+ pfd.revents = 0;
+
+ if (write(dp, &pfd, sizeof(struct pollfd))
+ != (ssize_t) sizeof(struct pollfd))
+ {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "write(/dev/poll) for %d failed, fd");
+ }
+
+ if (close(fd) == -1) {
+ ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+ "close(%d) failed", fd);
+ }
+
+ break;
}
- ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");
continue;
}
- revents = event_list[i].revents;
-
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
- event_list[i].fd, event_list[i].events, revents);
+ fd, event_list[i].events, revents);
if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
"ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
- event_list[i].fd, event_list[i].events, revents);
+ fd, event_list[i].events, revents);
}
if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
"strange ioctl(DP_POLL) events "
"fd:%d ev:%04Xd rev:%04Xd",
- event_list[i].fd, event_list[i].events, revents);
+ fd, event_list[i].events, revents);
}
if ((revents & (POLLERR|POLLHUP|POLLNVAL))
diff --git a/src/event/modules/ngx_kqueue_module.c b/src/event/modules/ngx_kqueue_module.c
index c5fd6d80e..1b1f9712f 100644
--- a/src/event/modules/ngx_kqueue_module.c
+++ b/src/event/modules/ngx_kqueue_module.c
@@ -200,7 +200,9 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
}
}
- ngx_event_flags = 0;
+ ngx_event_flags = NGX_USE_ONESHOT_EVENT
+ |NGX_USE_KQUEUE_EVENT
+ |NGX_USE_VNODE_EVENT;
#if (NGX_HAVE_TIMER_EVENT)
@@ -226,8 +228,6 @@ ngx_kqueue_init(ngx_cycle_t *cycle, ngx_msec_t timer)
#endif
- ngx_event_flags |= NGX_USE_ONESHOT_EVENT|NGX_USE_KQUEUE_EVENT;
-
#if (NGX_HAVE_CLEAR_EVENT)
ngx_event_flags |= NGX_USE_CLEAR_EVENT;
#else
@@ -389,10 +389,12 @@ ngx_kqueue_del_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
if (flags & NGX_DISABLE_EVENT) {
ev->disabled = 1;
+
+ } else {
+ flags |= EV_DELETE;
}
- rc = ngx_kqueue_set_event(ev, event,
- flags & NGX_DISABLE_EVENT ? EV_DISABLE : EV_DELETE);
+ rc = ngx_kqueue_set_event(ev, event, flags);
ngx_mutex_unlock(list_mutex);
@@ -409,7 +411,7 @@ ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
c = ev->data;
- ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, ev->log, 0,
"kevent set event: %d: ft:%i fl:%04Xi",
c->fd, filter, flags);
@@ -466,6 +468,22 @@ ngx_kqueue_set_event(ngx_event_t *ev, ngx_int_t filter, ngx_uint_t flags)
ev->index = nchanges;
nchanges++;
+ if (flags & NGX_FLUSH_EVENT) {
+ ts.tv_sec = 0;
+ ts.tv_nsec = 0;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "kevent flush");
+
+ if (kevent(ngx_kqueue, change_list, (int) nchanges, NULL, 0, &ts)
+ == -1)
+ {
+ ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, "kevent() failed");
+ return NGX_ERROR;
+ }
+
+ nchanges = 0;
+ }
+
return NGX_OK;
}
diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h
index a2b7c5cc5..ed6ba29c1 100644
--- a/src/event/ngx_event.h
+++ b/src/event/ngx_event.h
@@ -41,7 +41,7 @@ struct ngx_event_s {
unsigned accept:1;
- /* used to detect the stale events in kqueue, rt signals and epoll */
+ /* used to detect the stale events in kqueue, rtsig, and epoll */
unsigned instance:1;
/*
@@ -247,8 +247,7 @@ extern ngx_event_actions_t ngx_event_actions;
#define NGX_USE_LOWAT_EVENT 0x00000010
/*
- * The event filter requires to do i/o operation until EAGAIN:
- * epoll, rt signals.
+ * The event filter requires to do i/o operation until EAGAIN: epoll, rtsig.
*/
#define NGX_USE_GREEDY_EVENT 0x00000020
@@ -258,7 +257,7 @@ extern ngx_event_actions_t ngx_event_actions;
#define NGX_USE_EPOLL_EVENT 0x00000040
/*
- * No need to add or delete the event filters: rt signals.
+ * No need to add or delete the event filters: rtsig.
*/
#define NGX_USE_RTSIG_EVENT 0x00000080
@@ -276,13 +275,13 @@ extern ngx_event_actions_t ngx_event_actions;
/*
* The event filter has no opaque data and requires file descriptors table:
- * poll, /dev/poll, rt signals.
+ * poll, /dev/poll, rtsig.
*/
#define NGX_USE_FD_EVENT 0x00000400
/*
* The event module handles periodic or absolute timer event by itself:
- * kqueue in FreeBSD 4.4 and NetBSD 2.0, Solaris 10's event ports.
+ * kqueue in FreeBSD 4.4, NetBSD 2.0, and MacOSX 10.4, Solaris 10's event ports.
*/
#define NGX_USE_TIMER_EVENT 0x00000800
@@ -290,19 +289,37 @@ extern ngx_event_actions_t ngx_event_actions;
* All event filters on file descriptor are deleted after a notification:
* Solaris 10's event ports.
*/
-#define NGX_USE_EVENTPORT_EVENT 0x00001000
+#define NGX_USE_EVENTPORT_EVENT 0x00001000
+/*
+ * The event filter support vnode notifications: kqueue.
+ */
+#define NGX_USE_VNODE_EVENT 0x00002000
/*
- * The event filter is deleted before the closing file.
- * Has no meaning for select, poll, kqueue, epoll.
- * /dev/poll: we need to flush POLLREMOVE event before closing file
+ * The event filter is deleted just before the closing file.
+ * Has no meaning for select and poll.
+ * kqueue, epoll, rtsig, eventport: allows to avoid explicit delete,
+ * because filter automatically is deleted
+ * on file close,
+ *
+ * /dev/poll: we need to flush POLLREMOVE event
+ * before closing file.
*/
-
#define NGX_CLOSE_EVENT 1
+
+/*
+ * disable temporarily event filter, this may avoid locks
+ * in kernel malloc()/free(): kqueue.
+ */
#define NGX_DISABLE_EVENT 2
+/*
+ * event must be passed to kernel right now, do not wait until batch processing.
+ */
+#define NGX_FLUSH_EVENT 4
+
/* these flags have a meaning only for kqueue */
#define NGX_LOWAT_EVENT 0
@@ -318,11 +335,11 @@ extern ngx_event_actions_t ngx_event_actions;
#define NGX_VNODE_EVENT EVFILT_VNODE
/*
- * NGX_CLOSE_EVENT and NGX_LOWAT_EVENT are the module flags and they would
- * not go into a kernel so we need to choose the value that would not interfere
- * with any existent and future kqueue flags. kqueue has such values -
- * EV_FLAG1, EV_EOF and EV_ERROR. They are reserved and cleared on a kernel
- * entrance.
+ * NGX_CLOSE_EVENT, NGX_LOWAT_EVENT, and NGX_FLUSH_EVENT are the module flags
+ * and they must not go into a kernel so we need to choose the value
+ * that must not interfere with any existent and future kqueue flags.
+ * kqueue has such values - EV_FLAG1, EV_EOF, and EV_ERROR:
+ * they are reserved and cleared on a kernel entrance.
*/
#undef NGX_CLOSE_EVENT
#define NGX_CLOSE_EVENT EV_EOF
@@ -330,6 +347,9 @@ extern ngx_event_actions_t ngx_event_actions;
#undef NGX_LOWAT_EVENT
#define NGX_LOWAT_EVENT EV_FLAG1
+#undef NGX_FLUSH_EVENT
+#define NGX_FLUSH_EVENT EV_ERROR
+
#define NGX_LEVEL_EVENT 0
#define NGX_ONESHOT_EVENT EV_ONESHOT
#define NGX_CLEAR_EVENT EV_CLEAR
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 4971d9359..be24d9c77 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -1601,7 +1601,7 @@ ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
}
if (n++ != 0 && sess_id->expire > tp->sec) {
- break;
+ return;
}
sess_id->next->prev = sess_id->prev;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index c1ce79ce7..ac14d75ce 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1640,7 +1640,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.hide_headers = NULL;
* conf->upstream.pass_headers = NULL;
- * conf->upstream.catch_stderr = NULL;
* conf->upstream.schema = { 0, NULL };
* conf->upstream.uri = { 0, NULL };
* conf->upstream.location = NULL;
@@ -1675,6 +1674,8 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
/* "fastcgi_cyclic_temp_file" is disabled */
conf->upstream.cyclic_temp_file = 0;
+ conf->catch_stderr = NGX_CONF_UNSET_PTR;
+
return conf;
}
diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c
index cc258ea23..04327d938 100644
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -60,20 +60,17 @@ ngx_module_t ngx_http_flv_module = {
static ngx_int_t
ngx_http_flv_handler(ngx_http_request_t *r)
{
- u_char *p;
+ u_char *p, *last;
off_t start, len;
size_t root;
ngx_fd_t fd;
ngx_int_t rc;
ngx_uint_t level, i;
ngx_str_t path;
- ngx_err_t err;
ngx_log_t *log;
ngx_buf_t *b;
ngx_chain_t out[2];
- ngx_file_info_t fi;
- ngx_pool_cleanup_t *cln;
- ngx_pool_cleanup_file_t *clnf;
+ ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
@@ -95,64 +92,66 @@ ngx_http_flv_handler(ngx_http_request_t *r)
return rc;
}
- if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) {
+ last = ngx_http_map_uri_to_path(r, &path, &root, 0);
+ if (last == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
log = r->connection->log;
+ path.len = last - path.data;
+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
- "http flv filename: \"%s\"", path.data);
+ "http flv filename: \"%V\"", &path);
- cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
- if (cln == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ of.test_dir = 0;
+ of.retest = clcf->open_file_cache_retest;
+ of.errors = clcf->open_file_cache_errors;
+ of.events = clcf->open_file_cache_events;
+
+ rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
+
+ if (rc == NGX_ERROR) {
- fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ switch (of.err) {
- if (fd == NGX_INVALID_FILE) {
- err = ngx_errno;
+ case 0:
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+
+ case NGX_ENOENT:
+ case NGX_ENOTDIR:
+ case NGX_ENAMETOOLONG:
- if (err == NGX_ENOENT
- || err == NGX_ENOTDIR
- || err == NGX_ENAMETOOLONG)
- {
level = NGX_LOG_ERR;
rc = NGX_HTTP_NOT_FOUND;
+ break;
+
+ case NGX_EACCES:
- } else if (err == NGX_EACCES) {
level = NGX_LOG_ERR;
rc = NGX_HTTP_FORBIDDEN;
+ break;
+
+ default:
- } else {
level = NGX_LOG_CRIT;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
}
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
- ngx_log_error(level, log, err,
+ ngx_log_error(level, log, of.err,
ngx_open_file_n " \"%s\" failed", path.data);
}
return rc;
}
- if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", path.data);
+ fd = of.fd;
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", path.data);
- }
-
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
- if (!ngx_is_file(&fi)) {
+ if (!of.is_file) {
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
@@ -163,7 +162,7 @@ ngx_http_flv_handler(ngx_http_request_t *r)
}
start = 0;
- len = ngx_file_size(&fi);
+ len = of.size;
i = 1;
if (r->args.len) {
@@ -187,16 +186,9 @@ ngx_http_flv_handler(ngx_http_request_t *r)
log->action = "sending flv to client";
- cln->handler = ngx_pool_cleanup_file;
- clnf = cln->data;
-
- clnf->fd = fd;
- clnf->name = path.data;
- clnf->log = r->pool->log;
-
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = len;
- r->headers_out.last_modified_time = ngx_file_mtime(&fi);
+ r->headers_out.last_modified_time = of.mtime;
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -237,7 +229,7 @@ ngx_http_flv_handler(ngx_http_request_t *r)
}
b->file_pos = start;
- b->file_last = ngx_file_size(&fi);
+ b->file_last = of.size;
b->in_file = b->file_last ? 1: 0;
b->last_buf = 1;
diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c
index d0f415fce..6f81a49cf 100644
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -38,7 +38,7 @@ typedef struct {
static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
- ngx_http_index_ctx_t *ctx);
+ ngx_http_core_loc_conf_t *clcf, ngx_http_index_ctx_t *ctx);
static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
ngx_http_index_ctx_t *ctx, ngx_err_t err);
@@ -59,17 +59,6 @@ static ngx_command_t ngx_http_index_commands[] = {
0,
NULL },
-#if (NGX_HTTP_CACHE)
-
- { ngx_string("index_cache"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
- ngx_http_set_cache_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_index_loc_conf_t, index_cache),
- NULL },
-
-#endif
-
ngx_null_command
};
@@ -120,16 +109,13 @@ ngx_http_index_handler(ngx_http_request_t *r)
{
u_char *last;
size_t len;
- ngx_fd_t fd;
ngx_int_t rc;
- ngx_err_t err;
- ngx_str_t uri;
+ ngx_str_t path, uri;
ngx_log_t *log;
ngx_uint_t i;
ngx_http_index_t *index;
ngx_http_index_ctx_t *ctx;
- ngx_pool_cleanup_t *cln;
- ngx_pool_cleanup_file_t *clnf;
+ ngx_open_file_info_t of;
ngx_http_script_code_pt code;
ngx_http_script_engine_t e;
ngx_http_core_loc_conf_t *clcf;
@@ -151,13 +137,14 @@ ngx_http_index_handler(ngx_http_request_t *r)
log = r->connection->log;
+ ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
/*
* we use context because the handler supports an async file opening,
* and may be called several times
*/
- ilcf = ngx_http_get_module_loc_conf(r, ngx_http_index_module);
-
ctx = ngx_http_get_module_ctx(r, ngx_http_index_module);
if (ctx == NULL) {
@@ -214,12 +201,16 @@ ngx_http_index_handler(ngx_http_request_t *r)
ctx->index.data = last;
}
+ path.data = ctx->path.data;
+
if (index[i].values == NULL) {
/* index[i].name.len includes the terminating '\0' */
ngx_memcpy(ctx->index.data, index[i].name.data, index[i].name.len);
+ path.len = (ctx->index.data + index[i].name.len - 1) - path.data;
+
} else {
e.ip = index[i].values->elts;
e.pos = ctx->index.data;
@@ -234,39 +225,46 @@ ngx_http_index_handler(ngx_http_request_t *r)
return ngx_http_internal_redirect(r, &ctx->index, &r->args);
}
+ path.len = e.pos - path.data;
+
*e.pos++ = '\0';
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
- "open index \"%s\"", ctx->path.data);
+ "open index \"%V\"", &path);
- cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
- if (cln == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ of.test_dir = 0;
+ of.retest = clcf->open_file_cache_retest;
+ of.errors = clcf->open_file_cache_errors;
+ of.events = clcf->open_file_cache_events;
- fd = ngx_open_file(ctx->path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
- if (fd == (ngx_fd_t) NGX_AGAIN) {
+#if 0
+ if (rc == NGX_AGAIN) {
ctx->current = i;
return NGX_AGAIN;
}
+#endif
- if (fd == NGX_INVALID_FILE) {
- err = ngx_errno;
+ if (rc == NGX_ERROR) {
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, err,
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, of.err,
ngx_open_file_n " \"%s\" failed", ctx->path.data);
- if (err == NGX_ENOTDIR) {
- return ngx_http_index_error(r, ctx, err);
+ if (of.err == 0) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if (of.err == NGX_ENOTDIR) {
+ return ngx_http_index_error(r, ctx, of.err);
- } else if (err == NGX_EACCES) {
- return ngx_http_index_error(r, ctx, err);
+ } else if (of.err == NGX_EACCES) {
+ return ngx_http_index_error(r, ctx, of.err);
}
if (!ctx->tested) {
- rc = ngx_http_index_test_dir(r, ctx);
+ rc = ngx_http_index_test_dir(r, clcf, ctx);
if (rc != NGX_OK) {
return rc;
@@ -275,25 +273,16 @@ ngx_http_index_handler(ngx_http_request_t *r)
ctx->tested = 1;
}
- if (err == NGX_ENOENT) {
+ if (of.err == NGX_ENOENT) {
continue;
}
- ngx_log_error(NGX_LOG_ERR, log, err,
+ ngx_log_error(NGX_LOG_ERR, log, of.err,
ngx_open_file_n " \"%s\" failed", ctx->path.data);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- cln->handler = ngx_pool_cleanup_file;
- clnf = cln->data;
-
- clnf->fd = fd;
- clnf->name = ctx->path.data;
- clnf->log = r->pool->log;
-
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
uri.len = r->uri.len + ctx->index.len - 1;
if (!clcf->alias) {
@@ -317,43 +306,53 @@ ngx_http_index_handler(ngx_http_request_t *r)
static ngx_int_t
-ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_index_ctx_t *ctx)
+ngx_http_index_test_dir(ngx_http_request_t *r, ngx_http_core_loc_conf_t *clcf,
+ ngx_http_index_ctx_t *ctx)
{
- u_char c;
- ngx_uint_t i;
- ngx_err_t err;
- ngx_file_info_t fi;
+ u_char c;
+ ngx_str_t path;
+ ngx_uint_t i;
+ ngx_open_file_info_t of;
c = *(ctx->index.data - 1);
i = (c == '/') ? 1 : 0;
*(ctx->index.data - i) = '\0';
+ path.len = (ctx->index.data - i) - ctx->path.data;
+ path.data = ctx->path.data;
+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http index check dir: \"%s\"", ctx->path.data);
+ "http index check dir: \"%V\"", &path);
- if (ngx_file_info(ctx->path.data, &fi) == -1) {
+ of.test_dir = 1;
+ of.retest = clcf->open_file_cache_retest;
+ of.errors = clcf->open_file_cache_errors;
- err = ngx_errno;
+ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+ != NGX_OK)
+ {
+ if (of.err) {
- if (err == NGX_ENOENT) {
- *(ctx->index.data - i) = c;
- return ngx_http_index_error(r, ctx, err);
- }
+ if (of.err == NGX_ENOENT) {
+ *(ctx->index.data - i) = c;
+ return ngx_http_index_error(r, ctx, of.err);
+ }
- ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
- ngx_file_info_n " \"%s\" failed", ctx->path.data);
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
+ ngx_open_file_n " \"%s\" failed", path.data);
+ }
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
*(ctx->index.data - i) = c;
- if (ngx_is_dir(&fi)) {
+ if (of.is_dir) {
return NGX_OK;
}
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "\"%s\" is not a directory", ctx->path.data);
+ "\"%s\" is not a directory", path.data);
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index b94ebf230..9278497d9 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -9,35 +9,10 @@
#include <ngx_http.h>
-typedef struct {
- ngx_http_cache_hash_t *redirect_cache;
-} ngx_http_static_loc_conf_t;
-
-
static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
-static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
-static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf,
- void *parent, void *child);
static ngx_int_t ngx_http_static_init(ngx_conf_t *cf);
-static ngx_command_t ngx_http_static_commands[] = {
-
-#if (NGX_HTTP_CACHE)
-
- { ngx_string("redirect_cache"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE3,
- ngx_http_set_cache_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_static_loc_conf_t, redirect_cache),
- NULL },
-
-#endif
-
- ngx_null_command
-};
-
-
ngx_http_module_t ngx_http_static_module_ctx = {
NULL, /* preconfiguration */
ngx_http_static_init, /* postconfiguration */
@@ -48,15 +23,15 @@ ngx_http_module_t ngx_http_static_module_ctx = {
NULL, /* create server configuration */
NULL, /* merge server configuration */
- ngx_http_static_create_loc_conf, /* create location configuration */
- ngx_http_static_merge_loc_conf /* merge location configuration */
+ NULL, /* create location configuration */
+ NULL /* merge location configuration */
};
ngx_module_t ngx_http_static_module = {
NGX_MODULE_V1,
&ngx_http_static_module_ctx, /* module context */
- ngx_http_static_commands, /* module directives */
+ NULL, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
@@ -75,16 +50,13 @@ ngx_http_static_handler(ngx_http_request_t *r)
u_char *last, *location;
size_t root;
ngx_fd_t fd;
+ ngx_str_t path;
ngx_int_t rc;
ngx_uint_t level;
- ngx_str_t path;
- ngx_err_t err;
ngx_log_t *log;
ngx_buf_t *b;
ngx_chain_t out;
- ngx_file_info_t fi;
- ngx_pool_cleanup_t *cln;
- ngx_pool_cleanup_file_t *clnf;
+ ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
@@ -118,75 +90,69 @@ ngx_http_static_handler(ngx_http_request_t *r)
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
+ path.len = last - path.data;
+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
"http filename: \"%s\"", path.data);
- cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
- if (cln == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ of.test_dir = 0;
+ of.retest = clcf->open_file_cache_retest;
+ of.errors = clcf->open_file_cache_errors;
+ of.events = clcf->open_file_cache_events;
- fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
- if (fd == NGX_INVALID_FILE) {
- err = ngx_errno;
+ if (rc == NGX_ERROR) {
+
+ switch (of.err) {
+
+ case 0:
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+
+ case NGX_ENOENT:
+ case NGX_ENOTDIR:
+ case NGX_ENAMETOOLONG:
- if (err == NGX_ENOENT
- || err == NGX_ENOTDIR
- || err == NGX_ENAMETOOLONG)
- {
level = NGX_LOG_ERR;
rc = NGX_HTTP_NOT_FOUND;
+ break;
+
+ case NGX_EACCES:
- } else if (err == NGX_EACCES) {
level = NGX_LOG_ERR;
rc = NGX_HTTP_FORBIDDEN;
+ break;
+
+ default:
- } else {
level = NGX_LOG_CRIT;
rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
}
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
if (rc != NGX_HTTP_NOT_FOUND || clcf->log_not_found) {
- ngx_log_error(level, log, err,
+ ngx_log_error(level, log, of.err,
ngx_open_file_n " \"%s\" failed", path.data);
}
return rc;
}
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
-
- if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", path.data);
-
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", path.data);
- }
+ fd = of.fd;
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", fd);
- if (ngx_is_dir(&fi)) {
+ if (of.is_dir) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", path.data);
- }
-
r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
if (r->headers_out.location == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
if (!clcf->alias && clcf->root_lengths == NULL) {
location = path.data + clcf->root.len;
@@ -214,15 +180,10 @@ ngx_http_static_handler(ngx_http_request_t *r)
#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
- if (!ngx_is_file(&fi)) {
+ if (!of.is_file) {
ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
"\"%s\" is not a regular file", path.data);
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", path.data);
- }
-
return NGX_HTTP_NOT_FOUND;
}
@@ -230,22 +191,15 @@ ngx_http_static_handler(ngx_http_request_t *r)
log->action = "sending response to client";
- cln->handler = ngx_pool_cleanup_file;
- clnf = cln->data;
-
- clnf->fd = fd;
- clnf->name = path.data;
- clnf->log = r->pool->log;
-
r->headers_out.status = NGX_HTTP_OK;
- r->headers_out.content_length_n = ngx_file_size(&fi);
- r->headers_out.last_modified_time = ngx_file_mtime(&fi);
+ r->headers_out.content_length_n = of.size;
+ r->headers_out.last_modified_time = of.mtime;
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
- if (r != r->main && ngx_file_size(&fi) == 0) {
+ if (r != r->main && of.size == 0) {
return ngx_http_send_header(r);
}
@@ -270,7 +224,7 @@ ngx_http_static_handler(ngx_http_request_t *r)
}
b->file_pos = 0;
- b->file_last = ngx_file_size(&fi);
+ b->file_last = of.size;
b->in_file = b->file_last ? 1: 0;
b->last_buf = (r == r->main) ? 1: 0;
@@ -287,36 +241,6 @@ ngx_http_static_handler(ngx_http_request_t *r)
}
-static void *
-ngx_http_static_create_loc_conf(ngx_conf_t *cf)
-{
- ngx_http_static_loc_conf_t *conf;
-
- conf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t));
- if (conf == NULL) {
- return NGX_CONF_ERROR;
- }
-
- conf->redirect_cache = NULL;
-
- return conf;
-}
-
-
-static char *
-ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
-{
- ngx_http_static_loc_conf_t *prev = parent;
- ngx_http_static_loc_conf_t *conf = child;
-
- if (conf->redirect_cache == NULL) {
- conf->redirect_cache = prev->redirect_cache;
- }
-
- return NGX_CONF_OK;
-}
-
-
static ngx_int_t
ngx_http_static_init(ngx_conf_t *cf)
{
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index 0bbf2768d..c18ac2ef5 100644
--- 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.6.9';
+our $VERSION = '0.6.10';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
index 7423daa93..24379ad9e 100644
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -131,6 +131,8 @@ send_http_header(r, ...)
XSRETURN_EMPTY;
}
+ r->headers_out.content_type_len = r->headers_out.content_type.len;
+
} else {
if (ngx_http_set_content_type(r) != NGX_OK) {
XSRETURN_EMPTY;
@@ -603,15 +605,15 @@ void
sendfile(r, filename, offset = -1, bytes = 0)
CODE:
- ngx_http_request_t *r;
- char *filename;
- int offset;
- size_t bytes;
- ngx_fd_t fd;
- ngx_buf_t *b;
- ngx_file_info_t fi;
- ngx_pool_cleanup_t *cln;
- ngx_pool_cleanup_file_t *clnf;
+ ngx_http_request_t *r;
+ char *filename;
+ int offset;
+ size_t bytes;
+ ngx_int_t rc;
+ ngx_str_t path;
+ ngx_buf_t *b;
+ ngx_open_file_info_t of;
+ ngx_http_core_loc_conf_t *clcf;
ngx_http_perl_set_request(r);
@@ -634,14 +636,30 @@ sendfile(r, filename, offset = -1, bytes = 0)
XSRETURN_EMPTY;
}
- cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_pool_cleanup_file_t));
- if (cln == NULL) {
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ of.test_dir = 0;
+ of.retest = clcf->open_file_cache_retest;
+ 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);
+ if (path.data == NULL) {
XSRETURN_EMPTY;
}
- fd = ngx_open_file((u_char *) filename, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
+ (void) ngx_cpystrn(path.data, filename, path.len + 1);
+
+ rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool);
+
+ if (rc == NGX_ERROR) {
+
+ if (of.err == 0) {
+ XSRETURN_EMPTY;
+ }
- if (fd == NGX_INVALID_FILE) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
ngx_open_file_n " \"%s\" failed", filename);
XSRETURN_EMPTY;
@@ -652,34 +670,15 @@ sendfile(r, filename, offset = -1, bytes = 0)
}
if (bytes == 0) {
- if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", filename);
-
- if (ngx_close_file(fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed", filename);
- }
-
- XSRETURN_EMPTY;
- }
-
- bytes = ngx_file_size(&fi) - offset;
+ bytes = of.size - offset;
}
- cln->handler = ngx_pool_cleanup_file;
- clnf = cln->data;
-
- clnf->fd = fd;
- clnf->name = (u_char *) "";
- clnf->log = r->pool->log;
-
b->in_file = 1;
b->file_pos = offset;
b->file_last = offset + bytes;
- b->file->fd = fd;
+ b->file->fd = of.fd;
b->file->log = r->connection->log;
(void) ngx_http_perl_output(r, b);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 13273f678..b25346daa 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -61,6 +61,8 @@ static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_keepalive(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -448,16 +450,33 @@ static ngx_command_t ngx_http_core_commands[] = {
0,
NULL },
-#if (NGX_HTTP_CACHE)
-
{ ngx_string("open_file_cache"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE4,
- ngx_http_set_cache_slot,
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
+ ngx_http_core_open_file_cache,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_core_loc_conf_t, open_files),
+ offsetof(ngx_http_core_loc_conf_t, open_file_cache),
NULL },
-#endif
+ { ngx_string("open_file_cache_retest"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_sec_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, open_file_cache_retest),
+ NULL },
+
+ { ngx_string("open_file_cache_errors"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, open_file_cache_errors),
+ NULL },
+
+ { ngx_string("open_file_cache_events"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, open_file_cache_events),
+ NULL },
ngx_null_command
};
@@ -2360,6 +2379,10 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
lcf->recursive_error_pages = NGX_CONF_UNSET;
lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
+ lcf->open_file_cache = NGX_CONF_UNSET_PTR;
+ lcf->open_file_cache_retest = NGX_CONF_UNSET;
+ lcf->open_file_cache_errors = NGX_CONF_UNSET;
+ lcf->open_file_cache_events = NGX_CONF_UNSET;
return lcf;
}
@@ -2543,9 +2566,17 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_value(conf->recursive_error_pages,
prev->recursive_error_pages, 0);
- if (conf->open_files == NULL) {
- conf->open_files = prev->open_files;
- }
+ ngx_conf_merge_ptr_value(conf->open_file_cache,
+ prev->open_file_cache, NULL);
+
+ ngx_conf_merge_sec_value(conf->open_file_cache_retest,
+ prev->open_file_cache_retest, 60);
+
+ ngx_conf_merge_sec_value(conf->open_file_cache_errors,
+ prev->open_file_cache_errors, 0);
+
+ ngx_conf_merge_sec_value(conf->open_file_cache_events,
+ prev->open_file_cache_events, 0);
return NGX_CONF_OK;
}
@@ -3162,6 +3193,82 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char *
+ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_loc_conf_t *lcf = conf;
+
+ time_t inactive;
+ ngx_str_t *value, s;
+ ngx_int_t max;
+ ngx_uint_t i;
+
+ if (lcf->open_file_cache != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ max = 0;
+ inactive = 60;
+
+ 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) {
+ return NGX_CONF_ERROR;
+ }
+
+ 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) {
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strcmp(value[i].data, "off") == 0) {
+
+ lcf->open_file_cache = NULL;
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid \"open_file_cache\" parameter \"%V\"",
+ &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (lcf->open_file_cache == NULL) {
+ return NGX_CONF_OK;
+ }
+
+ if (max == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"open_file_cache\" must have \"max\" parameter");
+ return NGX_CONF_ERROR;
+ }
+
+ lcf->open_file_cache = ngx_open_file_cache_init(cf->pool, max, inactive);
+ if (lcf->open_file_cache) {
+ return NGX_CONF_OK;
+ }
+
+ return NGX_CONF_ERROR;
+}
+
+
+static char *
ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index ec96c3ee1..2bd687e88 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -290,7 +290,10 @@ struct ngx_http_core_loc_conf_s {
ngx_path_t *client_body_temp_path; /* client_body_temp_path */
- ngx_http_cache_hash_t *open_files;
+ ngx_open_file_cache_t *open_file_cache;
+ time_t open_file_cache_retest;
+ ngx_flag_t open_file_cache_errors;
+ ngx_flag_t open_file_cache_events;
ngx_log_t *err_log;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 87b6017a6..f3d8f4841 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -75,7 +75,7 @@ ngx_http_header_t ngx_http_headers_in[] = {
{ ngx_string("If-Modified-Since"),
offsetof(ngx_http_headers_in_t, if_modified_since),
- ngx_http_process_header_line },
+ ngx_http_process_unique_header_line },
{ ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),
ngx_http_process_header_line },
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 9c34b7c2e..dfe5e0fe1 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -446,8 +446,6 @@ ngx_http_discard_request_body(ngx_http_request_t *r)
return NGX_OK;
}
- r->discard_body = 1;
-
size = r->header_in->last - r->header_in->pos;
if (size) {
@@ -461,6 +459,8 @@ ngx_http_discard_request_body(ngx_http_request_t *r)
}
}
+ r->discard_body = 1;
+
r->read_event_handler = ngx_http_read_discarded_request_body_handler;
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
@@ -521,6 +521,7 @@ ngx_http_read_discarded_request_body_handler(ngx_http_request_t *r)
/* rc == NGX_AGAIN */
if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+ c->error = 1;
ngx_http_finalize_request(r, rc);
return;
}
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 945602178..b19ee91dc 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -952,8 +952,10 @@ ngx_http_script_not_equal_code(ngx_http_script_engine_t *e)
void
ngx_http_script_file_code(ngx_http_script_engine_t *e)
{
- ngx_err_t err;
- ngx_file_info_t fi;
+ ngx_str_t path;
+ ngx_http_request_t *r;
+ ngx_open_file_info_t of;
+ ngx_http_core_loc_conf_t *clcf;
ngx_http_variable_value_t *value;
ngx_http_script_file_code_t *code;
@@ -962,14 +964,26 @@ ngx_http_script_file_code(ngx_http_script_engine_t *e)
code = (ngx_http_script_file_code_t *) e->ip;
e->ip += sizeof(ngx_http_script_file_code_t);
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
- "http script file op %p", code->op);
+ path.len = value->len - 1;
+ path.data = value->data;
+
+ r = e->request;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http script file op %p \"%V\"", code->op, &path);
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
- if (ngx_file_info(value->data, &fi) == -1) {
- err = ngx_errno;
+ of.test_dir = 0;
+ of.retest = clcf->open_file_cache_retest;
+ of.errors = clcf->open_file_cache_errors;
+ of.events = clcf->open_file_cache_events;
- if (err != NGX_ENOENT && err != NGX_ENOTDIR) {
- ngx_log_error(NGX_LOG_CRIT, e->request->connection->log, err,
+ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+ == NGX_ERROR)
+ {
+ if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
ngx_file_info_n " \"%s\" failed", value->data);
}
@@ -993,69 +1007,57 @@ ngx_http_script_file_code(ngx_http_script_engine_t *e)
switch (code->op) {
case ngx_http_script_file_plain:
- if (ngx_is_file(&fi)) {
+ if (of.is_file) {
goto true;
}
goto false;
case ngx_http_script_file_not_plain:
- if (ngx_is_file(&fi)) {
+ if (of.is_file) {
goto false;
}
goto true;
case ngx_http_script_file_dir:
- if (ngx_is_dir(&fi)) {
+ if (of.is_dir) {
goto true;
}
goto false;
case ngx_http_script_file_not_dir:
- if (ngx_is_dir(&fi)) {
+ if (of.is_dir) {
goto false;
}
goto true;
case ngx_http_script_file_exists:
- if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+ if (of.is_file || of.is_dir || of.is_link) {
goto true;
}
goto false;
case ngx_http_script_file_not_exists:
- if (ngx_is_file(&fi) || ngx_is_dir(&fi) || ngx_is_link(&fi)) {
+ if (of.is_file || of.is_dir || of.is_link) {
goto false;
}
goto true;
-#if (NGX_WIN32)
-
- case ngx_http_script_file_exec:
- goto false;
-
- case ngx_http_script_file_not_exec:
- goto true;
-
-#else
-
case ngx_http_script_file_exec:
- if (ngx_is_exec(&fi)) {
+ if (of.is_exec) {
goto true;
}
goto false;
case ngx_http_script_file_not_exec:
- if (ngx_is_exec(&fi)) {
+ if (of.is_exec) {
goto false;
}
goto true;
-
-#endif
}
false:
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0,
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http script file op false");
*value = ngx_http_variable_null_value;
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
index be93ccbf8..441a1aaab 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -608,8 +608,8 @@ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
rc = ngx_ssl_set_session(pc->connection, ssl_session);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
- "set session: %p:%d",
- ssl_session, ssl_session ? ssl_session->references : 0);
+ "set session: %p:%d",
+ ssl_session, ssl_session ? ssl_session->references : 0);
/* ngx_unlock_mutex(rrp->peers->mutex); */
@@ -633,7 +633,7 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
- "save session: %p:%d", ssl_session, ssl_session->references);
+ "save session: %p:%d", ssl_session, ssl_session->references);
peer = &rrp->peers->peer[rrp->current];
@@ -648,7 +648,7 @@ ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
if (old_ssl_session) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
- "old session: %p:%d",
+ "old session: %p:%d",
old_ssl_session, old_ssl_session->references);
/* TODO: may block */
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index c7e2fd46d..26eb1e1fb 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -62,6 +62,11 @@ u_long cpu_affinity;
static u_char master_process[] = "master process";
+static ngx_cycle_t ngx_exit_cycle;
+static ngx_log_t ngx_exit_log;
+static ngx_open_file_t ngx_exit_log_file;
+
+
void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
@@ -649,13 +654,21 @@ ngx_master_process_exit(ngx_cycle_t *cycle)
}
/*
- * we do not destroy cycle->pool here because a signal handler
- * that uses cycle->log can be called at this point
+ * Copy ngx_cycle->log related data to the special static exit cycle,
+ * log, and log file structures enough to allow a signal handler to log.
+ * The handler may be called when standard ngx_cycle->log allocated from
+ * ngx_cycle->pool is already destroyed.
*/
-#if 0
+ ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
+
+ ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log.file = &ngx_exit_log_file;
+
+ ngx_exit_cycle.log = &ngx_exit_log;
+ ngx_cycle = &ngx_exit_cycle;
+
ngx_destroy_pool(cycle->pool);
-#endif
exit(0);
}
@@ -996,13 +1009,23 @@ ngx_worker_process_exit(ngx_cycle_t *cycle)
}
/*
- * we do not destroy cycle->pool here because a signal handler
- * that uses cycle->log can be called at this point
+ * Copy ngx_cycle->log related data to the special static exit cycle,
+ * log, and log file structures enough to allow a signal handler to log.
+ * The handler may be called when standard ngx_cycle->log allocated from
+ * ngx_cycle->pool is already destroyed.
*/
-#if 0
+ ngx_exit_log_file.fd = ngx_cycle->log->file->fd;
+
+ ngx_exit_log = *ngx_cycle->log;
+ ngx_exit_log.file = &ngx_exit_log_file;
+
+ ngx_exit_cycle.log = &ngx_exit_log;
+ ngx_cycle = &ngx_exit_cycle;
+
ngx_destroy_pool(cycle->pool);
-#endif
+
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, "exit");
exit(0);
}