Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nginx/nginx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2009-03-23 16:14:51 +0300
committerIgor Sysoev <igor@sysoev.ru>2009-03-23 16:14:51 +0300
commit52859f2f1309fc8452f1cf182b712ae2d72bc40c (patch)
treef87d424675f857d0dcebdc80ce3828389d75a69b
parent1af7090b5091ebbee1cd9354fe8a702e601a8ce0 (diff)
a prelimiary proxy cache support
-rw-r--r--auto/modules12
-rw-r--r--auto/options4
-rw-r--r--auto/sources9
-rw-r--r--src/core/ngx_file.c45
-rw-r--r--src/core/ngx_file.h119
-rw-r--r--src/core/ngx_garbage_collector.c217
-rw-r--r--src/core/ngx_garbage_collector.h31
-rw-r--r--src/core/ngx_palloc.c21
-rw-r--r--src/core/ngx_palloc.h1
-rw-r--r--src/event/ngx_event_pipe.c14
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c16
-rw-r--r--src/http/modules/ngx_http_not_modified_filter_module.c1
-rw-r--r--src/http/modules/ngx_http_proxy_module.c444
-rw-r--r--src/http/modules/ngx_http_range_filter_module.c12
-rw-r--r--src/http/ngx_http.h18
-rw-r--r--src/http/ngx_http_cache.c576
-rw-r--r--src/http/ngx_http_cache.h190
-rw-r--r--src/http/ngx_http_core_module.c20
-rw-r--r--src/http/ngx_http_file_cache.c1308
-rw-r--r--src/http/ngx_http_request.h5
-rw-r--r--src/http/ngx_http_upstream.c636
-rw-r--r--src/http/ngx_http_upstream.h292
-rw-r--r--src/os/unix/ngx_files.h1
-rw-r--r--src/os/unix/ngx_process_cycle.c106
-rw-r--r--src/os/win32/ngx_files.h1
25 files changed, 2456 insertions, 1643 deletions
diff --git a/auto/modules b/auto/modules
index 456d6e7a5..5e9d4d534 100644
--- a/auto/modules
+++ b/auto/modules
@@ -65,6 +65,13 @@ if [ $HTTP != YES ]; then
fi
+if [ $HTTP_CACHE = YES ]; then
+ USE_MD5=YES
+ have=NGX_HTTP_CACHE . auto/have
+ HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS"
+fi
+
+
if [ $HTTP_SSI = YES ]; then
HTTP_POSTPONE=YES
fi
@@ -305,11 +312,6 @@ if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS"
fi
-# STUB
-#USE_MD5=YES
-#HTTP_SRCS="$HTTP_SRCS $HTTP_CACHE_SRCS"
-#HTTP_SRCS="$HTTP_SRCS $HTTP_FILE_CACHE_SRCS"
-
if [ $HTTP_STUB_STATUS = YES ]; then
have=NGX_STAT_STUB . auto/have
HTTP_MODULES="$HTTP_MODULES ngx_http_stub_status_module"
diff --git a/auto/options b/auto/options
index e90e15abb..8ec692e7d 100644
--- a/auto/options
+++ b/auto/options
@@ -52,6 +52,7 @@ NGX_HTTP_CLIENT_TEMP_PATH=
NGX_HTTP_PROXY_TEMP_PATH=
NGX_HTTP_FASTCGI_TEMP_PATH=
+HTTP_CACHE=YES
HTTP_CHARSET=YES
HTTP_GZIP=YES
HTTP_SSL=NO
@@ -165,6 +166,8 @@ do
--with-ipv6) NGX_IPV6=YES ;;
--without-http) HTTP=NO ;;
+ --without-http-cache) HTTP_CACHE=NO ;;
+
--http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;;
--http-client-body-temp-path=*) NGX_HTTP_CLIENT_TEMP_PATH="$value" ;;
--http-proxy-temp-path=*) NGX_HTTP_PROXY_TEMP_PATH="$value" ;;
@@ -337,6 +340,7 @@ cat << END
files
--without-http disable HTTP server
+ --without-http-cache disable HTTP cache
--with-mail enable POP3/IMAP4/SMTP proxy module
--with-mail_ssl_module enable ngx_mail_ssl_module
diff --git a/auto/sources b/auto/sources
index 1c063d12c..4c14634de 100644
--- a/auto/sources
+++ b/auto/sources
@@ -33,8 +33,7 @@ CORE_DEPS="src/core/nginx.h \
src/core/ngx_cycle.h \
src/core/ngx_conf_file.h \
src/core/ngx_resolver.h \
- src/core/ngx_open_file_cache.h \
- src/core/ngx_garbage_collector.h"
+ src/core/ngx_open_file_cache.h"
CORE_SRCS="src/core/nginx.c \
@@ -62,8 +61,7 @@ CORE_SRCS="src/core/nginx.c \
src/core/ngx_cpuinfo.c \
src/core/ngx_conf_file.c \
src/core/ngx_resolver.c \
- src/core/ngx_open_file_cache.c \
- src/core/ngx_garbage_collector.c"
+ src/core/ngx_open_file_cache.c"
REGEX_DEPS=src/core/ngx_regex.h
@@ -254,8 +252,6 @@ HTTP_MODULES="ngx_http_module \
ngx_http_log_module \
ngx_http_upstream_module"
-HTTP_CACHE_MODULE=ngx_http_cache_module
-
HTTP_WRITE_FILTER_MODULE="ngx_http_write_filter_module"
HTTP_HEADER_FILTER_MODULE="ngx_http_header_filter_module"
@@ -313,7 +309,6 @@ HTTP_SRCS="$HTTP_SRCS src/http/ngx_http_busy_lock.c"
HTTP_POSTPONE_FILTER_SRCS=src/http/ngx_http_postpone_filter_module.c
-HTTP_CACHE_SRCS=src/http/ngx_http_cache.c
HTTP_FILE_CACHE_SRCS=src/http/ngx_http_file_cache.c
diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c
index 1bb418226..fed19e690 100644
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -264,7 +264,7 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
path->len = 0;
- path->cleaner = (ngx_gc_handler_pt) cmd->post;
+ path->cleaner = (ngx_path_cleaner_pt) cmd->post;
path->conf_file = cf->conf_file->file.name.data;
path->line = cf->conf_file->line;
@@ -293,6 +293,49 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
char *
+ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path, ngx_path_t *prev,
+ ngx_path_init_t *init)
+{
+ if (*path) {
+ return NGX_CONF_OK;
+ }
+
+ if (prev) {
+ *path = prev;
+ return NGX_CONF_OK;
+ }
+
+ *path = ngx_palloc(cf->pool, sizeof(ngx_path_t));
+ if (*path == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ (*path)->name = init->name;
+
+ if (ngx_conf_full_name(cf->cycle, &(*path)->name, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ (*path)->level[0] = init->level[0];
+ (*path)->level[1] = init->level[1];
+ (*path)->level[2] = init->level[2];
+
+ (*path)->len = init->level[0] + (init->level[0] ? 1 : 0)
+ + init->level[1] + (init->level[1] ? 1 : 0)
+ + init->level[2] + (init->level[2] ? 1 : 0);
+
+ (*path)->cleaner = NULL;
+ (*path)->conf_file = NULL;
+
+ if (ngx_add_path(cf, path) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+char *
ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
char *confp = conf;
diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h
index 344da0957..7890c48cc 100644
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -11,65 +11,73 @@
#include <ngx_config.h>
#include <ngx_core.h>
-typedef struct ngx_path_s ngx_path_t;
-
-#include <ngx_garbage_collector.h>
-
struct ngx_file_s {
- ngx_fd_t fd;
- ngx_str_t name;
- ngx_file_info_t info;
+ ngx_fd_t fd;
+ ngx_str_t name;
+ ngx_file_info_t info;
- off_t offset;
- off_t sys_offset;
+ off_t offset;
+ off_t sys_offset;
- ngx_log_t *log;
+ ngx_log_t *log;
- unsigned valid_info:1;
- unsigned directio:1;
+ unsigned valid_info:1;
+ unsigned directio:1;
};
#define NGX_MAX_PATH_LEVEL 3
-struct ngx_path_s {
- ngx_str_t name;
- size_t len;
- size_t level[3];
- ngx_gc_handler_pt cleaner;
- u_char *conf_file;
- ngx_uint_t line;
-};
+typedef time_t (*ngx_path_cleaner_pt) (void *data);
+
+
+typedef struct {
+ ngx_str_t name;
+ size_t len;
+ size_t level[3];
+
+ ngx_path_cleaner_pt cleaner;
+ void *data;
+
+ u_char *conf_file;
+ ngx_uint_t line;
+} ngx_path_t;
typedef struct {
- ngx_file_t file;
- off_t offset;
- ngx_path_t *path;
- ngx_pool_t *pool;
- char *warn;
+ ngx_str_t name;
+ size_t level[3];
+} ngx_path_init_t;
- ngx_uint_t access;
- unsigned log_level:8;
- unsigned persistent:1;
- unsigned clean:1;
+typedef struct {
+ ngx_file_t file;
+ off_t offset;
+ ngx_path_t *path;
+ ngx_pool_t *pool;
+ char *warn;
+
+ ngx_uint_t access;
+
+ unsigned log_level:8;
+ unsigned persistent:1;
+ unsigned clean:1;
} ngx_temp_file_t;
typedef struct {
- ngx_uint_t access;
- ngx_uint_t path_access;
- time_t time;
- ngx_fd_t fd;
- ngx_err_t rename_error;
+ ngx_uint_t access;
+ ngx_uint_t path_access;
+ time_t time;
+ ngx_fd_t fd;
+ ngx_err_t rename_error;
- unsigned create_path:1;
- unsigned delete_file:1;
- unsigned log_rename_error:1;
+ unsigned create_path:1;
+ unsigned delete_file:1;
+ unsigned log_rename_error:1;
- ngx_log_t *log;
+ ngx_log_t *log;
} ngx_ext_rename_file_t;
@@ -113,40 +121,9 @@ void ngx_init_temp_number(void);
ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_merge_path_value(ngx_conf_t *cf, ngx_path_t **path,
+ ngx_path_t *prev, ngx_path_init_t *init);
char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-#define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \
- if (curr == NULL) { \
- if (prev == NULL) { \
- curr = ngx_palloc(cf->pool, sizeof(ngx_path_t)); \
- if (curr == NULL) { \
- return NGX_CONF_ERROR; \
- } \
- \
- curr->name.len = sizeof(path) - 1; \
- curr->name.data = (u_char *) path; \
- \
- if (ngx_conf_full_name(cf->cycle, &curr->name, 0) == NGX_ERROR) { \
- return NGX_CONF_ERROR; \
- } \
- \
- curr->level[0] = l1; \
- curr->level[1] = l2; \
- curr->level[2] = l3; \
- curr->len = l1 + l2 + l3 + (l1 ? 1:0) + (l2 ? 1:0) + (l3 ? 1:0); \
- curr->cleaner = clean; \
- curr->conf_file = NULL; \
- \
- if (ngx_add_path(cf, &curr) == NGX_ERROR) { \
- return NGX_CONF_ERROR; \
- } \
- \
- } else { \
- curr = prev; \
- } \
- }
-
-
-
#endif /* _NGX_FILE_H_INCLUDED_ */
diff --git a/src/core/ngx_garbage_collector.c b/src/core/ngx_garbage_collector.c
deleted file mode 100644
index 4eeaeb9be..000000000
--- a/src/core/ngx_garbage_collector.c
+++ /dev/null
@@ -1,217 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-
-
-
-ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level)
-{
- int rc;
- u_char *last;
- size_t len;
- ngx_err_t err;
- ngx_str_t fname, buf;
- ngx_dir_t dir;
-
- buf.len = 0;
-#if (NGX_SUPPRESS_WARN)
- buf.data = NULL;
- fname.data = NULL;
-#endif
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "gc dir \"%s\":%d", dname->data, dname->len);
-
- if (ngx_open_dir(dname, &dir) == NGX_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_open_dir_n " \"%s\" failed", dname->data);
- return NGX_ERROR;
- }
-
- for ( ;; ) {
- ngx_set_errno(0);
- if (ngx_read_dir(&dir) == NGX_ERROR) {
- err = ngx_errno;
-
- if (err != NGX_ENOMOREFILES) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
- ngx_read_dir_n " \"%s\" failed", dname->data);
- rc = NGX_ERROR;
-
- } else {
- rc = NGX_OK;
- }
-
- break;
- }
-
- len = ngx_de_namelen(&dir);
-
- ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "gc name \"%s\":%d", ngx_de_name(&dir), len);
-
- if (len == 1 && ngx_de_name(&dir)[0] == '.') {
- continue;
- }
-
- if (len == 2
- && ngx_de_name(&dir)[0] == '.'
- && ngx_de_name(&dir)[1] == '.')
- {
- continue;
- }
-
- fname.len = dname->len + 1+ len;
-
- if (fname.len + NGX_DIR_MASK_LEN > buf.len) {
-
- if (buf.len) {
- ngx_free(buf.data);
- }
-
- buf.len = dname->len + 1 + len + NGX_DIR_MASK_LEN;
-
- buf.data = ngx_alloc(buf.len + 1, ctx->log);
- if (buf.data == NULL) {
- return NGX_ABORT;
- }
- }
-
- last = ngx_cpymem(buf.data, dname->data, dname->len);
- *last++ = '/';
- ngx_memcpy(last, ngx_de_name(&dir), len + 1);
- fname.data = buf.data;
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "gc path: \"%s\"", fname.data);
-
- if (!dir.valid_info) {
- if (ngx_de_info(fname.data, &dir) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_de_info_n " \"%s\" failed", fname.data);
- continue;
- }
- }
-
- if (ngx_de_is_dir(&dir)) {
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "gc enter dir \"%s\"", fname.data);
-
- if (level == -1
- /* there can not be directory on the last level */
- || level == NGX_MAX_PATH_LEVEL
- /* an directory from the old path hierarchy */
- || len != ctx->path->level[level])
- {
- if (ngx_collect_garbage(ctx, &fname, -1) == NGX_ABORT) {
- return NGX_ABORT;
- }
-
- fname.data[fname.len] = '\0';
-
- ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
- "delete old hierachy directory \"%s\"",
- fname.data);
-
- if (ngx_delete_dir(fname.data) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_delete_dir_n " \"%s\" failed",
- fname.data);
- } else {
- ctx->deleted++;
- ctx->freed += ngx_de_size(&dir);
- }
-
- continue;
- }
-
- if (ngx_collect_garbage(ctx, &fname, level + 1) == NGX_ABORT) {
- return NGX_ABORT;
- }
-
- } else if (ngx_de_is_file(&dir)) {
-
- ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
- "gc file \"%s\"", fname.data);
-
- if (level == -1
- || (level < NGX_MAX_PATH_LEVEL && ctx->path->level[level] != 0))
- {
- if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_delete_file_n " \"%s\" failed",
- fname.data);
- } else {
- ctx->deleted++;
- ctx->freed += ngx_de_size(&dir);
- }
-
- continue;
- }
-
- if (ctx->handler(ctx, &fname, &dir) == NGX_ABORT) {
- return NGX_ABORT;
- }
-
- } else {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- "the file \"%s\" has unknown type, deleting",
- fname.data);
-
- if (ngx_delete_file(fname.data) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_delete_file_n " \"%s\" failed", fname.data);
- } else {
- ctx->deleted++;
- ctx->freed += ngx_de_size(&dir);
- }
- }
- }
-
- if (buf.len) {
- ngx_free(buf.data);
- }
-
- if (ngx_close_dir(&dir) == NGX_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_close_dir_n " \"%s\" failed", fname.data);
- }
-
- return rc;
-}
-
-
-ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
- ngx_dir_t *dir)
-{
- /*
- * We use mtime only and do not use atime because:
- * on NTFS access time has a resolution of 1 hour,
- * on NT FAT access time has a resolution of 1 day,
- * Unices have the mount option "noatime".
- */
-
- if (ngx_time() - ngx_de_mtime(dir) < 3600) {
- return NGX_OK;
- }
-
- ngx_log_error(NGX_LOG_NOTICE, ctx->log, 0,
- "delete the stale temporary file \"%s\"", name->data);
-
- if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
- ngx_delete_file_n " \"%s\" failed", name->data);
- return NGX_ERROR;
- }
-
- ctx->deleted++;
- ctx->freed += ngx_de_size(dir);
-
- return NGX_OK;
-}
diff --git a/src/core/ngx_garbage_collector.h b/src/core/ngx_garbage_collector.h
deleted file mode 100644
index 4b0a7344f..000000000
--- a/src/core/ngx_garbage_collector.h
+++ /dev/null
@@ -1,31 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#ifndef _NGX_GARBAGE_COLLECTOR_H_INCLUDED_
-#define _NGX_GARBAGE_COLLECTOR_H_INCLUDED_
-
-
-typedef struct ngx_gc_s ngx_gc_t;
-
-typedef ngx_int_t (*ngx_gc_handler_pt) (ngx_gc_t *ctx, ngx_str_t *name,
- ngx_dir_t *dir);
-
-
-struct ngx_gc_s {
- ngx_path_t *path;
- u_int deleted;
- off_t freed;
- ngx_gc_handler_pt handler;
- ngx_log_t *log;
-};
-
-
-ngx_int_t ngx_collect_garbage(ngx_gc_t *ctx, ngx_str_t *dname, ngx_int_t level);
-ngx_int_t ngx_garbage_collector_temp_handler(ngx_gc_t *ctx, ngx_str_t *name,
- ngx_dir_t *dir);
-
-
-#endif /* _NGX_GARBAGE_COLLECTOR_H_INCLUDED_ */
diff --git a/src/core/ngx_palloc.c b/src/core/ngx_palloc.c
index 7c89fda70..3e1c9f2ad 100644
--- a/src/core/ngx_palloc.c
+++ b/src/core/ngx_palloc.c
@@ -326,6 +326,27 @@ ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
void
+ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
+{
+ ngx_pool_cleanup_t *c;
+ ngx_pool_cleanup_file_t *cf;
+
+ for (c = p->cleanup; c; c = c->next) {
+ if (c->handler == ngx_pool_cleanup_file) {
+
+ cf = c->data;
+
+ if (cf->fd == fd) {
+ c->handler(cf);
+ c->handler = NULL;
+ return;
+ }
+ }
+ }
+}
+
+
+void
ngx_pool_cleanup_file(void *data)
{
ngx_pool_cleanup_file_t *c = data;
diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h
index c31db932c..f9d5216ed 100644
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -82,6 +82,7 @@ ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
+void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);
diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c
index ca18d7cae..c13d2ea5a 100644
--- a/src/event/ngx_event_pipe.c
+++ b/src/event/ngx_event_pipe.c
@@ -423,7 +423,7 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
size_t bsize;
ngx_int_t rc;
ngx_uint_t flush, prev_last_shadow;
- ngx_chain_t *out, **ll, *cl;
+ ngx_chain_t *out, **ll, *cl, file;
ngx_connection_t *downstream;
downstream = p->downstream;
@@ -488,6 +488,18 @@ ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p)
p->in = NULL;
}
+ if (p->cacheable && p->buf_to_file) {
+
+ file.buf = p->buf_to_file;
+ file.next = NULL;
+
+ if (ngx_write_chain_to_temp_file(p->temp_file, &file)
+ == NGX_ERROR)
+ {
+ return NGX_ABORT;
+ }
+ }
+
ngx_log_debug0(NGX_LOG_DEBUG_EVENT, p->log, 0,
"pipe write downstream done");
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 45b647505..f054c3c8e 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -288,7 +288,7 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
ngx_conf_set_path_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_fastcgi_loc_conf_t, upstream.temp_path),
- (void *) ngx_garbage_collector_temp_handler },
+ NULL },
{ ngx_string("fastcgi_max_temp_file_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
@@ -436,6 +436,11 @@ static ngx_str_t ngx_http_fastcgi_hide_headers[] = {
};
+static ngx_path_init_t ngx_http_fastcgi_temp_path = {
+ ngx_string(NGX_HTTP_FASTCGI_TEMP_PATH), { 1, 2, 0 }
+};
+
+
static ngx_int_t
ngx_http_fastcgi_handler(ngx_http_request_t *r)
{
@@ -1923,10 +1928,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_path_value(conf->upstream.temp_path,
+ if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
prev->upstream.temp_path,
- NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0,
- ngx_garbage_collector_temp_handler, cf);
+ &ngx_http_fastcgi_temp_path)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
ngx_conf_merge_value(conf->upstream.pass_request_headers,
prev->upstream.pass_request_headers, 1);
diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c
index feed9cf54..ac1227a4c 100644
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -83,6 +83,7 @@ ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)
}
r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
+ r->headers_out.status_line.len = 0;
r->headers_out.content_type.len = 0;
ngx_http_clear_content_length(r);
ngx_http_clear_accept_ranges(r);
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index e8c19bb16..f28ee9ae7 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -32,6 +32,7 @@ struct ngx_http_proxy_redirect_s {
typedef struct {
+ ngx_str_t key_start;
ngx_str_t schema;
ngx_str_t host_header;
ngx_str_t port;
@@ -89,6 +90,9 @@ typedef struct {
static ngx_int_t ngx_http_proxy_eval(ngx_http_request_t *r,
ngx_http_proxy_ctx_t *ctx, ngx_http_proxy_loc_conf_t *plcf);
+#if (NGX_HTTP_CACHE)
+static ngx_int_t ngx_http_proxy_create_key(ngx_http_request_t *r);
+#endif
static ngx_int_t ngx_http_proxy_create_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_reinit_request(ngx_http_request_t *r);
static ngx_int_t ngx_http_proxy_process_status_line(ngx_http_request_t *r);
@@ -116,6 +120,8 @@ static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf);
static char *ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child);
+static ngx_int_t ngx_http_proxy_merge_headers(ngx_conf_t *cf,
+ ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_loc_conf_t *prev);
static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -123,6 +129,10 @@ static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+#if (NGX_HTTP_CACHE)
+static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+#endif
static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data);
@@ -135,8 +145,7 @@ static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf,
static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf,
ngx_http_proxy_loc_conf_t *plcf);
#endif
-static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
- ngx_http_proxy_vars_t *v);
+static void ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v);
static ngx_conf_post_t ngx_http_proxy_lowat_post =
@@ -157,6 +166,9 @@ static ngx_conf_bitmask_t ngx_http_proxy_next_upstream_masks[] = {
};
+ngx_module_t ngx_http_proxy_module;
+
+
static ngx_command_t ngx_http_proxy_commands[] = {
{ ngx_string("proxy_pass"),
@@ -306,12 +318,51 @@ static ngx_command_t ngx_http_proxy_commands[] = {
offsetof(ngx_http_proxy_loc_conf_t, upstream.busy_buffers_size_conf),
NULL },
+#if (NGX_HTTP_CACHE)
+
+ { ngx_string("proxy_cache"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+ ngx_http_proxy_cache,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache),
+ NULL },
+
+ { ngx_string("proxy_cache_path"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_2MORE,
+ ngx_http_file_cache_set_slot,
+ 0,
+ 0,
+ &ngx_http_proxy_module },
+
+ { ngx_string("proxy_cache_valid"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_http_file_cache_valid_set_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_valid),
+ NULL },
+
+ { ngx_string("proxy_cache_min_uses"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_num_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_min_uses),
+ NULL },
+
+ { ngx_string("proxy_cache_use_stale"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.cache_use_stale),
+ &ngx_http_proxy_next_upstream_masks },
+
+#endif
+
{ ngx_string("proxy_temp_path"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
ngx_conf_set_path_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_proxy_loc_conf_t, upstream.temp_path),
- (void *) ngx_garbage_collector_temp_handler },
+ NULL },
{ ngx_string("proxy_max_temp_file_size"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
@@ -455,6 +506,11 @@ static ngx_http_variable_t ngx_http_proxy_vars[] = {
};
+static ngx_path_init_t ngx_http_proxy_temp_path = {
+ ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 }
+};
+
+
static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t *r)
{
@@ -502,6 +558,9 @@ ngx_http_proxy_handler(ngx_http_request_t *r)
u->conf = &plcf->upstream;
+#if (NGX_HTTP_CACHE)
+ u->create_key = ngx_http_proxy_create_key;
+#endif
u->create_request = ngx_http_proxy_create_request;
u->reinit_request = ngx_http_proxy_reinit_request;
u->process_header = ngx_http_proxy_process_status_line;
@@ -537,11 +596,12 @@ static ngx_int_t
ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
ngx_http_proxy_loc_conf_t *plcf)
{
- u_char *p;
- size_t add;
- u_short port;
- ngx_str_t proxy;
- ngx_url_t u;
+ u_char *p;
+ size_t add;
+ u_short port;
+ ngx_str_t proxy;
+ ngx_url_t url;
+ ngx_http_upstream_t *u;
if (ngx_http_script_run(r, &proxy, plcf->proxy_lengths->elts, 0,
plcf->proxy_values->elts)
@@ -571,70 +631,162 @@ ngx_http_proxy_eval(ngx_http_request_t *r, ngx_http_proxy_ctx_t *ctx,
return NGX_ERROR;
}
- r->upstream->schema.len = add;
- r->upstream->schema.data = proxy.data;
+ u = r->upstream;
- ngx_memzero(&u, sizeof(ngx_url_t));
+ u->schema.len = add;
+ u->schema.data = proxy.data;
- u.url.len = proxy.len - add;
- u.url.data = proxy.data + add;
- u.default_port = port;
- u.uri_part = 1;
- u.no_resolve = 1;
+ ngx_memzero(&url, sizeof(ngx_url_t));
- if (ngx_parse_url(r->pool, &u) != NGX_OK) {
- if (u.err) {
+ url.url.len = proxy.len - add;
+ url.url.data = proxy.data + add;
+ url.default_port = port;
+ url.uri_part = 1;
+ url.no_resolve = 1;
+
+ if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+ if (url.err) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
- "%s in upstream \"%V\"", u.err, &u.url);
+ "%s in upstream \"%V\"", url.err, &url.url);
}
return NGX_ERROR;
}
- if (u.uri.len && u.uri.data[0] == '?') {
- p = ngx_pnalloc(r->pool, u.uri.len + 1);
+ if (url.uri.len && url.uri.data[0] == '?') {
+ p = ngx_pnalloc(r->pool, url.uri.len + 1);
if (p == NULL) {
return NGX_ERROR;
}
*p++ = '/';
- ngx_memcpy(p, u.uri.data, u.uri.len);
+ ngx_memcpy(p, url.uri.data, url.uri.len);
- u.uri.len++;
- u.uri.data = p - 1;
+ url.uri.len++;
+ url.uri.data = p - 1;
}
- if (ngx_http_proxy_set_vars(r->pool, &u, &ctx->vars) != NGX_OK) {
+ ctx->vars.key_start = u->schema;
+
+ ngx_http_proxy_set_vars(&url, &ctx->vars);
+
+ u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+ if (u->resolved == NULL) {
return NGX_ERROR;
}
- r->upstream->resolved = ngx_pcalloc(r->pool,
- sizeof(ngx_http_upstream_resolved_t));
- if (r->upstream->resolved == NULL) {
+ if (url.addrs && url.addrs[0].sockaddr) {
+ u->resolved->sockaddr = url.addrs[0].sockaddr;
+ u->resolved->socklen = url.addrs[0].socklen;
+ u->resolved->naddrs = 1;
+ u->resolved->host = url.addrs[0].name;
+
+ } else {
+ u->resolved->host = url.host;
+ u->resolved->port = (in_port_t) (url.no_port ? port : url.port);
+ u->resolved->no_port = url.no_port;
+ }
+
+ return NGX_OK;
+}
+
+
+#if (NGX_HTTP_CACHE)
+
+static ngx_int_t
+ngx_http_proxy_create_key(ngx_http_request_t *r)
+{
+ size_t len, loc_len;
+ u_char *p;
+ uintptr_t escape;
+ ngx_str_t *key;
+ ngx_http_upstream_t *u;
+ ngx_http_proxy_ctx_t *ctx;
+ ngx_http_proxy_loc_conf_t *plcf;
+
+ u = r->upstream;
+
+ plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
+
+ ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
+
+ key = ngx_array_push(&r->cache->keys);
+ if (key == NULL) {
+ return NGX_ERROR;
+ }
+
+ *key = ctx->vars.key_start;
+
+ key = ngx_array_push(&r->cache->keys);
+ if (key == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (plcf->proxy_lengths) {
+
+ *key = ctx->vars.uri;
+ u->uri = ctx->vars.uri;
+
+ return NGX_OK;
+
+ } else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
+ {
+ *key = r->unparsed_uri;
+ u->uri = r->unparsed_uri;
+
+ return NGX_OK;
+ }
+
+ loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0;
+
+ if (r->quoted_uri || r->internal) {
+ escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ } else {
+ escape = 0;
+ }
+
+ len = ctx->vars.uri.len + r->uri.len - loc_len + escape
+ + sizeof("?") - 1 + r->args.len;
+
+ p = ngx_pnalloc(r->pool, len);
+ if (p == NULL) {
return NGX_ERROR;
}
- if (u.addrs && u.addrs[0].sockaddr) {
- r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
- r->upstream->resolved->socklen = u.addrs[0].socklen;
- r->upstream->resolved->naddrs = 1;
- r->upstream->resolved->host = u.addrs[0].name;
+ key->data = p;
+
+ if (r->valid_location) {
+ p = ngx_copy(p, ctx->vars.uri.data, ctx->vars.uri.len);
+ }
+
+ if (escape) {
+ ngx_escape_uri(p, r->uri.data + loc_len,
+ r->uri.len - loc_len, NGX_ESCAPE_URI);
+ p += r->uri.len - loc_len + escape;
} else {
- r->upstream->resolved->host = u.host;
- r->upstream->resolved->port = (in_port_t) (u.no_port ? u.default_port:
- u.port);
- r->upstream->resolved->no_port = u.no_port;
+ p = ngx_copy(p, r->uri.data + loc_len, r->uri.len - loc_len);
+ }
+
+ if (r->args.len > 0) {
+ *p++ = '?';
+ p = ngx_copy(p, r->args.data, r->args.len);
}
+ key->len = p - key->data;
+ u->uri = *key;
+
return NGX_OK;
}
+#endif
+
static ngx_int_t
ngx_http_proxy_create_request(ngx_http_request_t *r)
{
- size_t len, loc_len, body_len;
+ size_t len, uri_len, loc_len, body_len;
uintptr_t escape;
ngx_buf_t *b;
ngx_str_t method;
@@ -675,12 +827,12 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
if (plcf->proxy_lengths) {
- len += ctx->vars.uri.len;
+ uri_len = ctx->vars.uri.len;
} else if (ctx->vars.uri.len == 0 && r->valid_unparsed_uri && r == r->main)
{
unparsed_uri = 1;
- len += r->unparsed_uri.len;
+ uri_len = r->unparsed_uri.len;
} else {
loc_len = (r->valid_location && ctx->vars.uri.len) ?
@@ -691,10 +843,18 @@ ngx_http_proxy_create_request(ngx_http_request_t *r)
r->uri.len - loc_len, NGX_ESCAPE_URI);
}
- len += ctx->vars.uri.len + r->uri.len - loc_len + escape
- + sizeof("?") - 1 + r->args.len;
+ uri_len = ctx->vars.uri.len + r->uri.len - loc_len + escape
+ + sizeof("?") - 1 + r->args.len;
}
+ if (uri_len == 0) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "zero length URI to proxy");
+ return NGX_ERROR;
+ }
+
+ len += uri_len;
+
ngx_http_script_flush_no_cacheable_variables(r, plcf->flushes);
if (plcf->body_set_len) {
@@ -980,6 +1140,17 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r)
u = r->upstream;
if (rc == NGX_HTTP_PROXY_PARSE_NO_HEADER) {
+
+#if (NGX_HTTP_CACHE)
+
+ if (r->cache) {
+ r->http_version = NGX_HTTP_VERSION_9;
+ u->headers_in.status_n = NGX_HTTP_OK;
+ return NGX_OK;
+ }
+
+#endif
+
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"upstream sent no valid HTTP/1.0 header");
@@ -996,8 +1167,11 @@ ngx_http_proxy_process_status_line(ngx_http_request_t *r)
return NGX_OK;
}
+ if (u->state) {
+ u->state->status = ctx->status;
+ }
+
u->headers_in.status_n = ctx->status;
- u->state->status = ctx->status;
u->headers_in.status_line.len = ctx->status_end - ctx->status_start;
u->headers_in.status_line.data = ngx_pnalloc(r->pool,
@@ -1638,6 +1812,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
*
* conf->upstream.bufs.num = 0;
* conf->upstream.next_upstream = 0;
+ * conf->upstream.use_stale_cache = 0;
* conf->upstream.temp_path = NULL;
* conf->upstream.hide_headers_hash = { NULL, 0 };
* conf->upstream.uri = { 0, NULL };
@@ -1675,6 +1850,12 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
conf->upstream.pass_request_headers = NGX_CONF_UNSET;
conf->upstream.pass_request_body = NGX_CONF_UNSET;
+#if (NGX_HTTP_CACHE)
+ conf->upstream.cache = NGX_CONF_UNSET_PTR;
+ conf->upstream.cache_min_uses = NGX_CONF_UNSET_UINT;
+ conf->upstream.cache_valid = NGX_CONF_UNSET_PTR;
+#endif
+
conf->upstream.hide_headers = NGX_CONF_UNSET_PTR;
conf->upstream.pass_headers = NGX_CONF_UNSET_PTR;
@@ -1702,16 +1883,11 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_proxy_loc_conf_t *prev = parent;
ngx_http_proxy_loc_conf_t *conf = child;
- u_char *p;
- size_t size;
- uintptr_t *code;
- ngx_uint_t i;
- ngx_keyval_t *src, *s, *h;
- ngx_hash_key_t *hk;
- ngx_hash_init_t hash;
- ngx_http_proxy_redirect_t *pr;
- ngx_http_script_compile_t sc;
- ngx_http_script_copy_code_t *copy;
+ size_t size;
+ ngx_keyval_t *s;
+ ngx_hash_init_t hash;
+ ngx_http_proxy_redirect_t *pr;
+ ngx_http_script_compile_t sc;
if (conf->upstream.store != 0) {
ngx_conf_merge_value(conf->upstream.store,
@@ -1850,10 +2026,53 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
|NGX_HTTP_UPSTREAM_FT_OFF;
}
- ngx_conf_merge_path_value(conf->upstream.temp_path,
+ if (ngx_conf_merge_path_value(cf, &conf->upstream.temp_path,
prev->upstream.temp_path,
- NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0,
- ngx_garbage_collector_temp_handler, cf);
+ &ngx_http_proxy_temp_path)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+
+#if (NGX_HTTP_CACHE)
+
+ ngx_conf_merge_ptr_value(conf->upstream.cache,
+ prev->upstream.cache, NULL);
+
+ if (conf->upstream.cache && conf->upstream.cache->data == NULL) {
+ ngx_shm_zone_t *shm_zone;
+
+ shm_zone = conf->upstream.cache;
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"proxy_cache\" zone \"%V\" is unknown",
+ &shm_zone->name);
+
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_conf_merge_uint_value(conf->upstream.cache_min_uses,
+ prev->upstream.cache_min_uses, 1);
+
+ ngx_conf_merge_bitmask_value(conf->upstream.cache_use_stale,
+ prev->upstream.cache_use_stale,
+ (NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_OFF));
+
+ if (conf->upstream.cache_use_stale & NGX_HTTP_UPSTREAM_FT_OFF) {
+ conf->upstream.cache_use_stale = NGX_CONF_BITMASK_SET
+ |NGX_HTTP_UPSTREAM_FT_OFF;
+ }
+
+ ngx_conf_merge_ptr_value(conf->upstream.cache_valid,
+ prev->upstream.cache_valid, NULL);
+
+ if (conf->upstream.cache_valid == NULL) {
+ conf->upstream.cache = NULL;
+ }
+
+#endif
if (conf->method.len == 0) {
conf->method = prev->method;
@@ -1984,6 +2203,27 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
s->value.data = (u_char *) "$proxy_internal_body_length";
}
+ if (ngx_http_proxy_merge_headers(cf, conf, prev) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_merge_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
+ ngx_http_proxy_loc_conf_t *prev)
+{
+ u_char *p;
+ size_t size;
+ uintptr_t *code;
+ ngx_uint_t i;
+ ngx_keyval_t *src, *s, *h;
+ ngx_hash_key_t *hk;
+ ngx_hash_init_t hash;
+ ngx_http_script_compile_t sc;
+ ngx_http_script_copy_code_t *copy;
if (conf->headers_source == NULL) {
conf->flushes = prev->flushes;
@@ -1994,31 +2234,31 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
}
if (conf->headers_set_hash.buckets) {
- return NGX_CONF_OK;
+ return NGX_OK;
}
conf->headers_names = ngx_array_create(cf->pool, 4, sizeof(ngx_hash_key_t));
if (conf->headers_names == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
if (conf->headers_source == NULL) {
conf->headers_source = ngx_array_create(cf->pool, 4,
sizeof(ngx_keyval_t));
if (conf->headers_source == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
}
conf->headers_set_len = ngx_array_create(cf->pool, 64, 1);
if (conf->headers_set_len == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
conf->headers_set = ngx_array_create(cf->pool, 512, 1);
if (conf->headers_set == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
@@ -2034,7 +2274,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
s = ngx_array_push(conf->headers_source);
if (s == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
*s = *h;
@@ -2052,7 +2292,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
hk = ngx_array_push(conf->headers_names);
if (hk == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
hk->key = src[i].key;
@@ -2067,7 +2307,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
copy = ngx_array_push_n(conf->headers_set_len,
sizeof(ngx_http_script_copy_code_t));
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = (ngx_http_script_code_pt)
@@ -2084,7 +2324,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
copy = ngx_array_push_n(conf->headers_set, size);
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = ngx_http_script_copy_code;
@@ -2102,7 +2342,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
copy = ngx_array_push_n(conf->headers_set_len,
sizeof(ngx_http_script_copy_code_t));
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = (ngx_http_script_code_pt)
@@ -2116,7 +2356,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
copy = ngx_array_push_n(conf->headers_set, size);
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = ngx_http_script_copy_code;
@@ -2136,14 +2376,14 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
sc.values = &conf->headers_set;
if (ngx_http_script_compile(&sc) != NGX_OK) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy = ngx_array_push_n(conf->headers_set_len,
sizeof(ngx_http_script_copy_code_t));
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = (ngx_http_script_code_pt)
@@ -2157,7 +2397,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
copy = ngx_array_push_n(conf->headers_set, size);
if (copy == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
copy->code = ngx_http_script_copy_code;
@@ -2169,14 +2409,14 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
if (code == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
*code = (uintptr_t) NULL;
code = ngx_array_push_n(conf->headers_set, sizeof(uintptr_t));
if (code == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
*code = (uintptr_t) NULL;
@@ -2184,7 +2424,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
code = ngx_array_push_n(conf->headers_set_len, sizeof(uintptr_t));
if (code == NULL) {
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
*code = (uintptr_t) NULL;
@@ -2202,10 +2442,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->headers_names->nelts)
!= NGX_OK)
{
- return NGX_CONF_ERROR;
+ return NGX_ERROR;
}
- return NGX_CONF_OK;
+ return NGX_OK;
}
@@ -2298,16 +2538,16 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
return NGX_CONF_ERROR;
}
- if (ngx_http_proxy_set_vars(cf->pool, &u, &plcf->vars) != NGX_OK) {
- return NGX_CONF_ERROR;
- }
-
plcf->vars.schema.len = add;
plcf->vars.schema.data = url->data;
- plcf->location = clcf->name;
+ plcf->vars.key_start = plcf->vars.schema;
+
+ ngx_http_proxy_set_vars(&u, &plcf->vars);
clcf->handler = ngx_http_proxy_handler;
+ plcf->location = clcf->name;
+
if (clcf->named
#if (NGX_PCRE)
|| clcf->regex
@@ -2473,6 +2713,38 @@ ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
+#if (NGX_HTTP_CACHE)
+
+static char *
+ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ if (plcf->upstream.cache != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+ plcf->upstream.cache = NULL;
+ return NGX_CONF_OK;
+ }
+
+ plcf->upstream.cache = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_proxy_module);
+ if (plcf->upstream.cache == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+#endif
+
+
static char *
ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data)
{
@@ -2563,12 +2835,13 @@ ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf)
#endif
-static ngx_int_t
-ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
- ngx_http_proxy_vars_t *v)
+static void
+ngx_http_proxy_set_vars(ngx_url_t *u, ngx_http_proxy_vars_t *v)
{
if (u->family != AF_UNIX) {
+
if (u->no_port || u->port == u->default_port) {
+
v->host_header = u->host;
if (u->default_port == 80) {
@@ -2586,14 +2859,15 @@ ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u,
v->port = u->port_text;
}
+ v->key_start.len += v->host_header.len;
+
} else {
v->host_header.len = sizeof("localhost") - 1;
v->host_header.data = (u_char *) "localhost";
v->port.len = 0;
v->port.data = (u_char *) "";
+ v->key_start.len += sizeof("unix:") - 1 + u->host.len + 1;
}
v->uri = u->uri;
-
- return NGX_OK;
}
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 47e08e733..f708c874b 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -199,6 +199,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
+ r->headers_out.status_line.len = 0;
if (ctx->ranges.nelts == 1) {
return ngx_http_range_singlepart_header(r, ctx);
@@ -708,6 +709,7 @@ static ngx_int_t
ngx_http_range_multipart_body(ngx_http_request_t *r,
ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in)
{
+ off_t body_start;
ngx_buf_t *b, *buf;
ngx_uint_t i;
ngx_chain_t *out, *hcl, *rcl, *dcl, **ll;
@@ -717,6 +719,12 @@ ngx_http_range_multipart_body(ngx_http_request_t *r,
buf = in->buf;
range = ctx->ranges.elts;
+#if (NGX_HTTP_CACHE)
+ body_start = r->cached ? r->cache->body_start : 0;
+#else
+ body_start = 0;
+#endif
+
for (i = 0; i < ctx->ranges.nelts; i++) {
/*
@@ -777,8 +785,8 @@ ngx_http_range_multipart_body(ngx_http_request_t *r,
b->file = buf->file;
if (buf->in_file) {
- b->file_pos = range[i].start;
- b->file_last = range[i].end;
+ b->file_pos = body_start + range[i].start;
+ b->file_last = body_start + range[i].end;
}
if (ngx_buf_in_memory(buf)) {
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 7699cb0a2..89de976df 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -10,12 +10,13 @@
#include <ngx_config.h>
#include <ngx_core.h>
-#include <ngx_garbage_collector.h>
-typedef struct ngx_http_request_s ngx_http_request_t;
-typedef struct ngx_http_upstream_s ngx_http_upstream_t;
-typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t;
+typedef struct ngx_http_request_s ngx_http_request_t;
+typedef struct ngx_http_upstream_s ngx_http_upstream_t;
+typedef struct ngx_http_cache_s ngx_http_cache_t;
+typedef struct ngx_http_file_cache_s ngx_http_file_cache_t;
+typedef struct ngx_http_log_ctx_s ngx_http_log_ctx_t;
typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
@@ -23,12 +24,6 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r,
ngx_http_request_t *sr, u_char *buf, size_t len);
-#if (NGX_HTTP_CACHE)
-#include <ngx_http_cache.h>
-#endif
-/* STUB */
-#include <ngx_http_cache.h>
-
#include <ngx_http_variables.h>
#include <ngx_http_request.h>
#include <ngx_http_upstream.h>
@@ -38,6 +33,9 @@ typedef u_char *(*ngx_http_log_handler_pt)(ngx_http_request_t *r,
#include <ngx_http_script.h>
#include <ngx_http_core_module.h>
+#if (NGX_HTTP_CACHE)
+#include <ngx_http_cache.h>
+#endif
#if (NGX_HTTP_SSI)
#include <ngx_http_ssi_filter_module.h>
#endif
diff --git a/src/http/ngx_http_cache.c b/src/http/ngx_http_cache.c
deleted file mode 100644
index 8471459af..000000000
--- a/src/http/ngx_http_cache.c
+++ /dev/null
@@ -1,576 +0,0 @@
-
-/*
- * Copyright (C) Igor Sysoev
- */
-
-
-#include <ngx_config.h>
-#include <ngx_core.h>
-#include <ngx_http.h>
-
-
-#if 0
-
-static ngx_http_module_t ngx_http_cache_module_ctx = {
- NULL, /* pre conf */
-
- NULL, /* create main configuration */
- NULL, /* init main configuration */
-
- NULL, /* create server configuration */
- NULL, /* merge server configuration */
-
- NULL, /* create location configuration */
- NULL /* merge location configuration */
-};
-
-
-ngx_module_t ngx_http_cache_module = {
- NGX_MODULE,
- &ngx_http_cache_module_ctx, /* module context */
- NULL, /* module directives */
- NGX_HTTP_MODULE, /* module type */
- NULL, /* init module */
- NULL /* init process */
-};
-
-#endif
-
-
-static ngx_int_t ngx_http_cache_create(ngx_http_request_t *r)
-{
- ngx_str_t *key;
-
- if (!(r->cache = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t)))) {
- return NGX_ERROR;
- }
-
- if (ngx_array_init(&r->cache->key, r->pool, 5, sizeof(ngx_str_t))
- == NGX_ERROR)
- {
- return NGX_ERROR;
- }
-
- /* preallocate the primary key */
-
- if (!(key = ngx_array_push(&r->cache->key))) {
- return NGX_ERROR;
- }
-
- key->len = 0;
- key->data = NULL;
-
- /*
- * we use offsetof() because sizeof() pads the struct size to the int size
- */
-
- r->cache->header_size = offsetof(ngx_http_cache_header_t, key);
-
- r->cache->log = r->connection->log;
- r->cache->file.log = r->connection->log;
-
- return NGX_OK;
-}
-
-
-ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx)
-{
- ngx_str_t *key;
- ngx_http_cache_t *c;
-
- if (r->cache == NULL) {
- if (ngx_http_cache_create(r) == NGX_ERROR) {
- return NGX_ABORT;
- }
- }
-
- c = r->cache;
- key = c->key.elts;
-
- if (ctx->primary) {
- key[0] = ctx->key;
- c->header_size += ctx->key.len;
- c->key_len += ctx->key.len;
- c->buf = ctx->buf;
-
- } else {
- if (key[0].len == 0) {
- key[0] = r->uri;
- c->header_size += r->uri.len;
- c->key_len += ctx->key.len;
- }
-
- if (!(key = ngx_array_push(&r->cache->key))) {
- return NGX_ABORT;
- }
-
- c->header_size += ctx->key.len;
- c->key_len += ctx->key.len;
- }
-
-#if 0
-
- if (ctx->memory) {
- ngx_http_memory_cache_get(r, ctx);
- }
-
-#endif
-
- if (ctx->file) {
- return ngx_http_file_cache_get(r, ctx);
- }
-
- return NGX_DECLINED;
-}
-
-
-#if 0
-
-
-ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *hash,
- ngx_http_cleanup_t *cleanup,
- ngx_str_t *key, uint32_t *crc)
-{
- ngx_uint_t i;
- ngx_http_cache_t *c;
-
- *crc = ngx_crc(key->data, key->len);
-
- c = hash->elts + *crc % hash->hash * hash->nelts;
-
- if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
- return (void *) NGX_ERROR;
- }
-
- for (i = 0; i < hash->nelts; i++) {
- if (c[i].crc == *crc
- && c[i].key.len == key->len
- && ngx_rstrncmp(c[i].key.data, key->data, key->len) == 0)
- {
-#if 0
- if (c[i].expired) {
- ngx_mutex_unlock(&hash->mutex);
- return (void *) NGX_AGAIN;
- }
-#endif
-
- c[i].refs++;
-
- if ((!(c[i].notify && (ngx_event_flags & NGX_USE_KQUEUE_EVENT)))
- && (ngx_cached_time - c[i].updated >= hash->update))
- {
- c[i].expired = 1;
- }
-
- ngx_mutex_unlock(&hash->mutex);
-
- if (cleanup) {
- cleanup->data.cache.hash = hash;
- cleanup->data.cache.cache = &c[i];
- cleanup->valid = 1;
- cleanup->cache = 1;
- }
-
- return &c[i];
- }
- }
-
- ngx_mutex_unlock(&hash->mutex);
-
- return NULL;
-}
-
-
-ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
- ngx_http_cache_t *cache,
- ngx_http_cleanup_t *cleanup,
- ngx_str_t *key, uint32_t crc,
- ngx_str_t *value, ngx_log_t *log)
-{
- time_t old;
- ngx_uint_t i;
- ngx_http_cache_t *c;
-
- old = ngx_cached_time + 1;
-
- c = hash->elts + crc % hash->hash * hash->nelts;
-
- if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
- return (void *) NGX_ERROR;
- }
-
- if (cache == NULL) {
-
- /* allocate a new entry */
-
- for (i = 0; i < hash->nelts; i++) {
- if (c[i].refs > 0) {
- /* a busy entry */
- continue;
- }
-
- if (c[i].key.len == 0) {
- /* a free entry is found */
- cache = &c[i];
- break;
- }
-
- /* looking for the oldest cache entry */
-
- if (old > c[i].accessed) {
-
- old = c[i].accessed;
- cache = &c[i];
- }
- }
-
- if (cache == NULL) {
- ngx_mutex_unlock(&hash->mutex);
- return NULL;
- }
-
- ngx_http_cache_free(cache, key, value, log);
-
- if (cache->key.data == NULL) {
- cache->key.data = ngx_alloc(key->len, log);
- if (cache->key.data == NULL) {
- ngx_http_cache_free(cache, NULL, NULL, log);
- ngx_mutex_unlock(&hash->mutex);
- return NULL;
- }
- }
-
- cache->key.len = key->len;
- ngx_memcpy(cache->key.data, key->data, key->len);
-
- } else if (value) {
- ngx_http_cache_free(cache, key, value, log);
- }
-
- if (value) {
- if (cache->data.value.data == NULL) {
- cache->data.value.data = ngx_alloc(value->len, log);
- if (cache->data.value.data == NULL) {
- ngx_http_cache_free(cache, NULL, NULL, log);
- ngx_mutex_unlock(&hash->mutex);
- return NULL;
- }
- }
-
- cache->data.value.len = value->len;
- ngx_memcpy(cache->data.value.data, value->data, value->len);
- }
-
- cache->crc = crc;
- cache->key.len = key->len;
-
- cache->refs = 1;
- cache->count = 0;
-
- cache->deleted = 0;
- cache->expired = 0;
- cache->memory = 0;
- cache->mmap = 0;
- cache->notify = 0;
-
- if (cleanup) {
- cleanup->data.cache.hash = hash;
- cleanup->data.cache.cache = cache;
- cleanup->valid = 1;
- cleanup->cache = 1;
- }
-
- ngx_mutex_unlock(&hash->mutex);
-
- return cache;
-}
-
-
-void ngx_http_cache_free(ngx_http_cache_t *cache,
- ngx_str_t *key, ngx_str_t *value, ngx_log_t *log)
-{
- if (cache->memory) {
- if (cache->data.value.data
- && (value == NULL || value->len > cache->data.value.len))
- {
- ngx_free(cache->data.value.data);
- cache->data.value.data = NULL;
- }
- }
-
- /* TODO: mmap */
-
- cache->data.value.len = 0;
-
- if (cache->fd != NGX_INVALID_FILE) {
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
- "http cache close fd: %d", cache->fd);
-
- if (ngx_close_file(cache->fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
- ngx_close_file_n " \"%s\" failed",
- cache->key.data);
- }
-
- cache->fd = NGX_INVALID_FILE;
- }
-
- if (cache->key.data && (key == NULL || key->len > cache->key.len)) {
- ngx_free(cache->key.data);
- cache->key.data = NULL;
- }
-
- cache->key.len = 0;
-
- cache->refs = 0;
-}
-
-
-void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache)
-{
- if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
- return;
- }
-}
-
-
-void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
- ngx_http_cache_t *cache, ngx_log_t *log)
-{
- if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
- return;
- }
-
- cache->refs--;
-
- if (cache->refs == 0 && cache->deleted) {
- ngx_http_cache_free(cache, NULL, NULL, log);
- }
-
- ngx_mutex_unlock(&hash->mutex);
-}
-
-
-#if 0
-
-ngx_http_cache_add_file_event(ngx_http_cache_hash_t *hash,
- ngx_http_cache_t *cache)
-{
- ngx_event_t *ev;
- ngx_http_cache_event_ctx_t *ctx;
-
- ev = &ngx_cycle->read_events[fd];
- ngx_memzero(ev, sizeof(ngx_event_t);
-
- ev->data = data;
- ev->event_handler = ngx_http_cache_invalidate;
-
- return ngx_add_event(ev, NGX_VNODE_EVENT, 0);
-}
-
-
-void ngx_http_cache_invalidate(ngx_event_t *ev)
-{
- ngx_http_cache_event_ctx_t *ctx;
-
- ctx = ev->data;
-
- ngx_http_cache_lock(&ctx->hash->mutex);
-
- if (ctx->cache->refs == 0)
- ngx_http_cache_free(ctx->cache, NULL, NULL, ctx->log);
-
- } else {
- ctx->cache->deleted = 1;
- }
-
- ngx_http_cache_unlock(&ctx->hash->mutex);
-}
-
-#endif
-
-
-/* TODO: currently fd only */
-
-ngx_int_t ngx_http_send_cached(ngx_http_request_t *r)
-{
- ngx_int_t rc;
- ngx_hunk_t *h;
- ngx_chain_t out;
- ngx_http_log_ctx_t *ctx;
-
- ctx = r->connection->log->data;
- ctx->action = "sending response to client";
-
- r->headers_out.status = NGX_HTTP_OK;
- r->headers_out.content_length_n = r->cache->data.size;
- r->headers_out.last_modified_time = r->cache->last_modified;
-
- if (ngx_http_set_content_type(r) != NGX_OK) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
- /* we need to allocate all before the header would be sent */
-
- if (!(h = ngx_pcalloc(r->pool, sizeof(ngx_hunk_t)))) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
- if (!(h->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)))) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
-
- rc = ngx_http_send_header(r);
-
- if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
- return rc;
- }
-
- h->type = r->main ? NGX_HUNK_FILE : NGX_HUNK_FILE|NGX_HUNK_LAST;
-
- h->file_pos = 0;
- h->file_last = r->cache->data.size;
-
- h->file->fd = r->cache->fd;
- h->file->log = r->connection->log;
-
- out.hunk = h;
- out.next = NULL;
-
- return ngx_http_output_filter(r, &out);
-}
-
-
-char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
- char *p = conf;
-
- ngx_int_t i, j, dup, invalid;
- ngx_str_t *value, line;
- ngx_http_cache_t *c;
- ngx_http_cache_hash_t *ch, **chp;
-
- chp = (ngx_http_cache_hash_t **) (p + cmd->offset);
- if (*chp) {
- return "is duplicate";
- }
-
- if (!(ch = ngx_pcalloc(cf->pool, sizeof(ngx_http_cache_hash_t)))) {
- return NGX_CONF_ERROR;
- }
- *chp = ch;
-
- dup = 0;
- invalid = 0;
-
- value = cf->args->elts;
-
- for (i = 1; i < cf->args->nelts; i++) {
-
- if (value[i].data[1] != '=') {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
-
- switch (value[i].data[0]) {
-
- case 'h':
- if (ch->hash) {
- dup = 1;
- break;
- }
-
- ch->hash = ngx_atoi(value[i].data + 2, value[i].len - 2);
- if (ch->hash == (size_t) NGX_ERROR || ch->hash == 0) {
- invalid = 1;
- break;
- }
-
- continue;
-
- case 'n':
- if (ch->nelts) {
- dup = 1;
- break;
- }
-
- ch->nelts = ngx_atoi(value[i].data + 2, value[i].len - 2);
- if (ch->nelts == (size_t) NGX_ERROR || ch->nelts == 0) {
- invalid = 1;
- break;
- }
-
- continue;
-
- case 'l':
- if (ch->life) {
- dup = 1;
- break;
- }
-
- line.len = value[i].len - 2;
- line.data = value[i].data + 2;
-
- ch->life = ngx_parse_time(&line, 1);
- if (ch->life == NGX_ERROR || ch->life == 0) {
- invalid = 1;
- break;
- }
-
- continue;
-
- case 'u':
- if (ch->update) {
- dup = 1;
- break;
- }
-
- line.len = value[i].len - 2;
- line.data = value[i].data + 2;
-
- ch->update = ngx_parse_time(&line, 1);
- if (ch->update == NGX_ERROR || ch->update == 0) {
- invalid = 1;
- break;
- }
-
- continue;
-
- default:
- invalid = 1;
- }
-
- if (dup) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "duplicate value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
-
- if (invalid) {
- ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
- "invalid value \"%s\"", value[i].data);
- return NGX_CONF_ERROR;
- }
- }
-
- ch->elts = ngx_pcalloc(cf->pool,
- ch->hash * ch->nelts * sizeof(ngx_http_cache_t));
- if (ch->elts == NULL) {
- return NGX_CONF_ERROR;
- }
-
- for (i = 0; i < (ngx_int_t) ch->hash; i++) {
- c = ch->elts + i * ch->nelts;
-
- for (j = 0; j < (ngx_int_t) ch->nelts; j++) {
- c[j].fd = NGX_INVALID_FILE;
- }
- }
-
- return NGX_CONF_OK;
-}
-
-
-#endif
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index fb446e471..b18d53961 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -13,145 +13,115 @@
#include <ngx_http.h>
-/*
- * The 3 bits allows the 7 uses before the cache entry allocation.
- * We can use maximum 7 bits, i.e up to the 127 uses.
- */
-#define NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS 3
-
-
-typedef struct {
- uint32_t crc;
- ngx_str_t key;
- time_t accessed;
-
- unsigned refs:20; /* 1048576 references */
-
- unsigned count:NGX_HTTP_CACHE_LAZY_ALLOCATION_BITS;
+/**/
+#define NGX_HTTP_CACHE_STALE 1
+#define NGX_HTTP_CACHE_AGED 2
+#define NGX_HTTP_CACHE_THE_SAME 3
+/**/
- unsigned deleted:1;
- unsigned expired:1;
- unsigned memory:1;
- unsigned mmap:1;
- unsigned notify:1;
-
- ngx_fd_t fd;
-#if (NGX_USE_HTTP_FILE_CACHE_UNIQ)
- ngx_file_uniq_t uniq; /* no needed with kqueue */
-#endif
- time_t last_modified;
- time_t updated;
-
- union {
- off_t size;
- ngx_str_t value;
- } data;
-} ngx_http_cache_entry_t;
+#define NGX_HTTP_CACHE_KEY_LEN 16
typedef struct {
- time_t expires;
- time_t last_modified;
- time_t date;
- off_t length;
- size_t key_len;
- char key[1];
-} ngx_http_cache_header_t;
+ ngx_uint_t status;
+ time_t valid;
+} ngx_http_cache_valid_t;
-#define NGX_HTTP_CACHE_HASH 7
-#define NGX_HTTP_CACHE_NELTS 4
+/* ngx_http_file_cache_node_t takes exactly 64 bytes on FreeBSD/i386 */
typedef struct {
- ngx_http_cache_entry_t *elts;
- size_t hash;
- size_t nelts;
- time_t life;
- time_t update;
-#if (NGX_THREADS)
- ngx_mutex_t mutex;
-#endif
- ngx_pool_t *pool;
-} ngx_http_cache_hash_t;
+ ngx_rbtree_node_t node;
+ ngx_queue_t queue;
+ u_char key[NGX_HTTP_CACHE_KEY_LEN
+ - sizeof(ngx_rbtree_key_t)];
-typedef struct {
- ngx_http_cache_hash_t *hash;
- ngx_http_cache_entry_t *cache;
- ngx_file_t file;
- ngx_array_t key;
- uint32_t crc;
- u_char md5[16];
- ngx_path_t *path;
- ngx_buf_t *buf;
- time_t expires;
- time_t last_modified;
- time_t date;
- off_t length;
- size_t key_len;
- size_t file_start;
- ngx_file_uniq_t uniq;
- ngx_log_t *log;
-
- /* STUB */
- ssize_t header_size;
- ngx_str_t key0;
-} ngx_http_cache_t;
+ unsigned count:20;
+ unsigned uses:10;
+ unsigned valid_msec:10;
+ unsigned error:10;
+ /* 7 unused bits */
+ unsigned exists:1;
+ ngx_file_uniq_t uniq;
+ time_t expire;
+ time_t valid_sec;
+ size_t body_start;
+} ngx_http_file_cache_node_t;
-typedef struct {
- ngx_path_t *path;
- ngx_str_t key;
- ngx_buf_t *buf;
- unsigned file:1;
- unsigned memory:1;
- unsigned primary:1;
-} ngx_http_cache_ctx_t;
+struct ngx_http_cache_s {
+ ngx_file_t file;
+ ngx_array_t keys;
+ uint32_t crc32;
+ u_char key[NGX_HTTP_CACHE_KEY_LEN];
+
+ ngx_file_uniq_t uniq;
+ time_t valid_sec;
+ time_t last_modified;
+ time_t date;
+ size_t header_start;
+ size_t body_start;
+ off_t length;
-#define NGX_HTTP_CACHE_STALE 1
-#define NGX_HTTP_CACHE_AGED 2
-#define NGX_HTTP_CACHE_THE_SAME 3
+ ngx_uint_t min_uses;
+ ngx_uint_t uses;
+ ngx_uint_t error;
+ ngx_uint_t valid_msec;
+ ngx_buf_t *buf;
-ngx_int_t ngx_http_cache_get(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx);
+ ngx_http_file_cache_t *file_cache;
+ ngx_http_file_cache_node_t *node;
-ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
- ngx_http_cache_ctx_t *ctx);
+ unsigned updated:1;
+ unsigned exists:1;
+ unsigned temp_file:1;
+};
-ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c);
-ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
- ngx_dir_t *dir);
+typedef struct {
+ time_t valid_sec;
+ time_t last_modified;
+ time_t date;
+ uint32_t crc32;
+ u_short valid_msec;
+ u_short header_start;
+ u_short body_start;
+} ngx_http_file_cache_header_t;
-#if 0
+struct ngx_http_file_cache_s {
+ ngx_rbtree_t *rbtree;
+ ngx_queue_t *queue;
+ ngx_slab_pool_t *shpool;
-ngx_http_cache_t *ngx_http_cache_get(ngx_http_cache_hash_t *cache,
- ngx_http_cleanup_t *cleanup,
- ngx_str_t *key, uint32_t *crc);
+ ngx_path_t *path;
-ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
- ngx_http_cache_t *cache,
- ngx_http_cleanup_t *cleanup,
- ngx_str_t *key, uint32_t crc,
- ngx_str_t *value, ngx_log_t *log);
-void ngx_http_cache_free(ngx_http_cache_t *cache,
- ngx_str_t *key, ngx_str_t *value, ngx_log_t *log);
-void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache);
-void ngx_http_cache_unlock(ngx_http_cache_hash_t *hash,
- ngx_http_cache_t *cache, ngx_log_t *log);
+ time_t inactive;
+ time_t created;
+ time_t clean_time;
+ time_t next_clean_time;
-int ngx_http_cache_update_file(ngx_http_request_t *r,ngx_http_cache_ctx_t *ctx,
- ngx_str_t *temp_file);
+ ngx_shm_zone_t *shm_zone;
+};
-int ngx_http_send_cached(ngx_http_request_t *r);
+void ngx_http_file_cache_create_key(ngx_http_request_t *r);
+ngx_int_t ngx_http_file_cache_open(ngx_http_request_t *r);
+void ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf);
+void ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf);
+ngx_int_t ngx_http_cache_send(ngx_http_request_t *);
+void ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf);
+time_t ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status);
-char *ngx_http_set_cache_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
-#endif
+char *ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+char *ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
#endif /* _NGX_HTTP_CACHE_H_INCLUDED_ */
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 4c2f96fc4..2e455b1e4 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -119,6 +119,11 @@ static ngx_conf_enum_t ngx_http_core_if_modified_since[] = {
};
+static ngx_path_init_t ngx_http_client_temp_path = {
+ ngx_string(NGX_HTTP_CLIENT_TEMP_PATH), { 0, 0, 0 }
+};
+
+
#if (NGX_HTTP_GZIP)
static ngx_conf_enum_t ngx_http_gzip_http_version[] = {
@@ -347,7 +352,7 @@ static ngx_command_t ngx_http_core_commands[] = {
ngx_conf_set_path_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_core_loc_conf_t, client_body_temp_path),
- (void *) ngx_garbage_collector_temp_handler },
+ NULL },
{ ngx_string("client_body_in_file_only"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
@@ -2185,6 +2190,10 @@ ngx_http_internal_redirect(ngx_http_request_t *r,
ngx_http_update_location_config(r);
+#if (NGX_HTTP_CACHE)
+ r->cache = NULL;
+#endif
+
r->internal = 1;
ngx_http_handler(r);
@@ -3156,10 +3165,13 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
conf->resolver = prev->resolver;
}
- ngx_conf_merge_path_value(conf->client_body_temp_path,
+ if (ngx_conf_merge_path_value(cf, &conf->client_body_temp_path,
prev->client_body_temp_path,
- NGX_HTTP_CLIENT_TEMP_PATH, 0, 0, 0,
- ngx_garbage_collector_temp_handler, cf);
+ &ngx_http_client_temp_path)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
ngx_conf_merge_value(conf->reset_timedout_connection,
prev->reset_timedout_connection, 0);
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 9f93bd8f5..0c2b9e2d9 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -7,253 +7,1277 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
+#include <ngx_md5.h>
-#if (NGX_HAVE_OPENSSL_MD5_H)
-#include <openssl/md5.h>
-#else
-#include <md5.h>
-#endif
+static ngx_int_t ngx_http_file_cache_exists(ngx_http_request_t *r,
+ ngx_http_file_cache_t *cache);
+static ngx_http_file_cache_node_t *
+ ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key);
+static void ngx_http_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static void ngx_http_file_cache_cleanup(void *data);
+static time_t ngx_http_file_cache_expire(ngx_http_file_cache_t *cache,
+ ngx_uint_t force);
+static ngx_int_t ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx,
+ ngx_str_t *path);
+static ngx_int_t ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx,
+ ngx_str_t *path);
-#if (NGX_OPENSSL_MD5)
-#define MD5Init MD5_Init
-#define MD5Update MD5_Update
-#define MD5Final MD5_Final
-#endif
+static u_char ngx_http_file_cache_key[] = { LF, 'K', 'E', 'Y', ':', ' ' };
-ngx_int_t ngx_http_file_cache_get(ngx_http_request_t *r,
- ngx_http_cache_ctx_t *ctx)
+
+static ngx_int_t
+ngx_http_file_cache_init(ngx_shm_zone_t *shm_zone, void *data)
{
- ngx_uint_t i;
+ ngx_http_file_cache_t *ocache = data;
+
+ ngx_rbtree_node_t *sentinel;
+ ngx_http_file_cache_t *cache;
+
+ cache = shm_zone->data;
+
+ if (ocache) {
+ if (ngx_strcmp(cache->path->name.data, ocache->path->name.data) != 0) {
+ ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+ "cache \"%V\" uses the \"%V\" cache path "
+ "while previously it used the \"%V\" cache path",
+ &shm_zone->name, &cache->path->name,
+ &ocache->path->name);
+
+ return NGX_ERROR;
+ }
+
+ cache->rbtree = ocache->rbtree;
+ cache->queue = ocache->queue;
+ cache->shpool = ocache->shpool;
+ cache->created = ocache->created;
+
+ return NGX_OK;
+ }
+
+ cache->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ cache->rbtree = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_t));
+ if (cache->rbtree == NULL) {
+ return NGX_ERROR;
+ }
+
+ sentinel = ngx_slab_alloc(cache->shpool, sizeof(ngx_rbtree_node_t));
+ if (sentinel == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_rbtree_init(cache->rbtree, sentinel,
+ ngx_http_file_cache_rbtree_insert_value);
+
+ cache->queue = ngx_slab_alloc(cache->shpool, sizeof(ngx_queue_t));
+ if (cache->queue == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_queue_init(cache->queue);
+
+ cache->created = ngx_time();
+
+ return NGX_OK;
+}
+
+
+void
+ngx_http_file_cache_create_key(ngx_http_request_t *r)
+{
+ size_t len;
ngx_str_t *key;
+ ngx_uint_t i;
+ ngx_md5_t md5;
ngx_http_cache_t *c;
- MD5_CTX md5;
c = r->cache;
- c->file.name.len = ctx->path->name.len + 1 + ctx->path->len + 32;
- if (!(c->file.name.data = ngx_palloc(r->pool, c->file.name.len + 1))) {
- return NGX_ABORT;
+ len = 0;
+
+ ngx_crc32_init(c->crc32);
+ ngx_md5_init(&md5);
+
+ key = c->keys.elts;
+ for (i = 0; i < c->keys.nelts; i++) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http cache key: \"%V\"", &key[i]);
+
+ len += key[i].len;
+
+ ngx_crc32_update(&c->crc32, key[i].data, key[i].len);
+ ngx_md5_update(&md5, key[i].data, key[i].len);
}
- MD5Init(&md5);
+ c->header_start = sizeof(ngx_http_file_cache_header_t)
+ + sizeof(ngx_http_file_cache_key) + len + 1;
- key = c->key.elts;
- for (i = 0; i < c->key.nelts; i++) {
- MD5Update(&md5, key[i].data, key[i].len);
+ ngx_crc32_final(c->crc32);
+ ngx_md5_final(c->key, &md5);
+}
+
+
+ngx_int_t
+ngx_http_file_cache_open(ngx_http_request_t *r)
+{
+ u_char *p;
+ time_t now;
+ ssize_t n;
+ ngx_int_t rc, rv;
+ ngx_uint_t cold, test;
+ ngx_path_t *path;
+ ngx_http_cache_t *c;
+ ngx_pool_cleanup_t *cln;
+ ngx_open_file_info_t of;
+ ngx_http_file_cache_t *cache;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_file_cache_header_t *h;
+
+ c = r->cache;
+ cache = c->file_cache;
+
+ cln = ngx_pool_cleanup_add(r->pool, 0);
+ if (cln == NULL) {
+ return NGX_ERROR;
}
- MD5Update(&md5, ctx->key.data, ctx->key.len);
+ rc = ngx_http_file_cache_exists(r, cache);
- MD5Final(c->md5, &md5);
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache exists: %i u:%ui e:%d",
+ rc, c->uses, c->exists);
- ngx_memcpy(c->file.name.data, ctx->path->name.data, ctx->path->name.len);
+ if (rc == NGX_ERROR) {
+ return rc;
+ }
- ngx_md5_text(c->file.name.data + ctx->path->name.len + 1 + ctx->path->len,
- c->md5);
+ cln->handler = ngx_http_file_cache_cleanup;
+ cln->data = c;
- ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "file cache key: %V, md5: %s", &ctx->key,
- c->file.name.data + ctx->path->name.len + 1 + ctx->path->len);
+ if (rc == NGX_AGAIN) {
+ return rc;
+ }
- ngx_create_hashed_filename(&c->file, ctx->path);
+ now = ngx_time();
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "file cache name: %s", c->file.name.data);
+ cold = (now - cache->created < cache->inactive) ? 1 : 0;
- return ngx_http_file_cache_open(r->cache);
-}
+ if (rc == NGX_OK) {
+ if (c->error) {
+ return c->error;
+ }
-ngx_int_t ngx_http_file_cache_open(ngx_http_cache_t *c)
-{
- ssize_t n;
- ngx_err_t err;
- ngx_http_cache_header_t *h;
+ c->temp_file = 1;
+ test = c->exists ? 1 : 0;
+ rv = NGX_DECLINED;
- c->file.fd = ngx_open_file(c->file.name.data,
- NGX_FILE_RDONLY, NGX_FILE_OPEN);
+ } else { /* rc == NGX_DECLINED */
- if (c->file.fd == NGX_INVALID_FILE) {
- err = ngx_errno;
+ if (c->min_uses > 1) {
- if (err == NGX_ENOENT || err == NGX_ENOTDIR) {
- return NGX_DECLINED;
+ if (!cold) {
+ return NGX_AGAIN;
+ }
+
+ test = 1;
+ rv = NGX_AGAIN;
+
+ } else {
+ c->temp_file = 1;
+ test = cold ? 1 : 0;
+ rv = NGX_DECLINED;
}
+ }
- ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
- ngx_open_file_n " \"%s\" failed", c->file.name.data);
+ path = cache->path;
+
+ c->file.name.len = path->name.len + 1 + path->len
+ + 2 * NGX_HTTP_CACHE_KEY_LEN;
+
+ c->file.name.data = ngx_pnalloc(r->pool, c->file.name.len + 1);
+ if (c->file.name.data == NULL) {
return NGX_ERROR;
}
- if (c->uniq) {
- if (ngx_fd_info(c->file.fd, &c->file.info) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, c->log, ngx_errno,
- ngx_fd_info_n " \"%s\" failed", c->file.name.data);
+ ngx_memcpy(c->file.name.data, path->name.data, path->name.len);
+
+ p = c->file.name.data + path->name.len + 1 + path->len;
+ p = ngx_hex_dump(p, c->key, NGX_HTTP_CACHE_KEY_LEN);
+ *p = '\0';
+ ngx_create_hashed_filename(path, c->file.name.data, c->file.name.len);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+ "cache file: \"%s\"", c->file.name.data);
+
+ if (!test) {
+ return NGX_DECLINED;
+ }
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ ngx_memzero(&of, sizeof(ngx_open_file_info_t));
+
+ of.uniq = c->uniq;
+ of.valid = clcf->open_file_cache_valid;
+ of.min_uses = clcf->open_file_cache_min_uses;
+ of.events = clcf->open_file_cache_events;
+ of.directio = NGX_OPEN_FILE_DIRECTIO_OFF;
+
+ if (ngx_open_cached_file(clcf->open_file_cache, &c->file.name, &of, r->pool)
+ != NGX_OK)
+ {
+ switch (of.err) {
+
+ case 0:
return NGX_ERROR;
- }
- if (ngx_file_uniq(&c->file.info) == c->uniq) {
- if (ngx_close_file(c->file.fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed",
- c->file.name.data);
- }
+ case NGX_ENOENT:
+ case NGX_ENOTDIR:
+ return rv;
- return NGX_HTTP_CACHE_THE_SAME;
+ default:
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
+ ngx_open_file_n " \"%s\" failed", c->file.name.data);
+ return NGX_ERROR;
}
}
- n = ngx_read_file(&c->file, c->buf->pos, c->buf->end - c->buf->last, 0);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache fd: %d", of.fd);
+
+ c->file.fd = of.fd;
- if (n == NGX_ERROR || n == NGX_AGAIN) {
+ c->buf = ngx_create_temp_buf(r->pool, c->body_start);
+ if (c->buf == NULL) {
+ return NGX_ERROR;
+ }
+
+ n = ngx_read_file(&c->file, c->buf->pos, c->body_start, 0);
+
+ if (n == NGX_ERROR) {
return n;
}
- if (n <= c->header_size) {
- ngx_log_error(NGX_LOG_CRIT, c->log, 0,
+ if ((size_t) n <= c->header_start) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
"cache file \"%s\" is too small", c->file.name.data);
return NGX_ERROR;
}
- h = (ngx_http_cache_header_t *) c->buf->pos;
- c->expires = h->expires;
- c->last_modified= h->last_modified;
- c->date = h->date;
- c->length = h->length;
+ h = (ngx_http_file_cache_header_t *) c->buf->pos;
- if (h->key_len > (size_t) (c->buf->end - c->buf->pos)) {
- ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "cache file \"%s\" is probably invalid",
- c->file.name.data);
+ if (h->crc32 != c->crc32 || (size_t) h->header_start != c->header_start) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, 0,
+ "cache file \"%s\" has md5 collision", c->file.name.data);
return NGX_DECLINED;
}
-#if 0
+ c->buf->last += n;
- /* TODO */
+ c->valid_sec = h->valid_sec;
+ c->last_modified = h->last_modified;
+ c->date = h->date;
+ c->valid_msec = h->valid_msec;
+ c->length = of.size;
+ c->body_start = h->body_start;
- if (c->key_len && h->key_len != c->key_len) {
+ r->cached = 1;
- ngx_strncmp(h->key, c->key_data, h->key_len) != 0))
+ if (cold) {
- h->key[h->key_len] = '\0';
- ngx_log_error(NGX_LOG_ALERT, c->log, 0,
- "md5 collision: \"%s\" and \"%s\"",
- h->key, c->key.data);
- return NGX_DECLINED;
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->uses = c->min_uses;
+ c->node->body_start = c->body_start;
+ c->node->exists = 1;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
}
-#endif
+ if (c->valid_sec < now) {
- c->buf->last += n;
+ c->uses = c->min_uses;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache expired: %T %T", c->valid_sec, now);
- if (c->expires < ngx_time()) {
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
- "http file cache expired");
return NGX_HTTP_CACHE_STALE;
}
/* TODO: NGX_HTTP_CACHE_AGED */
- /* STUB */ return NGX_DECLINED;
-
return NGX_OK;
}
-#if 0
+static ngx_int_t
+ngx_http_file_cache_exists(ngx_http_request_t *r, ngx_http_file_cache_t *cache)
+{
+ ngx_int_t rc;
+ ngx_http_file_cache_node_t *fcn;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ fcn = ngx_http_file_cache_lookup(cache, r->cache->key);
+
+ if (fcn) {
+ ngx_queue_remove(&fcn->queue);
+
+ if (fcn->error) {
+
+ if (fcn->valid_sec < ngx_time()) {
+ goto renew;
+ }
+
+ rc = NGX_OK;
+
+ goto done;
+ }
+
+ fcn->uses++;
+ fcn->count++;
+
+ if (fcn->exists) {
+
+ r->cache->exists = fcn->exists;
+ r->cache->body_start = fcn->body_start;
+
+ rc = NGX_OK;
+
+ goto done;
+ }
+
+ if (fcn->uses >= r->cache->min_uses) {
+
+ r->cache->exists = fcn->exists;
+
+ if (fcn->body_start) {
+ r->cache->body_start = fcn->body_start;
+ }
+
+ rc = NGX_OK;
+
+ } else {
+ rc = NGX_AGAIN;
+ }
+
+ goto done;
+ }
+
+ fcn = ngx_slab_alloc_locked(cache->shpool,
+ sizeof(ngx_http_file_cache_node_t));
+ if (fcn == NULL) {
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ (void) ngx_http_file_cache_expire(cache, 1);
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ fcn = ngx_slab_alloc_locked(cache->shpool,
+ sizeof(ngx_http_file_cache_node_t));
+ if (fcn == NULL) {
+ rc = NGX_ERROR;
+ goto failed;
+ }
+ }
+
+ ngx_memcpy((u_char *) &fcn->node.key, r->cache->key,
+ sizeof(ngx_rbtree_key_t));
+
+ ngx_memcpy(fcn->key, &r->cache->key[sizeof(ngx_rbtree_key_t)],
+ NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
+
+ ngx_rbtree_insert(cache->rbtree, &fcn->node);
+
+renew:
+
+ rc = NGX_DECLINED;
+
+ fcn->uses = 1;
+ fcn->count = 1;
+ fcn->valid_msec = 0;
+ fcn->error = 0;
+ fcn->exists = 0;
+ fcn->valid_sec = 0;
+ fcn->uniq = 0;
+ fcn->body_start = 0;
+
+done:
+
+ fcn->expire = ngx_time() + cache->inactive;
+
+ ngx_queue_insert_head(cache->queue, &fcn->queue);
+
+ r->cache->uniq = fcn->uniq;
+ r->cache->uses = fcn->uses;
+ r->cache->error = fcn->error;
+ r->cache->node = fcn;
+
+failed:
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ return rc;
+}
+
+
+static ngx_http_file_cache_node_t *
+ngx_http_file_cache_lookup(ngx_http_file_cache_t *cache, u_char *key)
+{
+ ngx_int_t rc;
+ ngx_rbtree_key_t node_key;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_http_file_cache_node_t *fcn;
+
+ ngx_memcpy((u_char *) &node_key, key, sizeof(ngx_rbtree_key_t));
+
+ node = cache->rbtree->root;
+ sentinel = cache->rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ if (node_key < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (node_key > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* node_key == node->key */
+
+ do {
+ fcn = (ngx_http_file_cache_node_t *) node;
+
+ rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key,
+ NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
+
+ if (rc == 0) {
+ return fcn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+
+ } while (node != sentinel && node_key == node->key);
+
+ break;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+
+static void
+ngx_http_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_http_file_cache_node_t *cn, *cnt;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ cn = (ngx_http_file_cache_node_t *) node;
+ cnt = (ngx_http_file_cache_node_t *) temp;
+
+ p = (ngx_memcmp(cn->key, cnt->key,
+ NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t))
+ < 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);
+}
+
+
+void
+ngx_http_file_cache_set_header(ngx_http_request_t *r, u_char *buf)
+{
+ ngx_http_file_cache_header_t *h = (ngx_http_file_cache_header_t *) buf;
+
+ u_char *p;
+ ngx_str_t *key;
+ ngx_uint_t i;
+ ngx_http_cache_t *c;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache set header");
+
+ c = r->cache;
+
+ h->valid_sec = c->valid_sec;
+ h->last_modified = c->last_modified;
+ h->date = c->date;
+ h->crc32 = c->crc32;
+ h->valid_msec = (u_short) c->valid_msec;
+ h->header_start = (u_short) c->header_start;
+ h->body_start = (u_short) c->body_start;
+
+ p = buf + sizeof(ngx_http_file_cache_header_t);
+
+ p = ngx_cpymem(p, ngx_http_file_cache_key, sizeof(ngx_http_file_cache_key));
+
+ key = c->keys.elts;
+ for (i = 0; i < c->keys.nelts; i++) {
+ p = ngx_copy(p, key[i].data, key[i].len);
+ }
+
+ *p = LF;
+}
+
+
+void
+ngx_http_file_cache_update(ngx_http_request_t *r, ngx_temp_file_t *tf)
+{
+ ngx_int_t rc;
+ ngx_file_uniq_t uniq;
+ ngx_file_info_t fi;
+ ngx_http_cache_t *c;
+ ngx_ext_rename_file_t ext;
+ ngx_http_file_cache_t *cache;
+
+ c = r->cache;
+
+ if (c->updated) {
+ return;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache update");
+
+ c->updated = 1;
+
+ cache = c->file_cache;
+
+ uniq = 0;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache rename: \"%s\" to \"%s\"",
+ tf->file.name.data, c->file.name.data);
+
+ ext.access = NGX_FILE_OWNER_ACCESS;
+ ext.path_access = NGX_FILE_OWNER_ACCESS;
+ ext.time = -1;
+ ext.create_path = 1;
+ ext.delete_file = 1;
+ ext.log_rename_error = 1;
+ ext.log = r->connection->log;
+
+ rc = ngx_ext_rename_file(&tf->file.name, &c->file.name, &ext);
+
+ if (rc == NGX_OK) {
+
+ if (ngx_fd_info(tf->file.fd, &fi) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_fd_info_n " \"%s\" failed", tf->file.name.data);
+
+ rc = NGX_ERROR;
+
+ } else {
+ uniq = ngx_file_uniq(&fi);
+ }
+ }
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+ c->node->uniq = uniq;
+ c->node->body_start = c->body_start;
+
+ if (rc == NGX_OK) {
+ c->node->exists = 1;
+ }
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+}
+
+
+ngx_int_t
+ngx_http_cache_send(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t out;
+ ngx_http_cache_t *c;
+
+ c = r->cache;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache send: %s", c->file.name.data);
+
+ /* we need to allocate all before the header would be sent */
+
+ b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+ if (b == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
+ if (b->file == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ b->file_pos = c->body_start;
+ b->file_last = c->length;
+
+ b->in_file = (c->length - c->body_start) ? 1: 0;
+ b->last_buf = (r == r->main) ? 1: 0;
+ b->last_in_chain = 1;
+
+ b->file->fd = c->file.fd;
+ b->file->name = c->file.name;
+ b->file->log = r->connection->log;
+
+ out.buf = b;
+ out.next = NULL;
+
+ return ngx_http_output_filter(r, &out);
+}
+
+
+void
+ngx_http_file_cache_free(ngx_http_request_t *r, ngx_temp_file_t *tf)
+{
+ ngx_http_cache_t *c;
+ ngx_http_file_cache_t *cache;
+
+ c = r->cache;
+
+ if (c->updated) {
+ return;
+ }
+
+ c->updated = 1;
+
+ cache = c->file_cache;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache free");
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+
+ if (c->error) {
+ c->node->valid_sec = c->valid_sec;
+ c->node->valid_msec = c->valid_msec;
+ c->node->error = c->error;
+ }
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ if (c->temp_file) {
+ if (tf && tf->file.fd != NGX_INVALID_FILE) {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http file cache incomplete: \"%s\"",
+ tf->file.name.data);
+
+ if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed",
+ tf->file.name.data);
+ }
+ }
+ }
+}
+
+
+static void
+ngx_http_file_cache_cleanup(void *data)
+{
+ ngx_http_cache_t *c = data;
+
+ ngx_http_file_cache_t *cache;
+
+ if (c->updated) {
+ return;
+ }
+
+ c->updated = 1;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->file.log, 0,
+ "http file cache cleanup");
+
+ if (c->error) {
+ return;
+ }
+
+ cache = c->file_cache;
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ c->node->count--;
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+}
-int ngx_http_cache_update_file(ngx_http_request_t *r, ngx_http_cache_ctx_t *ctx,
- ngx_str_t *temp_file)
+static time_t
+ngx_http_file_cache_expire(ngx_http_file_cache_t *cache, ngx_uint_t forced)
{
- int retry;
- ngx_err_t err;
+ u_char *name, *p;
+ size_t len;
+ time_t now, wait;
+ ngx_uint_t tries;
+ ngx_path_t *path;
+ ngx_queue_t *q;
+ ngx_http_file_cache_node_t *fcn;
+ u_char key[2 * NGX_HTTP_CACHE_KEY_LEN];
- retry = 0;
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+ "http file cache expire");
+
+ path = cache->path;
+ len = path->name.len + 1 + path->len + 2 * NGX_HTTP_CACHE_KEY_LEN;
+
+ now = ngx_time();
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
+
+ tries = 0;
for ( ;; ) {
- if (ngx_rename_file(temp_file->data, ctx->file.name.data) == NGX_OK) {
- return NGX_OK;
+
+ if (ngx_queue_empty(cache->queue)) {
+ wait = cache->inactive;
+ break;
}
- err = ngx_errno;
+ q = ngx_queue_last(cache->queue);
+
+ fcn = ngx_queue_data(q, ngx_http_file_cache_node_t, queue);
+
+ if (!forced) {
+ wait = fcn->expire - now;
-#if (NGX_WIN32)
- if (err == NGX_EEXIST) {
- if (ngx_win32_rename_file(temp_file, &ctx->file.name, r->pool)
- == NGX_ERROR)
- {
- return NGX_ERROR;
+ if (wait > 0) {
+ break;
}
}
-#endif
- if (retry || (err != NGX_ENOENT && err != NGX_ENOTDIR)) {
- ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
- ngx_rename_file_n "(\"%s\", \"%s\") failed",
- temp_file->data, ctx->file.name.data);
+ ngx_log_debug6(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+ "http file cache expire: #%d %d %02xd%02xd%02xd%02xd",
+ fcn->count, fcn->exists,
+ fcn->key[0], fcn->key[1], fcn->key[2], fcn->key[3]);
- return NGX_ERROR;
+ if (fcn->count) {
+
+ if (!forced) {
+
+ p = ngx_hex_dump(key, (u_char *) &fcn->node.key,
+ sizeof(ngx_rbtree_key_t));
+ (void) ngx_hex_dump(p, fcn->key,
+ NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
+
+ /*
+ * abnormally exited workers may leave locked cache entries,
+ * and although it may be safe to remove them completely,
+ * we prefer to remove them from inactive queue and rbtree
+ * only, and to allow other leaks
+ */
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(cache->rbtree, &fcn->node);
+
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "ignore long locked inactive cache entry %*s",
+ NGX_HTTP_CACHE_KEY_LEN, key);
+ }
+
+ if (tries++ < 10) {
+ continue;
+ }
+
+ wait = 1;
+ break;
}
- if (ngx_create_path(&ctx->file, ctx->path) == NGX_ERROR) {
- return NGX_ERROR;
+ forced = 0;
+
+ if (!fcn->exists) {
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(cache->rbtree, &fcn->node);
+
+ ngx_slab_free_locked(cache->shpool, fcn);
+
+ continue;
+ }
+
+ name = ngx_alloc(len + 1, ngx_cycle->log);
+ if (name == NULL) {
+ wait = 60;
+ break;
}
- retry = 1;
+ ngx_memcpy(name, path->name.data, path->name.len);
+
+ p = name + path->name.len + 1 + path->len;
+ p = ngx_hex_dump(p, (u_char *) &fcn->node.key,
+ sizeof(ngx_rbtree_key_t));
+ p = ngx_hex_dump(p, fcn->key,
+ NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t));
+ *p = '\0';
+
+ ngx_queue_remove(q);
+
+ ngx_rbtree_delete(cache->rbtree, &fcn->node);
+
+ ngx_slab_free_locked(cache->shpool, fcn);
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ ngx_create_hashed_filename(path, name, len);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ngx_cycle->log, 0,
+ "http file cache expire: \"%s\"", name);
+
+ if (ngx_delete_file(name) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed", name);
+ }
+
+ ngx_free(name);
+
+ ngx_shmtx_lock(&cache->shpool->mutex);
}
+
+ ngx_shmtx_unlock(&cache->shpool->mutex);
+
+ return wait;
}
-#endif
+time_t
+ngx_http_file_cache_cleaner(void *data)
+{
+ ngx_http_file_cache_t *cache = data;
+
+ time_t now, next;
+ ngx_tree_ctx_t tree;
+
+ now = ngx_time();
+
+ if (now >= cache->next_clean_time) {
+ ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+ "clean unused cache files");
-ngx_int_t ngx_http_cache_cleaner_handler(ngx_gc_t *gc, ngx_str_t *name,
- ngx_dir_t *dir)
+ tree.init_handler = NULL;
+ tree.file_handler = ngx_http_file_cache_clean_file;
+ tree.pre_tree_handler = ngx_http_file_cache_clean_noop;
+ tree.post_tree_handler = ngx_http_file_cache_clean_noop;
+ tree.spec_handler = ngx_http_file_cache_clean_file;
+ tree.data = cache;
+ tree.alloc = 0;
+ tree.log = ngx_cycle->log;
+
+ (void) ngx_walk_tree(&tree, &cache->path->name);
+
+ ngx_time_update(0, 0);
+
+ next = ngx_next_time(cache->clean_time);
+
+ if (next == -1) {
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
+ ngx_next_time_n " failed");
+ return 60;
+ }
+
+ cache->next_clean_time = next;
+ }
+
+ next = ngx_http_file_cache_expire(cache, 0);
+
+ now = ngx_time();
+
+ return (now + next < cache->next_clean_time) ? next:
+ cache->next_clean_time - now;
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_clean_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+{
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_file_cache_clean_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
{
- int rc;
- ngx_buf_t buf;
- ngx_http_cache_t c;
- u_char data[sizeof(ngx_http_cache_header_t)];
+ u_char *p, key[2 * NGX_HTTP_CACHE_KEY_LEN];
+ ngx_int_t n;
+ ngx_uint_t i;
+ ngx_http_file_cache_t *cache;
+ ngx_http_file_cache_node_t *node;
+
+ if (path->len < 2 * NGX_HTTP_CACHE_KEY_LEN) {
+ goto clean;
+ }
+
+ p = &path->data[path->len - 2 * NGX_HTTP_CACHE_KEY_LEN];
+
+ for (i = 0; i < NGX_HTTP_CACHE_KEY_LEN; i++) {
+ n = ngx_hextoi(p, 2);
- ngx_memzero(&c, sizeof(ngx_http_cache_t));
+ if (n == NGX_ERROR) {
+ goto clean;
+ }
+
+ p += 2;
- c.file.fd = NGX_INVALID_FILE;
- c.file.name = *name;
- c.file.log = gc->log;
+ key[i] = (u_char) n;
+ }
- c.header_size = sizeof(ngx_http_cache_header_t);
- c.buf = &buf;
- c.log = gc->log;
- c.key_len = 0;
+ cache = ctx->data;
- buf.memory = 1;
- buf.temporary = 1;
- buf.pos = data;
- buf.last = data;
- buf.start = data;
- buf.end = data + sizeof(ngx_http_cache_header_t);
+ ngx_shmtx_lock(&cache->shpool->mutex);
- rc = ngx_http_file_cache_open(&c);
+ node = ngx_http_file_cache_lookup(cache, key);
- /* TODO: NGX_AGAIN */
+ ngx_shmtx_unlock(&cache->shpool->mutex);
- if (rc != NGX_ERROR&& rc != NGX_DECLINED && rc != NGX_HTTP_CACHE_STALE) {
+ if (node) {
return NGX_OK;
}
- if (ngx_delete_file(name->data) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_CRIT, c.log, ngx_errno,
- ngx_delete_file_n " \"%s\" failed", name->data);
+clean:
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
+ "http file cache clean: \"%s\"", path->data);
+
+ if (ngx_delete_file(path->data) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed", path->data);
return NGX_ERROR;
}
- gc->deleted++;
- gc->freed += ngx_de_size(dir);
-
return NGX_OK;
}
+
+
+time_t
+ngx_http_file_cache_valid(ngx_array_t *cache_valid, ngx_uint_t status)
+{
+ ngx_uint_t i;
+ ngx_http_cache_valid_t *valid;
+
+ valid = cache_valid->elts;
+ for (i = 0; i < cache_valid->nelts; i++) {
+
+ if (valid[i].status == 0) {
+ return valid[i].valid;
+ }
+
+ if (valid[i].status == status) {
+ return valid[i].valid;
+ }
+ }
+
+ return 0;
+}
+
+
+char *
+ngx_http_file_cache_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ u_char *last, *p;
+ time_t inactive, clean_time, next;
+ ssize_t size;
+ ngx_str_t s, name, *value;
+ ngx_uint_t i, n;
+ ngx_http_file_cache_t *cache;
+
+ cache = ngx_pcalloc(cf->pool, sizeof(ngx_http_file_cache_t));
+ if (cache == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ cache->path = ngx_pcalloc(cf->pool, sizeof(ngx_path_t));
+ if (cache->path == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ inactive = 600;
+ clean_time = 5 * 60 * 60;
+
+ name.len = 0;
+ size = 0;
+
+ value = cf->args->elts;
+
+ cache->path->name = value[1];
+
+ if (cache->path->name.data[cache->path->name.len - 1] == '/') {
+ cache->path->name.len--;
+ }
+
+ if (ngx_conf_full_name(cf->cycle, &cache->path->name, 0) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ for (i = 2; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "levels=", 7) == 0) {
+
+ n = 0;
+ p = value[i].data + 7;
+ last = value[i].data + value[i].len;
+
+ while (p < last) {
+
+ if (*p > '0' && *p < '6') {
+
+ cache->path->level[n] = *p++ - '0';
+ cache->path->len += cache->path->level[n] + 1;
+
+ if (p == last) {
+ break;
+ }
+
+ if (*p++ == ':') {
+
+ if (n > 2) {
+ goto invalid_levels;
+ }
+
+ if (cache->path->level[n] == 0) {
+ goto invalid_levels;
+ }
+
+ n++;
+
+ continue;
+ }
+ }
+
+ goto invalid_levels;
+ }
+
+ if (cache->path->len < 10 + 3) {
+ continue;
+ }
+
+ invalid_levels:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid \"levels\" \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (ngx_strncmp(value[i].data, "keys_zone=", 10) == 0) {
+
+ name.data = value[i].data + 10;
+
+ p = (u_char *) ngx_strchr(name.data, ':');
+
+ if (p) {
+ name.len = p - name.data;
+
+ p++;
+
+ s.len = value[i].data + value[i].len - p;
+ s.data = p;
+
+ size = ngx_parse_size(&s);
+ if (size > 8191) {
+ continue;
+ }
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid keys zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ 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) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid inactive value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "clean_time=", 11) == 0) {
+
+ s.len = value[i].len - 11;
+ s.data = value[i].data + 11;
+
+ clean_time = ngx_parse_time(&s, 1);
+ if (clean_time < 0 || clean_time > 24 * 60 * 60) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid clean_time value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (name.len == 0 || size == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"keys_zone\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ cache->path->cleaner = ngx_http_file_cache_cleaner;
+ cache->path->data = cache;
+
+ if (ngx_add_path(cf, &cache->path) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ cache->shm_zone = ngx_shared_memory_add(cf, &name, size, cmd->post);
+ if (cache->shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (cache->shm_zone->data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate zone \"%V\"", &name);
+ return NGX_CONF_ERROR;
+ }
+
+ next = ngx_next_time(clean_time);
+
+ if (next == -1) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
+ ngx_next_time_n " failed");
+ return NGX_CONF_ERROR;
+ }
+
+ cache->shm_zone->init = ngx_http_file_cache_init;
+ cache->shm_zone->data = cache;
+
+ cache->inactive = inactive;
+ cache->clean_time = clean_time;
+ cache->next_clean_time = next;
+
+ return NGX_CONF_OK;
+}
+
+
+char *
+ngx_http_file_cache_valid_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf)
+{
+ char *p = conf;
+
+ time_t valid;
+ ngx_str_t *value;
+ ngx_uint_t i, n, status;
+ ngx_array_t **a;
+ ngx_http_cache_valid_t *v;
+ static ngx_uint_t statuses[] = { 200, 301, 302 };
+
+ a = (ngx_array_t **) (p + cmd->offset);
+
+ if (*a == NGX_CONF_UNSET_PTR) {
+ *a = ngx_array_create(cf->pool, 1, sizeof(ngx_http_cache_valid_t));
+ if (*a == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ value = cf->args->elts;
+ n = cf->args->nelts - 1;
+
+ valid = ngx_parse_time(&value[n], 1);
+ if (valid < 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid time value \"%V\"", &value[n]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (n == 1) {
+
+ for (i = 0; i < 3; i++) {
+ v = ngx_array_push(*a);
+ if (v == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ v->status = statuses[i];
+ v->valid = valid;
+ }
+
+ return NGX_CONF_OK;
+ }
+
+ for (i = 1; i < n; i++) {
+
+ if (ngx_strcmp(value[i].data, "any") == 0) {
+
+ status = 0;
+
+ } else {
+
+ status = ngx_atoi(value[i].data, value[i].len);
+ if (status < 100) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid status \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ v = ngx_array_push(*a);
+ if (v == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ v->status = status;
+ v->valid = valid;
+ }
+
+ return NGX_CONF_OK;
+}
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 403a4fccc..ee8766958 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -348,7 +348,9 @@ struct ngx_http_request_s {
ngx_http_event_handler_pt read_event_handler;
ngx_http_event_handler_pt write_event_handler;
+#if (NGX_HTTP_CACHE)
ngx_http_cache_t *cache;
+#endif
ngx_http_upstream_t *upstream;
ngx_array_t *upstream_states;
@@ -443,6 +445,9 @@ struct ngx_http_request_s {
unsigned subrequest_in_memory:1;
unsigned waited:1;
+#if (NGX_HTTP_CACHE)
+ unsigned cached:1;
+#endif
unsigned gzip:2;
unsigned proxy:1;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 5458a5816..1ff6ae4f6 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -9,6 +9,13 @@
#include <ngx_http.h>
+#if (NGX_HTTP_CACHE)
+static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
+static ngx_int_t ngx_http_upstream_cache_send(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
+#endif
+
static void ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx);
static void ngx_http_upstream_rd_check_broken_connection(ngx_http_request_t *r);
static void ngx_http_upstream_wr_check_broken_connection(ngx_http_request_t *r);
@@ -29,6 +36,8 @@ static ngx_int_t ngx_http_upstream_test_next(ngx_http_request_t *r,
static ngx_int_t ngx_http_upstream_intercept_errors(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static ngx_int_t ngx_http_upstream_test_connect(ngx_connection_t *c);
+static ngx_int_t ngx_http_upstream_process_headers(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
static void ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u);
static void ngx_http_upstream_send_response(ngx_http_request_t *r,
@@ -80,10 +89,15 @@ static ngx_int_t ngx_http_upstream_copy_content_type(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_copy_content_length(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_copy_last_modified(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_location(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
+static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset);
+
#if (NGX_HTTP_GZIP)
static ngx_int_t ngx_http_upstream_copy_content_encoding(ngx_http_request_t *r,
ngx_table_elt_t *h, ngx_uint_t offset);
@@ -139,8 +153,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
{ ngx_string("Last-Modified"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, last_modified),
- ngx_http_upstream_copy_header_line,
- offsetof(ngx_http_headers_out_t, last_modified), 0 },
+ ngx_http_upstream_copy_last_modified, 0, 0 },
{ ngx_string("Server"),
ngx_http_upstream_process_header_line,
@@ -185,7 +198,7 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
{ ngx_string("Accept-Ranges"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, accept_ranges),
- ngx_http_upstream_copy_header_line,
+ ngx_http_upstream_copy_allow_ranges,
offsetof(ngx_http_headers_out_t, accept_ranges), 1 },
{ ngx_string("Connection"),
@@ -360,6 +373,25 @@ ngx_http_upstream_init(ngx_http_request_t *r)
u->request_bufs = r->request_body->bufs;
}
+#if (NGX_HTTP_CACHE)
+
+ if (u->conf->cache) {
+ ngx_int_t rc;
+
+ rc = ngx_http_upstream_cache(r, u);
+
+ if (rc == NGX_DONE) {
+ return;
+ }
+
+ if (rc != NGX_DECLINED) {
+ ngx_http_finalize_request(r, rc);
+ return;
+ }
+ }
+
+#endif
+
if (u->create_request(r) != NGX_OK) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
@@ -491,6 +523,136 @@ found:
}
+#if (NGX_HTTP_CACHE)
+
+static ngx_int_t
+ngx_http_upstream_cache(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ ngx_int_t rc;
+ ngx_http_cache_t *c;
+
+ c = ngx_pcalloc(r->pool, sizeof(ngx_http_cache_t));
+ if (c == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_array_init(&c->keys, r->pool, 4, sizeof(ngx_str_t)) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ r->cache = c;
+ c->file.log = r->connection->log;
+
+ if (u->create_key(r) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ /* TODO: add keys */
+
+ ngx_http_file_cache_create_key(r);
+
+ u->cacheable = 1;
+
+ c->min_uses = r->upstream->conf->cache_min_uses;
+ c->body_start = r->upstream->conf->buffer_size;
+ c->file_cache = u->conf->cache->data;
+
+ rc = ngx_http_file_cache_open(r);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http upstream cache: %i u:%ui", rc, c->uses);
+
+ if (rc == NGX_OK) {
+
+ rc = ngx_http_upstream_cache_send(r, u);
+
+ if (rc != NGX_HTTP_UPSTREAM_INVALID_HEADER) {
+ return rc;
+ }
+
+ } else if (rc == NGX_ERROR) {
+
+ return NGX_ERROR;
+
+ } else if (rc == NGX_HTTP_CACHE_STALE) {
+
+ u->stale_cache = 1;
+ u->buffer.start = NULL;
+
+ } else if (rc == NGX_DECLINED) {
+
+ if ((size_t) (u->buffer.end - u->buffer.start) < u->conf->buffer_size) {
+ u->buffer.start = NULL;
+
+ } else {
+ u->buffer.pos = u->buffer.start + c->header_start;
+ u->buffer.last = u->buffer.pos;
+ }
+
+ } else if (rc == NGX_AGAIN) {
+
+ u->cacheable = 0;
+
+ } else {
+
+ /* cached NGX_HTTP_BAD_GATEWAY, NGX_HTTP_GATEWAY_TIME_OUT, etc. */
+
+ return rc;
+ }
+
+ r->cached = 0;
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_http_upstream_cache_send(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ ngx_int_t rc;
+ ngx_http_cache_t *c;
+
+ c = r->cache;
+
+ /* TODO: cache stack */
+
+ u->buffer = *c->buf;
+ u->buffer.pos += c->header_start;
+
+ ngx_memzero(&u->headers_in, sizeof(ngx_http_upstream_headers_in_t));
+
+ if (ngx_list_init(&u->headers_in.headers, r->pool, 8,
+ sizeof(ngx_table_elt_t))
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ rc = u->process_header(r);
+
+ if (rc == NGX_OK) {
+
+ if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
+ return NGX_DONE;
+ }
+
+ return ngx_http_cache_send(r);
+ }
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ /* rc == NGX_HTTP_UPSTREAM_INVALID_HEADER */
+
+ /* TODO: delete file */
+
+ return rc;
+}
+
+#endif
+
+
static void
ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)
{
@@ -969,22 +1131,18 @@ ngx_http_upstream_reinit(ngx_http_request_t *r, ngx_http_upstream_t *u)
/* reinit u->buffer */
-#if 0
- if (u->cache) {
- u->buffer.pos = u->buffer.start + u->cache->ctx.header_size;
- u->buffer.last = u->buffer.pos;
+ u->buffer.pos = u->buffer.start;
- } else {
- u->buffer.pos = u->buffer.start;
- u->buffer.last = u->buffer.start;
- }
-#else
+#if (NGX_HTTP_CACHE)
- u->buffer.pos = u->buffer.start;
- u->buffer.last = u->buffer.start;
+ if (r->cache) {
+ u->buffer.pos += r->cache->header_start;
+ }
#endif
+ u->buffer.last = u->buffer.pos;
+
return NGX_OK;
}
@@ -1115,15 +1273,9 @@ ngx_http_upstream_send_request_handler(ngx_http_request_t *r,
static void
ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
{
- ssize_t n;
- ngx_int_t rc;
- ngx_str_t *uri, args;
- ngx_uint_t i, flags;
- ngx_list_part_t *part;
- ngx_table_elt_t *h;
- ngx_connection_t *c;
- ngx_http_upstream_header_t *hh;
- ngx_http_upstream_main_conf_t *umcf;
+ ssize_t n;
+ ngx_int_t rc;
+ ngx_connection_t *c;
c = u->peer.connection;
@@ -1166,9 +1318,10 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
return;
}
-#if 0
- if (u->cache) {
- u->buffer.pos += u->cache->ctx.header_size;
+#if (NGX_HTTP_CACHE)
+
+ if (r->cache) {
+ u->buffer.pos += r->cache->header_start;
u->buffer.last = u->buffer.pos;
}
#endif
@@ -1257,124 +1410,10 @@ ngx_http_upstream_process_header(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
}
- umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
-
- if (u->headers_in.x_accel_redirect) {
-
- ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
-
- part = &u->headers_in.headers.part;
- h = part->elts;
-
- for (i = 0; /* void */; i++) {
-
- if (i >= part->nelts) {
- if (part->next == NULL) {
- break;
- }
-
- part = part->next;
- h = part->elts;
- i = 0;
- }
-
- hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
- h[i].lowcase_key, h[i].key.len);
-
- if (hh && hh->redirect) {
- if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
- ngx_http_finalize_request(r,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
- }
- }
- }
-
- uri = &u->headers_in.x_accel_redirect->value;
- args.len = 0;
- args.data = NULL;
- flags = 0;
-
- if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
- ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
- return;
- }
-
- if (flags & NGX_HTTP_ZERO_IN_URI) {
- r->zero_in_uri = 1;
- }
-
- if (r->method != NGX_HTTP_HEAD) {
- r->method = NGX_HTTP_GET;
- }
-
- r->valid_unparsed_uri = 0;
-
- ngx_http_internal_redirect(r, uri, &args);
+ if (ngx_http_upstream_process_headers(r, u) != NGX_OK) {
return;
}
- part = &u->headers_in.headers.part;
- h = part->elts;
-
- for (i = 0; /* void */; i++) {
-
- if (i >= part->nelts) {
- if (part->next == NULL) {
- break;
- }
-
- part = part->next;
- h = part->elts;
- i = 0;
- }
-
- if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
- h[i].lowcase_key, h[i].key.len))
- {
- continue;
- }
-
- hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
- h[i].lowcase_key, h[i].key.len);
-
- if (hh) {
- if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
- }
-
- continue;
- }
-
- if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
- ngx_http_upstream_finalize_request(r, u,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
- }
- }
-
- if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
- r->headers_out.server->hash = 0;
- }
-
- if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
- r->headers_out.date->hash = 0;
- }
-
- r->headers_out.status = u->headers_in.status_n;
- r->headers_out.status_line = u->headers_in.status_line;
-
- u->headers_in.content_length_n = r->headers_out.content_length_n;
-
- if (r->headers_out.content_length_n != -1) {
- u->length = (size_t) r->headers_out.content_length_n;
-
- } else {
- u->length = NGX_MAX_SIZE_T_VALUE;
- }
-
if (!r->subrequest_in_memory) {
ngx_http_upstream_send_response(r, u);
return;
@@ -1443,9 +1482,12 @@ ngx_http_upstream_test_next(ngx_http_request_t *r, ngx_http_upstream_t *u)
#if (NGX_HTTP_CACHE)
- if (u->peer.tries == 0 && u->stale && (u->conf->use_stale & un->mask)) {
+ if (u->peer.tries == 0
+ && u->stale_cache
+ && (u->conf->cache_use_stale & un->mask))
+ {
ngx_http_upstream_finalize_request(r, u,
- ngx_http_send_cached_response(r));
+ ngx_http_upstream_cache_send(r, u));
return NGX_OK;
}
@@ -1557,6 +1599,138 @@ ngx_http_upstream_test_connect(ngx_connection_t *c)
}
+static ngx_int_t
+ngx_http_upstream_process_headers(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ ngx_str_t *uri, args;
+ ngx_uint_t i, flags;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *h;
+ ngx_http_upstream_header_t *hh;
+ ngx_http_upstream_main_conf_t *umcf;
+
+ umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module);
+
+ if (u->headers_in.x_accel_redirect) {
+
+ ngx_http_upstream_finalize_request(r, u, NGX_DECLINED);
+
+ part = &u->headers_in.headers.part;
+ h = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ h = part->elts;
+ i = 0;
+ }
+
+ hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
+ h[i].lowcase_key, h[i].key.len);
+
+ if (hh && hh->redirect) {
+ if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
+ ngx_http_finalize_request(r,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_DONE;
+ }
+ }
+ }
+
+ uri = &u->headers_in.x_accel_redirect->value;
+ args.len = 0;
+ args.data = NULL;
+ flags = 0;
+
+ if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
+ return NGX_DONE;
+ }
+
+ if (flags & NGX_HTTP_ZERO_IN_URI) {
+ r->zero_in_uri = 1;
+ }
+
+ if (r->method != NGX_HTTP_HEAD) {
+ r->method = NGX_HTTP_GET;
+ }
+
+ r->valid_unparsed_uri = 0;
+
+ ngx_http_internal_redirect(r, uri, &args);
+ return NGX_DONE;
+ }
+
+ part = &u->headers_in.headers.part;
+ h = part->elts;
+
+ for (i = 0; /* void */; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ h = part->elts;
+ i = 0;
+ }
+
+ if (ngx_hash_find(&u->conf->hide_headers_hash, h[i].hash,
+ h[i].lowcase_key, h[i].key.len))
+ {
+ continue;
+ }
+
+ hh = ngx_hash_find(&umcf->headers_in_hash, h[i].hash,
+ h[i].lowcase_key, h[i].key.len);
+
+ if (hh) {
+ if (hh->copy_handler(r, &h[i], hh->conf) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_DONE;
+ }
+
+ continue;
+ }
+
+ if (ngx_http_upstream_copy_header_line(r, &h[i], 0) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_DONE;
+ }
+ }
+
+ if (r->headers_out.server && r->headers_out.server->value.data == NULL) {
+ r->headers_out.server->hash = 0;
+ }
+
+ if (r->headers_out.date && r->headers_out.date->value.data == NULL) {
+ r->headers_out.date->hash = 0;
+ }
+
+ r->headers_out.status = u->headers_in.status_n;
+ r->headers_out.status_line = u->headers_in.status_line;
+
+ u->headers_in.content_length_n = r->headers_out.content_length_n;
+
+ if (r->headers_out.content_length_n != -1) {
+ u->length = (size_t) r->headers_out.content_length_n;
+
+ } else {
+ u->length = NGX_MAX_SIZE_T_VALUE;
+ }
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_upstream_process_body_in_memory(ngx_http_request_t *r,
ngx_http_upstream_t *u)
@@ -1637,8 +1811,6 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_int_t rc;
ngx_event_pipe_t *p;
ngx_connection_t *c;
- ngx_pool_cleanup_t *cl;
- ngx_pool_cleanup_file_t *clf;
ngx_http_core_loc_conf_t *clcf;
rc = ngx_http_send_header(r);
@@ -1651,18 +1823,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
u->header_sent = 1;
if (r->request_body && r->request_body->temp_file) {
- for (cl = r->pool->cleanup; cl; cl = cl->next) {
- if (cl->handler == ngx_pool_cleanup_file) {
- clf = cl->data;
-
- if (clf->fd == r->request_body->temp_file->file.fd) {
- cl->handler(clf);
- cl->handler = NULL;
- r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
- break;
- }
- }
- }
+ ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
+ r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
}
c = r->connection;
@@ -1738,28 +1900,38 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
/* TODO: preallocate event_pipe bufs, look "Content-Length" */
-#if 0
+#if (NGX_HTTP_CACHE)
- if (u->cache && u->cache->ctx.file.fd != NGX_INVALID_FILE) {
- if (ngx_close_file(u->cache->ctx.file.fd) == NGX_FILE_ERROR) {
- ngx_log_error(NGX_LOG_ALERT, c->log, ngx_errno,
- ngx_close_file_n " \"%s\" failed",
- u->cache->ctx.file.name.data);
- }
+ if (r->cache && r->cache->file.fd != NGX_INVALID_FILE) {
+ ngx_pool_run_cleanup_file(r->pool, r->cache->file.fd);
+ r->cache->file.fd = NGX_INVALID_FILE;
}
if (u->cacheable) {
- header = (ngx_http_cache_header_t *) u->buffer->start;
+ time_t now, valid;
+
+ valid = ngx_http_file_cache_valid(u->conf->cache_valid,
+ u->headers_in.status_n);
+ if (valid) {
+
+ now = ngx_time();
+
+ r->cache->valid_sec = now + valid;
+
+ r->cache->last_modified = r->headers_out.last_modified_time;
+ r->cache->date = now;
+ r->cache->body_start = (u_short) (u->buffer.pos - u->buffer.start);
+
+ if (r->headers_out.content_length_n != -1) {
+ r->cache->length = r->cache->body_start
+ + r->headers_out.content_length_n;
+ }
- header->expires = u->cache->ctx.expires;
- header->last_modified = u->cache->ctx.last_modified;
- header->date = u->cache->ctx.date;
- header->length = r->headers_out.content_length_n;
- u->cache->ctx.length = r->headers_out.content_length_n;
+ ngx_http_file_cache_set_header(r, u->buffer.start);
- header->key_len = u->cache->ctx.key0.len;
- ngx_memcpy(&header->key, u->cache->ctx.key0.data, header->key_len);
- header->key[header->key_len] = LF;
+ } else {
+ u->cacheable = 0;
+ }
}
#endif
@@ -1789,7 +1961,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->temp_file->path = u->conf->temp_path;
p->temp_file->pool = r->pool;
- if (u->cacheable || u->store) {
+ if (p->cacheable) {
p->temp_file->persistent = 1;
} else {
@@ -2241,23 +2413,21 @@ ngx_http_upstream_process_request(ngx_http_request_t *r)
}
}
-#if (NGX_HTTP_FILE_CACHE)
+#if (NGX_HTTP_CACHE)
- if (p->upstream_done && u->cacheable) {
- if (ngx_http_cache_update(r) == NGX_ERROR) {
- ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
- ngx_http_upstream_finalize_request(r, u, 0);
- return;
- }
+ if (u->cacheable) {
- } else if (p->upstream_eof && u->cacheable) {
+ if (p->upstream_done) {
+ ngx_http_file_cache_update(r, u->pipe->temp_file);
- /* TODO: check length & update cache */
+ } else if (p->upstream_eof) {
- if (ngx_http_cache_update(r) == NGX_ERROR) {
- ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock);
- ngx_http_upstream_finalize_request(r, u, 0);
- return;
+ /* TODO: check length & update cache */
+
+ ngx_http_file_cache_update(r, u->pipe->temp_file);
+
+ } else if (p->upstream_error) {
+ ngx_http_file_cache_free(r, u->pipe->temp_file);
}
}
@@ -2438,12 +2608,12 @@ ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u,
#if (NGX_HTTP_CACHE)
- if (u->stale && (u->conf->use_stale & ft_type)) {
+ if (u->stale_cache && (u->conf->cache_use_stale & ft_type)) {
+
ngx_http_upstream_finalize_request(r, u,
- ngx_http_send_cached_response(r));
+ ngx_http_upstream_cache_send(r, u));
return;
}
-
#endif
ngx_http_upstream_finalize_request(r, u, status);
@@ -2557,25 +2727,41 @@ ngx_http_upstream_finalize_request(ngx_http_request_t *r,
u->peer.connection = NULL;
- if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
- {
- rc = 0;
- }
-
if (u->pipe && u->pipe->temp_file) {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream temp fd: %d",
u->pipe->temp_file->file.fd);
}
-#if 0
- if (u->cache) {
+#if (NGX_HTTP_CACHE)
+
+ if (r->cache) {
+ time_t valid;
+
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http upstream cache fd: %d",
- u->cache->ctx.file.fd);
+ r->cache->file.fd);
+
+ if (rc == NGX_HTTP_BAD_GATEWAY || rc == NGX_HTTP_GATEWAY_TIME_OUT) {
+
+ valid = ngx_http_file_cache_valid(u->conf->cache_valid, rc);
+
+ if (valid) {
+ r->cache->valid_sec = ngx_time() + valid;
+ r->cache->error = rc;
+ }
+ }
+
+ ngx_http_file_cache_free(r, u->pipe->temp_file);
}
+
#endif
+ if (u->header_sent && (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE))
+ {
+ rc = 0;
+ }
+
if (rc == NGX_DECLINED) {
return;
}
@@ -2827,6 +3013,33 @@ ngx_http_upstream_copy_content_length(ngx_http_request_t *r, ngx_table_elt_t *h,
static ngx_int_t
+ngx_http_upstream_copy_last_modified(ngx_http_request_t *r, ngx_table_elt_t *h,
+ ngx_uint_t offset)
+{
+ ngx_table_elt_t *ho;
+
+ ho = ngx_list_push(&r->headers_out.headers);
+ if (ho == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ho = *h;
+
+#if (NGX_HTTP_CACHE)
+
+ if (r->cached) {
+ r->headers_out.last_modified = ho;
+ r->headers_out.last_modified_time = ngx_http_parse_time(h->value.data,
+ h->value.len);
+ }
+
+#endif
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_upstream_rewrite_location(ngx_http_request_t *r, ngx_table_elt_t *h,
ngx_uint_t offset)
{
@@ -2916,6 +3129,33 @@ ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h,
}
+static ngx_int_t
+ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r,
+ ngx_table_elt_t *h, ngx_uint_t offset)
+{
+ ngx_table_elt_t *ho;
+
+#if (NGX_HTTP_CACHE)
+
+ if (r->cached) {
+ r->allow_ranges = 1;
+ return NGX_OK;
+
+ }
+
+#endif
+
+ ho = ngx_list_push(&r->headers_out.headers);
+ if (ho == NULL) {
+ return NGX_ERROR;
+ }
+
+ *ho = *h;
+
+ return NGX_OK;
+}
+
+
#if (NGX_HTTP_GZIP)
static ngx_int_t
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index 3c141276d..8f30b6e31 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -39,21 +39,21 @@
typedef struct {
- ngx_msec_t bl_time;
- ngx_uint_t bl_state;
+ ngx_msec_t bl_time;
+ ngx_uint_t bl_state;
- ngx_uint_t status;
- time_t response_sec;
- ngx_uint_t response_msec;
+ ngx_uint_t status;
+ time_t response_sec;
+ ngx_uint_t response_msec;
off_t response_length;
- ngx_str_t *peer;
+ ngx_str_t *peer;
} ngx_http_upstream_state_t;
typedef struct {
- ngx_hash_t headers_in_hash;
- ngx_array_t upstreams;
+ ngx_hash_t headers_in_hash;
+ ngx_array_t upstreams;
/* ngx_http_upstream_srv_conf_t */
} ngx_http_upstream_main_conf_t;
@@ -66,21 +66,21 @@ typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r,
typedef struct {
- ngx_http_upstream_init_pt init_upstream;
- ngx_http_upstream_init_peer_pt init;
- void *data;
+ ngx_http_upstream_init_pt init_upstream;
+ ngx_http_upstream_init_peer_pt init;
+ void *data;
} ngx_http_upstream_peer_t;
typedef struct {
- ngx_peer_addr_t *addrs;
- ngx_uint_t naddrs;
- ngx_uint_t weight;
- ngx_uint_t max_fails;
- time_t fail_timeout;
-
- unsigned down:1;
- unsigned backup:1;
+ ngx_peer_addr_t *addrs;
+ ngx_uint_t naddrs;
+ ngx_uint_t weight;
+ ngx_uint_t max_fails;
+ time_t fail_timeout;
+
+ unsigned down:1;
+ unsigned backup:1;
} ngx_http_upstream_server_t;
@@ -93,67 +93,75 @@ typedef struct {
struct ngx_http_upstream_srv_conf_s {
- ngx_http_upstream_peer_t peer;
- void **srv_conf;
+ ngx_http_upstream_peer_t peer;
+ void **srv_conf;
- ngx_array_t *servers; /* ngx_http_upstream_server_t */
+ ngx_array_t *servers; /* ngx_http_upstream_server_t */
- ngx_uint_t flags;
- ngx_str_t host;
- u_char *file_name;
- ngx_uint_t line;
- in_port_t port;
- in_port_t default_port;
+ ngx_uint_t flags;
+ ngx_str_t host;
+ u_char *file_name;
+ ngx_uint_t line;
+ in_port_t port;
+ in_port_t default_port;
};
typedef struct {
- ngx_http_upstream_srv_conf_t *upstream;
+ ngx_http_upstream_srv_conf_t *upstream;
+
+ ngx_msec_t connect_timeout;
+ ngx_msec_t send_timeout;
+ ngx_msec_t read_timeout;
+ ngx_msec_t timeout;
+
+ size_t send_lowat;
+ size_t buffer_size;
- ngx_msec_t connect_timeout;
- ngx_msec_t send_timeout;
- ngx_msec_t read_timeout;
- ngx_msec_t timeout;
+ size_t busy_buffers_size;
+ size_t max_temp_file_size;
+ size_t temp_file_write_size;
- size_t send_lowat;
- size_t buffer_size;
+ size_t busy_buffers_size_conf;
+ size_t max_temp_file_size_conf;
+ size_t temp_file_write_size_conf;
- size_t busy_buffers_size;
- size_t max_temp_file_size;
- size_t temp_file_write_size;
+ ngx_bufs_t bufs;
- size_t busy_buffers_size_conf;
- size_t max_temp_file_size_conf;
- size_t temp_file_write_size_conf;
+ ngx_uint_t next_upstream;
+ ngx_uint_t store_access;
+ ngx_flag_t buffering;
+ ngx_flag_t pass_request_headers;
+ ngx_flag_t pass_request_body;
- ngx_uint_t next_upstream;
- ngx_uint_t store_access;
+ ngx_flag_t ignore_client_abort;
+ ngx_flag_t intercept_errors;
+ ngx_flag_t cyclic_temp_file;
- ngx_bufs_t bufs;
+ ngx_path_t *temp_path;
- ngx_flag_t buffering;
- ngx_flag_t pass_request_headers;
- ngx_flag_t pass_request_body;
+ ngx_hash_t hide_headers_hash;
+ ngx_array_t *hide_headers;
+ ngx_array_t *pass_headers;
- ngx_flag_t ignore_client_abort;
- ngx_flag_t intercept_errors;
- ngx_flag_t cyclic_temp_file;
+#if (NGX_HTTP_CACHE)
+ ngx_shm_zone_t *cache;
- ngx_path_t *temp_path;
+ ngx_uint_t cache_min_uses;
+ ngx_uint_t cache_use_stale;
- ngx_hash_t hide_headers_hash;
- ngx_array_t *hide_headers;
- ngx_array_t *pass_headers;
+ ngx_array_t *cache_valid;
+#endif
- ngx_array_t *store_lengths;
- ngx_array_t *store_values;
+ ngx_array_t *store_lengths;
+ ngx_array_t *store_values;
- signed store:2;
- unsigned intercept_404:1;
- unsigned change_buffering:1;
+ signed store:2;
+ unsigned intercept_404:1;
+ unsigned change_buffering:1;
#if (NGX_HTTP_SSL)
- ngx_ssl_t *ssl;
+ ngx_ssl_t *ssl;
ngx_flag_t ssl_session_reuse;
#endif
@@ -161,62 +169,62 @@ typedef struct {
typedef struct {
- ngx_str_t name;
- ngx_http_header_handler_pt handler;
- ngx_uint_t offset;
- ngx_http_header_handler_pt copy_handler;
- ngx_uint_t conf;
- ngx_uint_t redirect; /* unsigned redirect:1; */
+ ngx_str_t name;
+ ngx_http_header_handler_pt handler;
+ ngx_uint_t offset;
+ ngx_http_header_handler_pt copy_handler;
+ ngx_uint_t conf;
+ ngx_uint_t redirect; /* unsigned redirect:1; */
} ngx_http_upstream_header_t;
typedef struct {
- ngx_list_t headers;
+ ngx_list_t headers;
- ngx_uint_t status_n;
- ngx_str_t status_line;
+ ngx_uint_t status_n;
+ ngx_str_t status_line;
- ngx_table_elt_t *status;
- ngx_table_elt_t *date;
- ngx_table_elt_t *server;
- ngx_table_elt_t *connection;
+ ngx_table_elt_t *status;
+ ngx_table_elt_t *date;
+ ngx_table_elt_t *server;
+ ngx_table_elt_t *connection;
- ngx_table_elt_t *expires;
- ngx_table_elt_t *etag;
- ngx_table_elt_t *x_accel_expires;
- ngx_table_elt_t *x_accel_redirect;
- ngx_table_elt_t *x_accel_limit_rate;
+ ngx_table_elt_t *expires;
+ ngx_table_elt_t *etag;
+ ngx_table_elt_t *x_accel_expires;
+ ngx_table_elt_t *x_accel_redirect;
+ ngx_table_elt_t *x_accel_limit_rate;
- ngx_table_elt_t *content_type;
- ngx_table_elt_t *content_length;
+ ngx_table_elt_t *content_type;
+ ngx_table_elt_t *content_length;
- ngx_table_elt_t *last_modified;
- ngx_table_elt_t *location;
- ngx_table_elt_t *accept_ranges;
- ngx_table_elt_t *www_authenticate;
+ ngx_table_elt_t *last_modified;
+ ngx_table_elt_t *location;
+ ngx_table_elt_t *accept_ranges;
+ ngx_table_elt_t *www_authenticate;
#if (NGX_HTTP_GZIP)
- ngx_table_elt_t *content_encoding;
+ ngx_table_elt_t *content_encoding;
#endif
- off_t content_length_n;
+ off_t content_length_n;
- ngx_array_t cache_control;
+ ngx_array_t cache_control;
} ngx_http_upstream_headers_in_t;
typedef struct {
- ngx_str_t host;
- in_port_t port;
- ngx_uint_t no_port; /* unsigned no_port:1 */
+ ngx_str_t host;
+ in_port_t port;
+ ngx_uint_t no_port; /* unsigned no_port:1 */
- ngx_uint_t naddrs;
- in_addr_t *addrs;
+ ngx_uint_t naddrs;
+ in_addr_t *addrs;
- struct sockaddr *sockaddr;
- socklen_t socklen;
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
- ngx_resolver_ctx_t *ctx;
+ ngx_resolver_ctx_t *ctx;
} ngx_http_upstream_resolved_t;
@@ -225,63 +233,69 @@ typedef void (*ngx_http_upstream_handler_pt)(ngx_http_request_t *r,
struct ngx_http_upstream_s {
- ngx_http_upstream_handler_pt read_event_handler;
- ngx_http_upstream_handler_pt write_event_handler;
-
- ngx_peer_connection_t peer;
-
- ngx_event_pipe_t *pipe;
+ ngx_http_upstream_handler_pt read_event_handler;
+ ngx_http_upstream_handler_pt write_event_handler;
- ngx_chain_t *request_bufs;
+ ngx_peer_connection_t peer;
- ngx_output_chain_ctx_t output;
- ngx_chain_writer_ctx_t writer;
+ ngx_event_pipe_t *pipe;
- ngx_http_upstream_conf_t *conf;
+ ngx_chain_t *request_bufs;
- ngx_http_upstream_headers_in_t headers_in;
+ ngx_output_chain_ctx_t output;
+ ngx_chain_writer_ctx_t writer;
- ngx_http_upstream_resolved_t *resolved;
+ ngx_http_upstream_conf_t *conf;
- ngx_buf_t buffer;
- size_t length;
+ ngx_http_upstream_headers_in_t headers_in;
- ngx_chain_t *out_bufs;
- ngx_chain_t *busy_bufs;
- ngx_chain_t *free_bufs;
+ ngx_http_upstream_resolved_t *resolved;
- ngx_int_t (*input_filter_init)(void *data);
- ngx_int_t (*input_filter)(void *data, ssize_t bytes);
- void *input_filter_ctx;
+ ngx_buf_t buffer;
+ size_t length;
- ngx_int_t (*create_request)(ngx_http_request_t *r);
- ngx_int_t (*reinit_request)(ngx_http_request_t *r);
- ngx_int_t (*process_header)(ngx_http_request_t *r);
- void (*abort_request)(ngx_http_request_t *r);
- void (*finalize_request)(ngx_http_request_t *r,
- ngx_int_t rc);
- ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix);
+ ngx_chain_t *out_bufs;
+ ngx_chain_t *busy_bufs;
+ ngx_chain_t *free_bufs;
- ngx_msec_t timeout;
+ ngx_int_t (*input_filter_init)(void *data);
+ ngx_int_t (*input_filter)(void *data, ssize_t bytes);
+ void *input_filter_ctx;
- ngx_http_upstream_state_t *state;
-
- ngx_str_t method;
- ngx_str_t schema;
- ngx_str_t uri;
-
- ngx_http_cleanup_pt *cleanup;
-
- unsigned store:1;
- unsigned cacheable:1;
- unsigned accel:1;
- unsigned ssl:1;
+#if (NGX_HTTP_CACHE)
+ ngx_int_t (*create_key)(ngx_http_request_t *r);
+#endif
+ ngx_int_t (*create_request)(ngx_http_request_t *r);
+ ngx_int_t (*reinit_request)(ngx_http_request_t *r);
+ ngx_int_t (*process_header)(ngx_http_request_t *r);
+ void (*abort_request)(ngx_http_request_t *r);
+ void (*finalize_request)(ngx_http_request_t *r,
+ ngx_int_t rc);
+ ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r,
+ ngx_table_elt_t *h, size_t prefix);
+
+ ngx_msec_t timeout;
+
+ ngx_http_upstream_state_t *state;
+
+ ngx_str_t method;
+ ngx_str_t schema;
+ ngx_str_t uri;
+
+ ngx_http_cleanup_pt *cleanup;
+
+ unsigned store:1;
+ unsigned cacheable:1;
+ unsigned accel:1;
+ unsigned ssl:1;
+#if (NGX_HTTP_CACHE)
+ unsigned stale_cache:1;
+#endif
- unsigned buffering:1;
+ unsigned buffering:1;
- unsigned request_sent:1;
- unsigned header_sent:1;
+ unsigned request_sent:1;
+ unsigned header_sent:1;
};
diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h
index 068b4d8fd..21e5ff45c 100644
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -67,6 +67,7 @@ typedef struct {
#define NGX_FILE_APPEND O_APPEND
#define NGX_FILE_DEFAULT_ACCESS 0644
+#define NGX_FILE_OWNER_ACCESS 0600
#define ngx_close_file close
diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c
index a14a03c74..354722052 100644
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -12,7 +12,7 @@
static void ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n,
ngx_int_t type);
-static void ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type);
+static void ngx_start_cleaner_process(ngx_cycle_t *cycle, ngx_int_t type);
static void ngx_signal_worker_processes(ngx_cycle_t *cycle, int signo);
static ngx_uint_t ngx_reap_children(ngx_cycle_t *cycle);
static void ngx_master_process_exit(ngx_cycle_t *cycle);
@@ -24,9 +24,8 @@ static void ngx_channel_handler(ngx_event_t *ev);
static void ngx_wakeup_worker_threads(ngx_cycle_t *cycle);
static ngx_thread_value_t ngx_worker_thread_cycle(void *data);
#endif
-#if 0
-static void ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data);
-#endif
+static void ngx_cleaner_process_cycle(ngx_cycle_t *cycle, void *data);
+static void ngx_cleaner_process_handler(ngx_event_t *ev);
ngx_uint_t ngx_process;
@@ -123,7 +122,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
- ngx_start_garbage_collector(cycle, NGX_PROCESS_RESPAWN);
+ ngx_start_cleaner_process(cycle, NGX_PROCESS_RESPAWN);
ngx_new_binary = 0;
delay = 0;
@@ -204,7 +203,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
if (ngx_new_binary) {
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
- ngx_start_garbage_collector(cycle, NGX_PROCESS_RESPAWN);
+ ngx_start_cleaner_process(cycle, NGX_PROCESS_RESPAWN);
ngx_noaccepting = 0;
continue;
@@ -223,7 +222,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_core_module);
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_JUST_RESPAWN);
- ngx_start_garbage_collector(cycle, NGX_PROCESS_JUST_RESPAWN);
+ ngx_start_cleaner_process(cycle, NGX_PROCESS_JUST_RESPAWN);
live = 1;
ngx_signal_worker_processes(cycle,
ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
@@ -233,7 +232,7 @@ ngx_master_process_cycle(ngx_cycle_t *cycle)
ngx_restart = 0;
ngx_start_worker_processes(cycle, ccf->worker_processes,
NGX_PROCESS_RESPAWN);
- ngx_start_garbage_collector(cycle, NGX_PROCESS_RESPAWN);
+ ngx_start_cleaner_process(cycle, NGX_PROCESS_RESPAWN);
live = 1;
}
@@ -361,18 +360,28 @@ ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
static void
-ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type)
+ngx_start_cleaner_process(ngx_cycle_t *cycle, ngx_int_t type)
{
-#if 0
- ngx_int_t i;
- ngx_channel_t ch;
+ ngx_int_t i;
+ ngx_uint_t n;
+ ngx_path_t **path;
+ ngx_channel_t ch;
+
+ path = ngx_cycle->pathes.elts;
+ for (n = 0; n < ngx_cycle->pathes.nelts; n++) {
+ if (path[n]->cleaner) {
+ goto start;
+ }
+ }
- ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start garbage collector");
+ return;
+
+start:
ch.command = NGX_CMD_OPEN_CHANNEL;
- ngx_spawn_process(cycle, ngx_garbage_collector_cycle, NULL,
- "garbage collector", type);
+ ngx_spawn_process(cycle, ngx_cleaner_process_cycle, NULL,
+ "cleaner process", type);
ch.pid = ngx_processes[ngx_process_slot].pid;
ch.slot = ngx_process_slot;
@@ -398,7 +407,6 @@ ngx_start_garbage_collector(ngx_cycle_t *cycle, ngx_int_t type)
ngx_write_channel(ngx_processes[i].channel[0],
&ch, sizeof(ngx_channel_t), cycle->log);
}
-#endif
}
@@ -1254,27 +1262,29 @@ ngx_worker_thread_cycle(void *data)
#endif
-#if 0
-
static void
-ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data)
+ngx_cleaner_process_cycle(ngx_cycle_t *cycle, void *data)
{
- ngx_uint_t i;
- ngx_gc_t ctx;
- ngx_path_t **path;
- ngx_event_t *ev;
+ void *ident[4];
+ ngx_event_t ev;
+
+ cycle->connection_n = 512;
ngx_worker_process_init(cycle, 0);
- ev = &cycle->read_events0[ngx_channel];
+ ngx_close_listening_sockets(cycle);
- ngx_accept_mutex = NULL;
+ ngx_memzero(&ev, sizeof(ngx_event_t));
+ ev.handler = ngx_cleaner_process_handler;
+ ev.data = ident;
+ ev.log = cycle->log;
+ ident[3] = (void *) -1;
- ngx_setproctitle("garbage collector");
+ ngx_use_accept_mutex = 0;
-#if 0
- ngx_add_timer(ev, 60 * 1000);
-#endif
+ ngx_setproctitle("cleaner process");
+
+ ngx_add_timer(&ev, 0);
for ( ;; ) {
@@ -1289,19 +1299,35 @@ ngx_garbage_collector_cycle(ngx_cycle_t *cycle, void *data)
ngx_reopen_files(cycle, -1);
}
- path = cycle->pathes.elts;
- for (i = 0; i < cycle->pathes.nelts; i++) {
- ctx.path = path[i];
- ctx.log = cycle->log;
- ctx.handler = path[i]->cleaner;
+ ngx_process_events_and_timers(cycle);
+ }
+}
- ngx_collect_garbage(&ctx, &path[i]->name, 0);
- }
- ngx_add_timer(ev, 60 * 60 * 1000);
+static void
+ngx_cleaner_process_handler(ngx_event_t *ev)
+{
+ time_t next, n;
+ ngx_uint_t i;
+ ngx_path_t **path;
+
+ next = 60 * 60;
- ngx_process_events_and_timers(cycle);
+ path = ngx_cycle->pathes.elts;
+ for (i = 0; i < ngx_cycle->pathes.nelts; i++) {
+
+ if (path[i]->cleaner) {
+ n = path[i]->cleaner(path[i]->data);
+
+ next = (n <= next) ? n : next;
+
+ ngx_time_update(0, 0);
+ }
}
-}
-#endif
+ if (next == 0) {
+ next = 1;
+ }
+
+ ngx_add_timer(ev, next * 1000);
+}
diff --git a/src/os/win32/ngx_files.h b/src/os/win32/ngx_files.h
index 5855e673f..b8487920f 100644
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -75,6 +75,7 @@ typedef struct {
#define NGX_FILE_APPEND 0
#define NGX_FILE_DEFAULT_ACCESS 0
+#define NGX_FILE_OWNER_ACCESS 0
ngx_int_t ngx_file_append_mode(ngx_fd_t fd);