summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2007-01-09 17:09:00 +0000
committerJonathan Kolb <jon@b0g.us>2007-01-09 17:09:00 +0000
commit426223037017c6000f42bc041342171d1f666c6c (patch)
tree17cf24a9fec18aad176646cde33ea9ecdf44fd9d
parent0b70df4619adb2e1133feadc1063999583aee4b7 (diff)
downloadnginx-0.5.6.tar.gz
Changes with nginx 0.5.6 09 Jan 2007v0.5.6
*) Change: now the ngx_http_index_module ignores all methods except the GET, HEAD, and POST methods. *) Feature: the ngx_http_limit_zone_module. *) Feature: the $binary_remote_addr variable. *) Feature: the "ssl_session_cache" directives of the ngx_http_ssl_module and ngx_imap_ssl_module. *) Feature: the DELETE method supports recursive removal. *) Bugfix: the byte-ranges were transferred incorrectly if the $r->sendfile() was used.
-rw-r--r--CHANGES18
-rw-r--r--CHANGES.ru18
-rw-r--r--LICENSE2
-rw-r--r--auto/modules5
-rw-r--r--auto/options3
-rw-r--r--auto/sources4
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_conf_file.c12
-rw-r--r--src/core/ngx_core.h4
-rw-r--r--src/core/ngx_cycle.c178
-rw-r--r--src/core/ngx_cycle.h13
-rw-r--r--src/core/ngx_file.c165
-rw-r--r--src/core/ngx_file.h19
-rw-r--r--src/core/ngx_rbtree.h5
-rw-r--r--src/core/ngx_slab.c74
-rw-r--r--src/core/ngx_slab.h2
-rw-r--r--src/event/ngx_event_openssl.c480
-rw-r--r--src/event/ngx_event_openssl.h51
-rw-r--r--src/http/modules/ngx_http_dav_module.c63
-rw-r--r--src/http/modules/ngx_http_index_module.c4
-rw-r--r--src/http/modules/ngx_http_limit_zone_module.c444
-rw-r--r--src/http/modules/ngx_http_proxy_module.c2
-rw-r--r--src/http/modules/ngx_http_range_filter_module.c270
-rw-r--r--src/http/modules/ngx_http_realip_module.c12
-rw-r--r--src/http/modules/ngx_http_ssl_module.c176
-rw-r--r--src/http/modules/ngx_http_ssl_module.h26
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/ngx_http_request.c6
-rw-r--r--src/http/ngx_http_request.h14
-rw-r--r--src/http/ngx_http_upstream_round_robin.h2
-rw-r--r--src/http/ngx_http_variables.c25
-rw-r--r--src/imap/ngx_imap_ssl_module.c135
-rw-r--r--src/imap/ngx_imap_ssl_module.h21
-rw-r--r--src/os/unix/ngx_linux_init.c2
34 files changed, 2013 insertions, 246 deletions
diff --git a/CHANGES b/CHANGES
index 4e18def5d..564bbc5f5 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,22 @@
+Changes with nginx 0.5.6 09 Jan 2007
+
+ *) Change: now the ngx_http_index_module ignores all methods except the
+ GET, HEAD, and POST methods.
+
+ *) Feature: the ngx_http_limit_zone_module.
+
+ *) Feature: the $binary_remote_addr variable.
+
+ *) Feature: the "ssl_session_cache" directives of the
+ ngx_http_ssl_module and ngx_imap_ssl_module.
+
+ *) Feature: the DELETE method supports recursive removal.
+
+ *) Bugfix: the byte-ranges were transferred incorrectly if the
+ $r->sendfile() was used.
+
+
Changes with nginx 0.5.5 24 Dec 2006
*) Change: the -v switch does not show compiler information any more.
diff --git a/CHANGES.ru b/CHANGES.ru
index d0d378a5b..18e7b842d 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,22 @@
+Изменения в nginx 0.5.6 09.01.2007
+
+ *) Изменение: теперь модуль ngx_http_index_module игнорирует все
+ методы, кроме GET, HEAD и POST.
+
+ *) Добавление: модуль ngx_http_limit_zone_module.
+
+ *) Добавление: переменная $binary_remote_addr.
+
+ *) Добавление: директивы ssl_session_cache модулей ngx_http_ssl_module
+ и ngx_imap_ssl_module.
+
+ *) Добавление: метод DELETE поддерживает рекурсивное удаление.
+
+ *) Исправление: при использовании $r->sendfile() byte-ranges
+ передавались неверно.
+
+
Изменения в nginx 0.5.5 24.12.2006
*) Изменение: ключ -v больше не выводит информацию о компиляторе.
diff --git a/LICENSE b/LICENSE
index 4fe17bf41..605a07b8a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002-2006 Igor Sysoev
+ * Copyright (C) 2002-2007 Igor Sysoev
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
diff --git a/auto/modules b/auto/modules
index f6c818afa..a298210f6 100644
--- a/auto/modules
+++ b/auto/modules
@@ -169,6 +169,11 @@ if [ $HTTP_ACCESS = YES ]; then
HTTP_SRCS="$HTTP_SRCS $HTTP_ACCESS_SRCS"
fi
+if [ $HTTP_LIMIT_ZONE = YES ]; then
+ HTTP_MODULES="$HTTP_MODULES $HTTP_LIMIT_ZONE_MODULE"
+ HTTP_SRCS="$HTTP_SRCS $HTTP_LIMIT_ZONE_SRCS"
+fi
+
if [ $HTTP_REALIP = YES ]; then
have=NGX_HTTP_REALIP . auto/have
HTTP_MODULES="$HTTP_MODULES $HTTP_REALIP_MODULE"
diff --git a/auto/options b/auto/options
index 29ed3a9c4..c0bc3b428 100644
--- a/auto/options
+++ b/auto/options
@@ -68,6 +68,7 @@ HTTP_PROXY=YES
HTTP_FASTCGI=YES
HTTP_PERL=NO
HTTP_MEMCACHED=YES
+HTTP_LIMIT_ZONE=YES
HTTP_EMPTY_GIF=YES
HTTP_BROWSER=YES
HTTP_FLV=NO
@@ -169,6 +170,7 @@ do
--without-http_proxy_module) HTTP_PROXY=NO ;;
--without-http_fastcgi_module) HTTP_FASTCGI=NO ;;
--without-http_memcached_module) HTTP_MEMCACHED=NO ;;
+ --without-http_limit_zone_module) HTTP_LIMIT_ZONE=NO ;;
--without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;;
--without-http_browser_module) HTTP_BROWSER=NO ;;
--without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;;
@@ -271,6 +273,7 @@ cat << END
--without-http_proxy_module disable ngx_http_proxy_module
--without-http_fastcgi_module disable ngx_http_fastcgi_module
--without-http_memcached_module disable ngx_http_memcached_module
+ --without-http_limit_zone_module disable ngx_http_limit_zone_module
--without-http_empty_gif_module disable ngx_http_empty_gif_module
--without-http_browser_module disable ngx_http_browser_module
--without-http_upstream_ip_hash_module
diff --git a/auto/sources b/auto/sources
index 89b326892..0ff1ece09 100644
--- a/auto/sources
+++ b/auto/sources
@@ -388,6 +388,10 @@ HTTP_MEMCACHED_MODULE=ngx_http_memcached_module
HTTP_MEMCACHED_SRCS=src/http/modules/ngx_http_memcached_module.c
+HTTP_LIMIT_ZONE_MODULE=ngx_http_limit_zone_module
+HTTP_LIMIT_ZONE_SRCS=src/http/modules/ngx_http_limit_zone_module.c
+
+
HTTP_EMPTY_GIF_MODULE=ngx_http_empty_gif_module
HTTP_EMPTY_GIF_SRCS=src/http/modules/ngx_http_empty_gif_module.c
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 56c87c9d4..0e97499f6 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.5.5"
+#define NGINX_VERSION "0.5.6"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c
index 59a3db232..baa43c912 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -150,9 +150,9 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
if (rc == NGX_CONF_FILE_DONE && block) {
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "unexpected end of file in %s:%ui, expecting \"}\"",
- cf->conf_file->file.name.data,
- cf->conf_file->line);
+ "unexpected end of file in %s:%ui, expecting \"}\"",
+ cf->conf_file->file.name.data,
+ cf->conf_file->line);
rc = NGX_ERROR;
break;
}
@@ -179,9 +179,9 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
}
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
- "%s in %s:%ui",
- rv, cf->conf_file->file.name.data,
- cf->conf_file->line);
+ "%s in %s:%ui",
+ rv, cf->conf_file->file.name.data,
+ cf->conf_file->line);
rc = NGX_ERROR;
break;
}
diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h
index f4163e915..c54884b52 100644
--- a/src/core/ngx_core.h
+++ b/src/core/ngx_core.h
@@ -64,11 +64,11 @@ typedef void (*ngx_connection_handler_pt)(ngx_connection_t *c);
#include <ngx_times.h>
#include <ngx_shmtx.h>
#include <ngx_slab.h>
+#include <ngx_inet.h>
+#include <ngx_cycle.h>
#if (NGX_OPENSSL)
#include <ngx_event_openssl.h>
#endif
-#include <ngx_inet.h>
-#include <ngx_cycle.h>
#include <ngx_process_cycle.h>
#include <ngx_conf_file.h>
#include <ngx_os.h>
diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c
index a3effb205..eac6a5c48 100644
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -49,7 +49,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
ngx_conf_t conf;
ngx_pool_t *pool;
ngx_cycle_t *cycle, **old;
- ngx_shm_zone_t *shm, *oshm;
+ ngx_shm_zone_t *shm_zone, *oshm_zone;
ngx_slab_pool_t *shpool;
ngx_list_part_t *part, *opart;
ngx_open_file_t *file;
@@ -353,7 +353,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
/* create shared memory */
part = &cycle->shared_memory.part;
- shm = part->elts;
+ shm_zone = part->elts;
for (i = 0; /* void */ ; i++) {
@@ -362,14 +362,21 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
break;
}
part = part->next;
- shm = part->elts;
+ shm_zone = part->elts;
i = 0;
}
- shm[i].shm.log = cycle->log;
+ if (shm_zone[i].shm.size == 0) {
+ ngx_log_error(NGX_LOG_EMERG, log, 0,
+ "zero size shared memory zone \"%V\"",
+ &shm_zone[i].name);
+ goto failed;
+ }
+
+ shm_zone[i].shm.log = cycle->log;
opart = &old_cycle->shared_memory.part;
- oshm = opart->elts;
+ oshm_zone = opart->elts;
for (n = 0; /* void */ ; n++) {
@@ -378,31 +385,45 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
break;
}
opart = opart->next;
- oshm = opart->elts;
+ oshm_zone = opart->elts;
n = 0;
}
- if (ngx_strcmp(shm[i].name.data, oshm[n].name.data) != 0) {
+ if (shm_zone[i].name.len != oshm_zone[n].name.len) {
continue;
}
- if (shm[i].shm.size == oshm[n].shm.size) {
- shm[i].shm.addr = oshm[n].shm.addr;
- goto found;
+ if (ngx_strncmp(shm_zone[i].name.data, oshm_zone[n].name.data,
+ shm_zone[i].name.len)
+ != 0)
+ {
+ continue;
}
- ngx_shm_free(&oshm[n].shm);
+ if (shm_zone[i].shm.size == oshm_zone[n].shm.size) {
+ shm_zone[i].shm.addr = oshm_zone[n].shm.addr;
+
+ if (shm_zone[i].init(&shm_zone[i], oshm_zone[n].data)
+ != NGX_OK)
+ {
+ goto failed;
+ }
+
+ goto shm_zone_found;
+ }
+
+ ngx_shm_free(&oshm_zone[n].shm);
break;
}
- if (ngx_shm_alloc(&shm[i].shm) != NGX_OK) {
+ if (ngx_shm_alloc(&shm_zone[i].shm) != NGX_OK) {
goto failed;
}
- shpool = (ngx_slab_pool_t *) shm[i].shm.addr;
+ shpool = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
- shpool->end = shm[i].shm.addr + shm[i].shm.size;
+ shpool->end = shm_zone[i].shm.addr + shm_zone[i].shm.size;
shpool->min_shift = 3;
#if (NGX_HAVE_ATOMIC_OPS)
@@ -412,7 +433,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
#else
lock_file = ngx_palloc(cycle->pool,
- cycle->lock_file.len + shm[i].name.len);
+ cycle->lock_file.len + shm_zone[i].name.len);
if (lock_file == NULL) {
goto failed;
@@ -420,7 +441,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
(void) ngx_cpystrn(ngx_cpymem(lock_file, cycle->lock_file.data,
cycle->lock_file.len),
- shm[i].name.data, shm[i].name.len + 1);
+ shm_zone[i].name.data, shm_zone[i].name.len + 1);
#endif
@@ -432,7 +453,11 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
ngx_slab_init(shpool);
- found:
+ if (shm_zone[i].init(&shm_zone[i], NULL) != NGX_OK) {
+ goto failed;
+ }
+
+ shm_zone_found:
continue;
}
@@ -569,7 +594,57 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
/* close and delete stuff that lefts from an old cycle */
- /* close the unneeded listening sockets */
+ /* free the unnecessary shared memory */
+
+ opart = &old_cycle->shared_memory.part;
+ oshm_zone = opart->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= opart->nelts) {
+ if (opart->next == NULL) {
+ goto old_shm_zone_done;
+ }
+ opart = opart->next;
+ oshm_zone = opart->elts;
+ i = 0;
+ }
+
+ part = &cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (n = 0; /* void */ ; n++) {
+
+ if (n >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ n = 0;
+ }
+
+ if (oshm_zone[i].name.len == shm_zone[n].name.len
+ && ngx_strncmp(oshm_zone[i].name.data,
+ shm_zone[n].name.data,
+ oshm_zone[i].name.len)
+ == 0)
+ {
+ goto live_shm_zone;
+ }
+ }
+
+ ngx_shm_free(&oshm_zone[i].shm);
+
+ live_shm_zone:
+
+ continue;
+ }
+
+old_shm_zone_done:
+
+
+ /* close the unnecessary listening sockets */
ls = old_cycle->listening.elts;
for (i = 0; i < old_cycle->listening.nelts; i++) {
@@ -585,7 +660,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
}
- /* close the unneeded open files */
+ /* close the unnecessary open files */
part = &old_cycle->open_files.part;
file = part->elts;
@@ -988,6 +1063,71 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
}
+ngx_shm_zone_t *
+ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name, size_t size, void *tag)
+{
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_list_part_t *part;
+
+ part = &cf->cycle->shared_memory.part;
+ shm_zone = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+ part = part->next;
+ shm_zone = part->elts;
+ i = 0;
+ }
+
+ if (name->len != shm_zone[i].name.len) {
+ continue;
+ }
+
+ if (ngx_strncmp(name->data, shm_zone[i].name.data, name->len) != 0) {
+ continue;
+ }
+
+ if (size && size != shm_zone[i].shm.size) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the size %uz of shared memory zone \"%V\" "
+ "conflicts with already declared size %uz",
+ size, &shm_zone[i].name, shm_zone[i].shm.size);
+ return NULL;
+ }
+
+ if (tag != shm_zone[i].tag) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "the shared memory zone \"%V\" is "
+ "already declared for a different use",
+ &shm_zone[i].name);
+ return NULL;
+ }
+
+ return &shm_zone[i];
+ }
+
+ shm_zone = ngx_list_push(&cf->cycle->shared_memory);
+
+ if (shm_zone == NULL) {
+ return NULL;
+ }
+
+ shm_zone->data = NULL;
+ shm_zone->shm.log = cf->cycle->log;
+ shm_zone->shm.size = size;
+ shm_zone->init = NULL;
+ shm_zone->name = *name;
+ shm_zone->tag = tag;
+
+ return shm_zone;
+}
+
+
static void
ngx_clean_old_cycles(ngx_event_t *ev)
{
diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h
index 677132ee1..21fb86acf 100644
--- a/src/core/ngx_cycle.h
+++ b/src/core/ngx_cycle.h
@@ -21,10 +21,17 @@
#define NGX_DEBUG_POINTS_ABORT 2
-typedef struct {
+typedef struct ngx_shm_zone_s ngx_shm_zone_t;
+
+typedef ngx_int_t (*ngx_shm_zone_init_pt) (ngx_shm_zone_t *zone, void *data);
+
+struct ngx_shm_zone_s {
+ void *data;
ngx_shm_t shm;
+ ngx_shm_zone_init_pt init;
ngx_str_t name;
-} ngx_shm_zone_t;
+ void *tag;
+};
struct ngx_cycle_s {
@@ -108,6 +115,8 @@ void ngx_delete_pidfile(ngx_cycle_t *cycle);
void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user);
ngx_pid_t ngx_exec_new_binary(ngx_cycle_t *cycle, char *const *argv);
u_long ngx_get_cpu_affinity(ngx_uint_t n);
+ngx_shm_zone_t *ngx_shared_memory_add(ngx_conf_t *cf, ngx_str_t *name,
+ size_t size, void *tag);
extern volatile ngx_cycle_t *ngx_cycle;
diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c
index e74c1aeab..3efa90093 100644
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -418,3 +418,168 @@ ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user)
return NGX_OK;
}
+
+
+ngx_int_t
+ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree)
+{
+ void *data, *prev;
+ u_char *p, *name;
+ size_t len;
+ ngx_int_t rc;
+ ngx_err_t err;
+ ngx_str_t file, buf;
+ ngx_dir_t dir;
+
+ buf.len = 0;
+ buf.data = NULL;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "walk tree \"%V\"", tree);
+
+ if (ngx_open_dir(tree, &dir) == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
+ ngx_open_dir_n " \"%s\" failed", tree->data);
+ return NGX_ERROR;
+ }
+
+ prev = ctx->data;
+
+ if (ctx->size) {
+ data = ngx_alloc(ctx->size, ctx->log);
+ if (data == NULL) {
+ goto failed;
+ }
+
+ if (ctx->init_handler(data, prev) == NGX_ABORT) {
+ goto failed;
+ }
+
+ ctx->data = data;
+ }
+
+ for ( ;; ) {
+
+ ngx_set_errno(0);
+
+ if (ngx_read_dir(&dir) == NGX_ERROR) {
+ err = ngx_errno;
+
+ if (err == NGX_ENOMOREFILES) {
+ rc = NGX_OK;
+
+ } else {
+ ngx_log_error(NGX_LOG_CRIT, ctx->log, err,
+ ngx_read_dir_n " \"%s\" failed", tree->data);
+ rc = NGX_ERROR;
+ }
+
+ goto done;
+ }
+
+ len = ngx_de_namelen(&dir);
+ name = ngx_de_name(&dir);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree name %uz:\"%s\"", len, name);
+
+ if (len == 1 && name[0] == '.') {
+ continue;
+ }
+
+ if (len == 2 && name[0] == '.' && name[1] == '.') {
+ continue;
+ }
+
+ file.len = tree->len + 1 + len;
+
+ if (file.len + NGX_DIR_MASK_LEN > buf.len) {
+
+ if (buf.len) {
+ ngx_free(buf.data);
+ }
+
+ buf.len = tree->len + 1 + len + NGX_DIR_MASK_LEN;
+
+ buf.data = ngx_alloc(buf.len + 1, ctx->log);
+ if (buf.data == NULL) {
+ goto failed;
+ }
+ }
+
+ p = ngx_cpymem(buf.data, tree->data, tree->len);
+ *p++ = '/';
+ ngx_memcpy(p, name, len + 1);
+
+ file.data = buf.data;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree path \"%s\"", file.data);
+
+ if (!dir.valid_info) {
+ if (ngx_de_info(file.data, &dir) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
+ ngx_de_info_n " \"%s\" failed", file.data);
+ continue;
+ }
+ }
+
+ if (ngx_de_is_file(&dir)) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree file \"%s\"", file.data);
+
+ if (ctx->file_handler(ctx, &file) == NGX_ABORT) {
+ goto failed;
+ }
+
+ } else if (ngx_de_is_dir(&dir)) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree enter dir \"%s\"", file.data);
+
+ if (ctx->pre_tree_handler(ctx, &file) == NGX_ABORT) {
+ goto failed;
+ }
+
+ if (ngx_walk_tree(ctx, &file) == NGX_ABORT) {
+ goto failed;
+ }
+
+ if (ctx->post_tree_handler(ctx, &file) == NGX_ABORT) {
+ goto failed;
+ }
+
+ } else {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->log, 0,
+ "tree special \"%s\"", file.data);
+
+ if (ctx->spec_handler(ctx, &file) == NGX_ABORT) {
+ goto failed;
+ }
+ }
+ }
+
+failed:
+
+ rc = NGX_ABORT;
+
+done:
+
+ if (buf.len) {
+ ngx_free(buf.data);
+ }
+
+ if (ctx->data) {
+ ngx_free(ctx->data);
+ ctx->data = prev;
+ }
+
+ if (ngx_close_dir(&dir) == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, ctx->log, ngx_errno,
+ ngx_close_dir_n " \"%s\" failed", tree->data);
+ }
+
+ return rc;
+}
diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h
index b51cad21d..71c993175 100644
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -56,6 +56,24 @@ typedef struct {
} ngx_temp_file_t;
+typedef struct ngx_tree_ctx_s ngx_tree_ctx_t;
+
+typedef ngx_int_t (*ngx_tree_init_handler_pt) (ngx_tree_ctx_t *ctx,
+ ngx_tree_ctx_t *prev);
+typedef ngx_int_t (*ngx_tree_handler_pt) (ngx_tree_ctx_t *ctx, ngx_str_t *name);
+
+struct ngx_tree_ctx_s {
+ ngx_tree_init_handler_pt init_handler;
+ ngx_tree_handler_pt file_handler;
+ ngx_tree_handler_pt pre_tree_handler;
+ ngx_tree_handler_pt post_tree_handler;
+ ngx_tree_handler_pt spec_handler;
+ void *data;
+ size_t size;
+ ngx_log_t *log;
+};
+
+
ssize_t ngx_write_chain_to_temp_file(ngx_temp_file_t *tf, ngx_chain_t *chain);
ngx_int_t ngx_create_temp_file(ngx_file_t *file, ngx_path_t *path,
ngx_pool_t *pool, ngx_uint_t persistent,ngx_uint_t mode);
@@ -64,6 +82,7 @@ ngx_int_t ngx_create_path(ngx_file_t *file, ngx_path_t *path);
ngx_err_t ngx_create_full_path(u_char *dir, ngx_uint_t access);
ngx_int_t ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot);
ngx_int_t ngx_create_pathes(ngx_cycle_t *cycle, ngx_uid_t user);
+ngx_int_t ngx_walk_tree(ngx_tree_ctx_t *ctx, ngx_str_t *tree);
void ngx_init_temp_number(void);
ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h
index 008db2a25..16524ffc8 100644
--- a/src/core/ngx_rbtree.h
+++ b/src/core/ngx_rbtree.h
@@ -50,6 +50,11 @@ void ngx_rbtree_insert_timer_value(ngx_rbtree_node_t *root,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+/* a sentinel must be black */
+
+#define ngx_rbtree_sentinel_init(node) node->color = 0
+
+
static ngx_inline ngx_rbtree_node_t *
ngx_rbtree_min(ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
{
diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c
index 763a1d6e4..b09d2e44b 100644
--- a/src/core/ngx_slab.c
+++ b/src/core/ngx_slab.c
@@ -148,14 +148,31 @@ ngx_slab_init(ngx_slab_pool_t *pool)
void *
ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
{
+ void *p;
+
+ ngx_shmtx_lock(&pool->mutex);
+
+ p = ngx_slab_alloc_locked(pool, size);
+
+ ngx_shmtx_unlock(&pool->mutex);
+
+ return p;
+}
+
+
+void *
+ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size)
+{
size_t s;
uintptr_t p, n, m, mask, *bitmap;
ngx_uint_t i, slot, shift, map;
ngx_slab_page_t *page, *prev, *slots;
- ngx_shmtx_lock(&pool->mutex);
-
if (size >= ngx_slab_max_size) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
+ "slab alloc: %uz", size);
+
page = ngx_slab_alloc_pages(pool, (size + ngx_pagesize - 1)
>> ngx_pagesize_shift);
if (page) {
@@ -186,14 +203,9 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
slots = (ngx_slab_page_t *) ((u_char *) pool + sizeof(ngx_slab_pool_t));
page = slots[slot].next;
-#if 0
- ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0,
- "slab alloc: page %p next: %p", page, page->next);
-#endif
-
if (page->next != page) {
- if (size < ngx_slab_exact_size) {
+ if (shift < ngx_slab_exact_shift) {
do {
p = (page - pool->pages) << ngx_pagesize_shift;
@@ -212,7 +224,9 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
}
bitmap[n] |= m;
- i <<= shift;
+
+ i = ((n * sizeof(uintptr_t) * 8) << shift)
+ + (i << shift);
if (bitmap[n] == NGX_SLAB_BUSY) {
for (n = n + 1; n < map; n++) {
@@ -243,7 +257,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
} while (page);
- } else if (size == ngx_slab_exact_size) {
+ } else if (shift == ngx_slab_exact_shift) {
do {
if (page->slab != NGX_SLAB_BUSY) {
@@ -277,7 +291,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
} while (page);
- } else { /* size < ngx_pagesize */
+ } else { /* shift > ngx_slab_exact_shift */
n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK);
n = 1 << n;
@@ -324,7 +338,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
page = ngx_slab_alloc_pages(pool, 1);
if (page) {
- if (size < ngx_slab_exact_size) {
+ if (shift < ngx_slab_exact_shift) {
p = (page - pool->pages) << ngx_pagesize_shift;
bitmap = (uintptr_t *) (pool->start + p);
@@ -354,7 +368,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
goto done;
- } else if (size == ngx_slab_exact_size) {
+ } else if (shift == ngx_slab_exact_shift) {
page->slab = 1;
page->next = &slots[slot];
@@ -367,7 +381,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
goto done;
- } else { /* size < ngx_pagesize */
+ } else { /* shift > ngx_slab_exact_shift */
page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift;
page->next = &slots[slot];
@@ -386,8 +400,6 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size)
done:
- ngx_shmtx_unlock(&pool->mutex);
-
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab alloc: %p", p);
return (void *) p;
@@ -397,6 +409,17 @@ done:
void
ngx_slab_free(ngx_slab_pool_t *pool, void *p)
{
+ ngx_shmtx_lock(&pool->mutex);
+
+ ngx_slab_free_locked(pool, p);
+
+ ngx_shmtx_unlock(&pool->mutex);
+}
+
+
+void
+ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p)
+{
size_t size;
uintptr_t slab, *bitmap;
ngx_uint_t n, m, type, slot, shift, map;
@@ -404,8 +427,6 @@ ngx_slab_free(ngx_slab_pool_t *pool, void *p)
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p);
- ngx_shmtx_lock(&pool->mutex);
-
if ((u_char *) p < pool->start || (u_char *) p > pool->end) {
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"ngx_slab_free(): outside of pool");
@@ -584,8 +605,6 @@ done:
ngx_slab_junk(p, size);
- ngx_shmtx_unlock(&pool->mutex);
-
return;
wrong_chunk:
@@ -602,8 +621,6 @@ chunk_already_free:
fail:
- ngx_shmtx_unlock(&pool->mutex);
-
return;
}
@@ -658,6 +675,7 @@ ngx_slab_alloc_pages(ngx_slab_pool_t *pool, ngx_uint_t pages)
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, NGX_ENOMEM,
"ngx_slab_alloc(): failed");
+
return NULL;
}
@@ -674,12 +692,16 @@ ngx_slab_free_pages(ngx_slab_pool_t *pool, ngx_slab_page_t *page,
ngx_memzero(&page[1], pages * sizeof(ngx_slab_page_t));
}
- prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK);
- prev->next = page->next;
+ if (page->next) {
+ prev = (ngx_slab_page_t *) (page->prev & ~NGX_SLAB_PAGE_MASK);
+ prev->next = page->next;
+ page->next->prev = page->prev;
+ }
+ page->prev = (uintptr_t) &pool->free;
page->next = pool->free.next;
- pool->free.next = page;
- page->prev = page->next->prev;
page->next->prev = (uintptr_t) page;
+
+ pool->free.next = page;
}
diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h
index ea9e0ea25..5bdacaf1b 100644
--- a/src/core/ngx_slab.h
+++ b/src/core/ngx_slab.h
@@ -39,7 +39,9 @@ typedef struct {
void ngx_slab_init(ngx_slab_pool_t *pool);
void *ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size);
+void *ngx_slab_alloc_locked(ngx_slab_pool_t *pool, size_t size);
void ngx_slab_free(ngx_slab_pool_t *pool, void *p);
+void ngx_slab_free_locked(ngx_slab_pool_t *pool, void *p);
#endif /* _NGX_SLAB_H_INCLUDED_ */
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 3573dc850..dff23ae31 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -22,6 +22,17 @@ static void ngx_ssl_read_handler(ngx_event_t *rev);
static void ngx_ssl_shutdown_handler(ngx_event_t *ev);
static void ngx_ssl_connection_error(ngx_connection_t *c, int sslerr,
ngx_err_t err, char *text);
+
+static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone,
+ void *data);
+static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn,
+ ngx_ssl_session_t *sess);
+static ngx_ssl_session_t *ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn,
+ u_char *id, int len, int *copy);
+static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess);
+static void ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
+ ngx_slab_pool_t *shpool, ngx_uint_t n);
+
static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);
@@ -84,12 +95,18 @@ static long ngx_ssl_protocols[] = {
};
-int ngx_connection_index;
+int ngx_ssl_connection_index;
+int ngx_ssl_server_conf_index;
+int ngx_ssl_session_cache_index;
ngx_int_t
ngx_ssl_init(ngx_log_t *log)
{
+#if OPENSSL_VERSION_NUMBER >= 0x00907000
+ OPENSSL_config(NULL);
+#endif
+
SSL_library_init();
SSL_load_error_strings();
@@ -97,19 +114,35 @@ ngx_ssl_init(ngx_log_t *log)
ENGINE_load_builtin_engines();
#endif
- ngx_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ ngx_ssl_connection_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
- if (ngx_connection_index == -1) {
+ if (ngx_ssl_connection_index == -1) {
ngx_ssl_error(NGX_LOG_ALERT, log, 0, "SSL_get_ex_new_index() failed");
return NGX_ERROR;
}
+ ngx_ssl_server_conf_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+ if (ngx_ssl_server_conf_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
+ ngx_ssl_session_cache_index = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL,
+ NULL);
+ if (ngx_ssl_session_cache_index == -1) {
+ ngx_ssl_error(NGX_LOG_ALERT, log, 0,
+ "SSL_CTX_get_ex_new_index() failed");
+ return NGX_ERROR;
+ }
+
return NGX_OK;
}
ngx_int_t
-ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols)
+ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
{
ssl->ctx = SSL_CTX_new(SSLv23_method());
@@ -118,6 +151,12 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols)
return NGX_ERROR;
}
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_server_conf_index, data) == 0) {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ return NGX_ERROR;
+ }
+
/* client side options */
SSL_CTX_set_options(ssl->ctx, SSL_OP_MICROSOFT_SESS_ID_BUG);
@@ -260,7 +299,7 @@ ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store)
name = X509_get_issuer_name(cert);
issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)";
- ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
+ ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0,
"verify:%d, error:%d, depth:%d, "
"subject:\"%s\",issuer: \"%s\"",
ok, err, depth, subject, issuer);
@@ -332,7 +371,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c, ngx_uint_t flags)
SSL_set_accept_state(sc->connection);
}
- if (SSL_set_ex_data(sc->connection, ngx_connection_index, c) == 0) {
+ if (SSL_set_ex_data(sc->connection, ngx_ssl_connection_index, c) == 0) {
ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_set_ex_data() failed");
return NGX_ERROR;
}
@@ -1014,7 +1053,7 @@ ngx_ssl_shutdown_handler(ngx_event_t *ev)
c->timedout = 1;
}
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "SSL shutdown handler");
+ ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, "SSL shutdown handler");
if (ngx_ssl_shutdown(c) == NGX_AGAIN) {
return;
@@ -1100,6 +1139,433 @@ ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...)
}
+ngx_int_t
+ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
+ ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout)
+{
+ long cache_mode;
+
+ cache_mode = SSL_SESS_CACHE_SERVER;
+
+ if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) {
+ cache_mode |= SSL_SESS_CACHE_NO_INTERNAL;
+ }
+
+ SSL_CTX_set_session_cache_mode(ssl->ctx, cache_mode);
+
+ SSL_CTX_set_session_id_context(ssl->ctx, sess_ctx->data, sess_ctx->len);
+
+ if (builtin_session_cache != NGX_SSL_NO_BUILTIN_SCACHE) {
+
+ if (builtin_session_cache != NGX_SSL_DFLT_BUILTIN_SCACHE) {
+ SSL_CTX_sess_set_cache_size(ssl->ctx, builtin_session_cache);
+ }
+
+ SSL_CTX_set_timeout(ssl->ctx, timeout);
+ }
+
+ if (shm_zone) {
+ shm_zone->init = ngx_ssl_session_cache_init;
+
+ SSL_CTX_sess_set_new_cb(ssl->ctx, ngx_ssl_new_session);
+ SSL_CTX_sess_set_get_cb(ssl->ctx, ngx_ssl_get_cached_session);
+ SSL_CTX_sess_set_remove_cb(ssl->ctx, ngx_ssl_remove_session);
+
+ if (SSL_CTX_set_ex_data(ssl->ctx, ngx_ssl_session_cache_index, shm_zone)
+ == 0)
+ {
+ ngx_ssl_error(NGX_LOG_EMERG, ssl->log, 0,
+ "SSL_CTX_set_ex_data() failed");
+ return NGX_ERROR;
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data)
+{
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *sentinel;
+ ngx_ssl_session_cache_t *cache;
+
+ if (data) {
+ shm_zone->data = data;
+ return NGX_OK;
+ }
+
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ cache = ngx_slab_alloc(shpool, sizeof(ngx_ssl_session_cache_t));
+ if (cache == NULL) {
+ return NGX_ERROR;
+ }
+
+ cache->session_cache_head.prev = NULL;
+ cache->session_cache_head.next = &cache->session_cache_tail;
+
+ cache->session_cache_tail.prev = &cache->session_cache_head;
+ cache->session_cache_tail.next = NULL;
+
+ cache->session_rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
+ if (cache->session_rbtree == NULL) {
+ return NGX_ERROR;
+ }
+
+ sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
+ if (sentinel == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_rbtree_sentinel_init(sentinel);
+
+ cache->session_rbtree->root = sentinel;
+ cache->session_rbtree->sentinel = sentinel;
+ cache->session_rbtree->insert = ngx_rbtree_insert_value;
+
+ shm_zone->data = cache;
+
+ return NGX_OK;
+}
+
+
+/*
+ * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow,
+ * so they are outside the code locked by shared pool mutex
+ */
+
+static int
+ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess)
+{
+ int len;
+ u_char *p, *id;
+ uint32_t hash;
+ SSL_CTX *ssl_ctx;
+ ngx_time_t *tp;
+ ngx_shm_zone_t *shm_zone;
+ ngx_connection_t *c;
+ ngx_slab_pool_t *shpool;
+ ngx_ssl_sess_id_t *sess_id;
+ ngx_ssl_cached_sess_t *cached_sess;
+ ngx_ssl_session_cache_t *cache;
+ u_char buf[NGX_SSL_MAX_SESSION_SIZE];
+
+ len = i2d_SSL_SESSION(sess, NULL);
+
+ /* do not cache too big session */
+
+ if (len > (int) NGX_SSL_MAX_SESSION_SIZE) {
+ return 0;
+ }
+
+ p = buf;
+ i2d_SSL_SESSION(sess, &p);
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ ssl_ctx = SSL_get_SSL_CTX(ssl_conn);
+ shm_zone = SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_session_cache_index);
+
+ cache = shm_zone->data;
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ /* drop one or two expired sessions */
+ ngx_ssl_expire_sessions(cache, shpool, 1);
+
+ cached_sess = ngx_slab_alloc_locked(shpool,
+ offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+
+ if (cached_sess == NULL) {
+
+ /* drop the oldest non-expired session and try once more */
+
+ ngx_ssl_expire_sessions(cache, shpool, 0);
+
+ cached_sess = ngx_slab_alloc_locked(shpool,
+ offsetof(ngx_ssl_cached_sess_t, asn1) + len);
+
+ if (cached_sess == NULL) {
+ id = NULL;
+ goto failed;
+ }
+ }
+
+ id = ngx_slab_alloc_locked(shpool, sess->session_id_length);
+ if (id == NULL) {
+ goto failed;
+ }
+
+ sess_id = ngx_slab_alloc_locked(shpool, sizeof(ngx_ssl_sess_id_t));
+ if (sess_id == NULL) {
+ goto failed;
+ }
+
+ ngx_memcpy(&cached_sess->asn1[0], buf, len);
+
+ ngx_memcpy(id, sess->session_id, sess->session_id_length);
+
+ hash = ngx_crc32_short(sess->session_id, sess->session_id_length);
+
+ ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "http ssl new session: %08XD:%d:%d",
+ hash, sess->session_id_length, len);
+
+ sess_id->node.key = hash;
+ sess_id->node.data = (u_char) sess->session_id_length;
+ sess_id->id = id;
+ sess_id->len = len;
+ sess_id->session = cached_sess;
+
+ tp = ngx_timeofday();
+
+ cached_sess->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx);
+ cached_sess->sess_id = sess_id;
+
+ cached_sess->next = cache->session_cache_head.next;
+ cached_sess->next->prev = cached_sess;
+ cached_sess->prev = &cache->session_cache_head;
+ cache->session_cache_head.next = cached_sess;
+
+ ngx_rbtree_insert(cache->session_rbtree, &sess_id->node);
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ return 0;
+
+failed:
+
+ if (cached_sess) {
+ ngx_slab_free_locked(shpool, cached_sess);
+ }
+
+ if (id) {
+ ngx_slab_free_locked(shpool, id);
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ ngx_log_error(NGX_LOG_ALERT, c->log, 0,
+ "could not add new SSL session to the session cache");
+
+ return 0;
+}
+
+
+static ngx_ssl_session_t *
+ngx_ssl_get_cached_session(ngx_ssl_conn_t *ssl_conn, u_char *id, int len,
+ int *copy)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x0090707fL
+ const
+#endif
+ u_char *p;
+ uint32_t hash;
+ ngx_time_t *tp;
+ ngx_shm_zone_t *shm_zone;
+ ngx_slab_pool_t *shpool;
+ ngx_connection_t *c;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_ssl_session_t *sess;
+ ngx_ssl_sess_id_t *sess_id;
+ ngx_ssl_cached_sess_t *cached_sess;
+ ngx_ssl_session_cache_t *cache;
+ u_char buf[NGX_SSL_MAX_SESSION_SIZE];
+
+ c = ngx_ssl_get_connection(ssl_conn);
+
+ hash = ngx_crc32_short(id, len);
+ *copy = 0;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
+ "http ssl get session: %08XD:%d", hash, len);
+
+ shm_zone = SSL_CTX_get_ex_data(SSL_get_SSL_CTX(ssl_conn),
+ ngx_ssl_session_cache_index);
+
+ cache = shm_zone->data;
+
+ if (cache->session_rbtree == NULL) {
+ return NULL;
+ }
+
+ sess = NULL;
+
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ node = cache->session_rbtree->root;
+ sentinel = cache->session_rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ if (hash == node->key && (u_char) len == node->data) {
+ sess_id = (ngx_ssl_sess_id_t *) node;
+
+ if (ngx_strncmp(id, sess_id->id, len) == 0) {
+
+ cached_sess = sess_id->session;
+
+ tp = ngx_timeofday();
+
+ if (cached_sess->expire > tp->sec) {
+ ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len);
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ p = buf;
+ sess = d2i_SSL_SESSION(NULL, &p, sess_id->len);
+
+ return sess;
+ }
+
+ cached_sess->next->prev = cached_sess->prev;
+ cached_sess->prev->next = cached_sess->next;
+
+ ngx_rbtree_delete(cache->session_rbtree, node);
+
+ ngx_slab_free_locked(shpool, cached_sess);
+ ngx_slab_free_locked(shpool, sess_id->id);
+ ngx_slab_free_locked(shpool, sess_id);
+
+ sess = NULL;
+
+ break;
+ }
+ }
+
+ node = node->right;
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ return sess;
+}
+
+
+static void
+ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess)
+{
+ u_char *id, len;
+ uint32_t hash;
+ ngx_shm_zone_t *shm_zone;
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_ssl_sess_id_t *sess_id;
+ ngx_ssl_cached_sess_t *cached_sess;
+ ngx_ssl_session_cache_t *cache;
+
+ shm_zone = SSL_CTX_get_ex_data(ssl, ngx_ssl_session_cache_index);
+
+ cache = shm_zone->data;
+
+ id = sess->session_id;
+ len = (u_char) sess->session_id_length;
+
+ hash = ngx_crc32_short(id, (size_t) len);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
+ "http ssl remove session: %08XD:%d", hash, len);
+
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ node = cache->session_rbtree->root;
+ sentinel = cache->session_rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ if (hash == node->key && len == node->data) {
+ sess_id = (ngx_ssl_sess_id_t *) node;
+
+ if (ngx_strncmp(id, sess_id->id, (size_t) len) == 0) {
+
+ cached_sess = sess_id->session;
+
+ cached_sess->next->prev = cached_sess->prev;
+ cached_sess->prev->next = cached_sess->next;
+
+ ngx_rbtree_delete(cache->session_rbtree, node);
+
+ ngx_slab_free_locked(shpool, cached_sess);
+ ngx_slab_free_locked(shpool, sess_id->id);
+ ngx_slab_free_locked(shpool, sess_id);
+
+ break;
+ }
+ }
+
+ node = node->right;
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+}
+
+
+static void
+ngx_ssl_expire_sessions(ngx_ssl_session_cache_t *cache,
+ ngx_slab_pool_t *shpool, ngx_uint_t n)
+{
+ ngx_time_t *tp;
+ ngx_ssl_sess_id_t *sess_id;
+ ngx_ssl_cached_sess_t *sess;
+
+ tp = ngx_timeofday();
+
+ while (n < 3) {
+
+ sess = cache->session_cache_tail.prev;
+
+ if (sess == &cache->session_cache_head) {
+ return;
+ }
+
+ if (n++ != 0 && sess->expire > tp->sec) {
+ break;
+ }
+
+ sess->next->prev = sess->prev;
+ sess->prev->next = sess->next;
+
+ sess_id = sess->sess_id;
+
+ ngx_rbtree_delete(cache->session_rbtree, &sess_id->node);
+
+ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0,
+ "expire session: %08Xi", sess_id->node.key);
+
+ ngx_slab_free_locked(shpool, sess);
+ ngx_slab_free_locked(shpool, sess_id->id);
+ ngx_slab_free_locked(shpool, sess_id);
+ }
+}
+
+
void
ngx_ssl_cleanup_ctx(void *data)
{
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 9777fe3d9..078b2bab0 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -15,6 +15,7 @@
#include <openssl/err.h>
#if OPENSSL_VERSION_NUMBER >= 0x00907000
+#include <openssl/conf.h>
#include <openssl/engine.h>
#define NGX_SSL_ENGINE 1
#endif
@@ -50,6 +51,41 @@ typedef struct {
} ngx_ssl_connection_t;
+#define NGX_SSL_DFLT_BUILTIN_SCACHE -2
+#define NGX_SSL_NO_BUILTIN_SCACHE -3
+
+
+typedef struct ngx_ssl_cached_sess_s ngx_ssl_cached_sess_t;
+
+
+#define NGX_SSL_MAX_SESSION_SIZE (4096 - offsetof(ngx_ssl_cached_sess_t, asn1))
+
+
+typedef struct {
+ ngx_rbtree_node_t node;
+ u_char *id;
+ size_t len;
+ ngx_ssl_cached_sess_t *session;
+} ngx_ssl_sess_id_t;
+
+
+struct ngx_ssl_cached_sess_s {
+ ngx_ssl_cached_sess_t *prev;
+ ngx_ssl_cached_sess_t *next;
+ time_t expire;
+ ngx_ssl_sess_id_t *sess_id;
+ u_char asn1[1];
+};
+
+
+typedef struct {
+ ngx_rbtree_t *session_rbtree;
+ ngx_ssl_cached_sess_t session_cache_head;
+ ngx_ssl_cached_sess_t session_cache_tail;
+} ngx_ssl_session_cache_t;
+
+
+
#define NGX_SSL_SSLv2 2
#define NGX_SSL_SSLv3 4
#define NGX_SSL_TLSv1 8
@@ -62,19 +98,24 @@ typedef struct {
ngx_int_t ngx_ssl_init(ngx_log_t *log);
-ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols);
+ngx_int_t ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data);
ngx_int_t ngx_ssl_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_str_t *key);
ngx_int_t ngx_ssl_client_certificate(ngx_conf_t *cf, ngx_ssl_t *ssl,
ngx_str_t *cert, ngx_int_t depth);
ngx_int_t ngx_ssl_generate_rsa512_key(ngx_ssl_t *ssl);
+ngx_int_t ngx_ssl_session_cache(ngx_ssl_t *ssl, ngx_str_t *sess_ctx,
+ ssize_t builtin_session_cache, ngx_shm_zone_t *shm_zone, time_t timeout);
ngx_int_t ngx_ssl_create_connection(ngx_ssl_t *ssl, ngx_connection_t *c,
ngx_uint_t flags);
ngx_int_t ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session);
#define ngx_ssl_get_session(c) SSL_get1_session(c->ssl->connection)
#define ngx_ssl_free_session SSL_SESSION_free
-#define ngx_ssl_get_connection(sc) SSL_get_ex_data(sc, ngx_connection_index)
+#define ngx_ssl_get_connection(ssl_conn) \
+ SSL_get_ex_data(ssl_conn, ngx_ssl_connection_index)
+#define ngx_ssl_get_server_conf(ssl_ctx) \
+ SSL_CTX_get_ex_data(ssl_ctx, ngx_ssl_server_conf_index)
ngx_int_t ngx_ssl_get_protocol(ngx_connection_t *c, ngx_pool_t *pool,
@@ -89,8 +130,6 @@ ngx_int_t ngx_ssl_get_serial_number(ngx_connection_t *c, ngx_pool_t *pool,
ngx_str_t *s);
-
-
ngx_int_t ngx_ssl_handshake(ngx_connection_t *c);
ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size);
ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size);
@@ -103,7 +142,9 @@ void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
void ngx_ssl_cleanup_ctx(void *data);
-extern int ngx_connection_index;
+extern int ngx_ssl_connection_index;
+extern int ngx_ssl_server_conf_index;
+extern int ngx_ssl_session_cache_index;
#endif /* _NGX_EVENT_OPENSSL_H_INCLUDED_ */
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 0ecf8afa8..0d3c912b9 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -19,6 +19,11 @@ typedef struct {
static ngx_int_t ngx_http_dav_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_dav_no_init(ngx_tree_ctx_t *ctx,
+ ngx_tree_ctx_t *prev);
+static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path);
+static ngx_int_t ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path);
+static ngx_int_t ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path);
static void ngx_http_dav_put_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_dav_error(ngx_http_request_t *, ngx_err_t err,
ngx_int_t not_found, char *failed, u_char *path);
@@ -105,6 +110,7 @@ ngx_http_dav_handler(ngx_http_request_t *r)
size_t root;
ngx_int_t rc;
ngx_str_t path;
+ ngx_tree_ctx_t tree;
ngx_file_info_t fi;
ngx_table_elt_t *depth;
ngx_http_dav_loc_conf_t *dlcf;
@@ -176,8 +182,23 @@ ngx_http_dav_handler(ngx_http_request_t *r)
return NGX_HTTP_BAD_REQUEST;
}
- if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) {
- return NGX_HTTP_NO_CONTENT;
+ path.len -= 2;
+
+ tree.init_handler = ngx_http_dav_no_init;
+ tree.file_handler = ngx_http_dav_delete_file;
+ tree.pre_tree_handler = ngx_http_dav_noop;
+ tree.post_tree_handler = ngx_http_dav_delete_dir;
+ tree.spec_handler = ngx_http_dav_delete_file;
+ tree.data = NULL;
+ tree.size = 0;
+ tree.log = r->connection->log;
+
+ if (ngx_walk_tree(&tree, &path) == NGX_OK) {
+
+ if (ngx_delete_dir(path.data) != NGX_FILE_ERROR) {
+ return NGX_HTTP_NO_CONTENT;
+ }
+
}
failed = ngx_delete_dir_n;
@@ -248,6 +269,44 @@ ngx_http_dav_handler(ngx_http_request_t *r)
}
+static ngx_int_t
+ngx_http_dav_no_init(ngx_tree_ctx_t *ctx, ngx_tree_ctx_t *prev)
+{
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+{
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_dav_delete_dir(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+{
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
+ "http delete dir: \"%s\"", path->data);
+
+ ngx_delete_dir(path->data);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_dav_delete_file(ngx_tree_ctx_t *ctx, ngx_str_t *path)
+{
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
+ "http delete file: \"%s\"", path->data);
+
+ ngx_delete_file(path->data);
+
+ return NGX_OK;
+}
+
+
static void
ngx_http_dav_put_handler(ngx_http_request_t *r)
{
diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c
index 4df57f9ce..0f49551cc 100644
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -140,6 +140,10 @@ ngx_http_index_handler(ngx_http_request_t *r)
return NGX_DECLINED;
}
+ if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
+ return NGX_DECLINED;
+ }
+
/* TODO: Win32 */
if (r->zero_in_uri) {
return NGX_DECLINED;
diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c
new file mode 100644
index 000000000..396cb7fd3
--- /dev/null
+++ b/src/http/modules/ngx_http_limit_zone_module.c
@@ -0,0 +1,444 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_http.h>
+
+
+typedef struct {
+ u_char color;
+ u_char len;
+ u_short conn;
+ u_char data[1];
+} ngx_http_limit_zone_node_t;
+
+
+typedef struct {
+ ngx_shm_zone_t *shm_zone;
+ ngx_rbtree_node_t *node;
+} ngx_http_limit_zone_cleanup_t;
+
+
+typedef struct {
+ ngx_rbtree_t *rbtree;
+ ngx_int_t index;
+ ngx_str_t var;
+} ngx_http_limit_zone_ctx_t;
+
+
+typedef struct {
+ ngx_shm_zone_t *shm_zone;
+ ngx_uint_t conn;
+} ngx_http_limit_zone_conf_t;
+
+
+static void ngx_http_limit_zone_cleanup(void *data);
+
+static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf);
+static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf);
+
+
+static ngx_command_t ngx_http_limit_zone_commands[] = {
+
+ { ngx_string("limit_zone"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3,
+ ngx_http_limit_zone,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("limit_conn"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
+ ngx_http_limit_conn,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_http_module_t ngx_http_limit_zone_module_ctx = {
+ NULL, /* preconfiguration */
+ ngx_http_limit_zone_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
+
+ ngx_http_limit_zone_create_conf, /* create location configration */
+ ngx_http_limit_zone_merge_conf /* merge location configration */
+};
+
+
+ngx_module_t ngx_http_limit_zone_module = {
+ NGX_MODULE_V1,
+ &ngx_http_limit_zone_module_ctx, /* module context */
+ ngx_http_limit_zone_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
+};
+
+
+static ngx_int_t
+ngx_http_limit_zone_handler(ngx_http_request_t *r)
+{
+ size_t len, n;
+ uint32_t hash;
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_pool_cleanup_t *cln;
+ ngx_http_variable_value_t *vv;
+ ngx_http_limit_zone_ctx_t *ctx;
+ ngx_http_limit_zone_node_t *lz;
+ ngx_http_limit_zone_conf_t *lzcf;
+ ngx_http_limit_zone_cleanup_t *lzcln;
+
+ if (r->main->limit_zone_set) {
+ return NGX_DECLINED;
+ }
+
+ lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module);
+
+ if (lzcf->shm_zone == NULL) {
+ return NGX_DECLINED;
+ }
+
+ ctx = lzcf->shm_zone->data;
+
+ vv = ngx_http_get_indexed_variable(r, ctx->index);
+
+ if (vv == NULL || vv->not_found) {
+ return NGX_DECLINED;
+ }
+
+ r->limit_zone_set = 1;
+
+ len = vv->len;
+
+ hash = ngx_crc32_short(vv->data, len);
+
+ cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t));
+ if (cln == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ node = ctx->rbtree->root;
+ sentinel = ctx->rbtree->sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ if (hash == node->key ){
+ lz = (ngx_http_limit_zone_node_t *) &node->color;
+
+ if (len == (size_t) lz->len
+ && ngx_strncmp(lz->data, vv->data, len) == 0)
+ {
+ if ((ngx_uint_t) lz->conn < lzcf->conn) {
+ lz->conn++;
+ goto done;
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
+ }
+ }
+ }
+
+ n = offsetof(ngx_rbtree_node_t, color)
+ + offsetof(ngx_http_limit_zone_node_t, data)
+ + len;
+
+ node = ngx_slab_alloc_locked(shpool, n);
+ if (node == NULL) {
+ ngx_shmtx_unlock(&shpool->mutex);
+ return NGX_HTTP_SERVICE_UNAVAILABLE;
+ }
+
+ lz = (ngx_http_limit_zone_node_t *) &node->color;
+
+ node->key = hash;
+ lz->len = (u_char) len;
+ lz->conn = 1;
+ ngx_memcpy(lz->data, vv->data, len);
+
+ ngx_rbtree_insert(ctx->rbtree, node);
+
+done:
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "limit zone: %08XD %d", node->key, lz->conn);
+
+ ngx_shmtx_unlock(&shpool->mutex);
+
+ cln->handler = ngx_http_limit_zone_cleanup;
+ lzcln = cln->data;
+
+ lzcln->shm_zone = lzcf->shm_zone;
+ lzcln->node = node;
+
+ return NGX_DECLINED;
+}
+
+
+static void
+ngx_http_limit_zone_cleanup(void *data)
+{
+ ngx_http_limit_zone_cleanup_t *lzcln = data;
+
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *node;
+ ngx_http_limit_zone_ctx_t *ctx;
+ ngx_http_limit_zone_node_t *lz;
+
+ ctx = lzcln->shm_zone->data;
+ shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr;
+ node = lzcln->node;
+ lz = (ngx_http_limit_zone_node_t *) &node->color;
+
+ ngx_shmtx_lock(&shpool->mutex);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0,
+ "limit zone cleanup: %08XD %d", node->key, lz->conn);
+
+ lz->conn--;
+
+ if (lz->conn == 0) {
+ ngx_rbtree_delete(ctx->rbtree, node);
+ ngx_slab_free_locked(shpool, node);
+ }
+
+ ngx_shmtx_unlock(&shpool->mutex);
+}
+
+
+static ngx_int_t
+ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data)
+{
+ ngx_http_limit_zone_ctx_t *octx = data;
+
+ ngx_slab_pool_t *shpool;
+ ngx_rbtree_node_t *sentinel;
+ ngx_http_limit_zone_ctx_t *ctx;
+
+ ctx = shm_zone->data;
+
+ if (octx) {
+ if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) {
+ ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0,
+ "limit_zone \"%V\" use the \"%V\" variable "
+ "while previously it used the \"%V\" variable",
+ &shm_zone->name, &ctx->var, &octx->var);
+ return NGX_ERROR;
+ }
+
+ ctx->rbtree = octx->rbtree;
+
+ return NGX_OK;
+ }
+
+ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t));
+ if (ctx->rbtree == NULL) {
+ return NGX_ERROR;
+ }
+
+ sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t));
+ if (sentinel == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_rbtree_sentinel_init(sentinel);
+
+ ctx->rbtree->root = sentinel;
+ ctx->rbtree->sentinel = sentinel;
+ ctx->rbtree->insert = ngx_rbtree_insert_value;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_http_limit_zone_create_conf(ngx_conf_t *cf)
+{
+ ngx_http_limit_zone_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t));
+ if (conf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->shm_zone = NULL;
+ * conf->conn = 0;
+ */
+
+ return conf;
+}
+
+
+static char *
+ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+ ngx_http_limit_zone_conf_t *prev = parent;
+ ngx_http_limit_zone_conf_t *conf = child;
+
+ if (conf->shm_zone == NULL) {
+ *conf = *prev;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ssize_t n;
+ ngx_str_t *value;
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_limit_zone_ctx_t *ctx;
+
+ value = cf->args->elts;
+
+ if (value[2].data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ value[2].len--;
+ value[2].data++;
+
+ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t));
+ if (ctx == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->index = ngx_http_get_variable_index(cf, &value[2]);
+ if (ctx->index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ ctx->var = value[2];
+
+ n = ngx_parse_size(&value[3]);
+
+ if (n == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid size of limit_zone \"%V\"", &value[3]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (n < (ngx_int_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "limit_zone \"%V\" is too small", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+
+ shm_zone = ngx_shared_memory_add(cf, &value[1], n,
+ &ngx_http_limit_zone_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (shm_zone->data) {
+ ctx = shm_zone->data;
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "limit_zone \"%V\" is already bound to variable \"%V\"",
+ &value[1], &ctx->var);
+ return NGX_CONF_ERROR;
+ }
+
+ shm_zone->init = ngx_http_limit_zone_init_zone;
+ shm_zone->data = ctx;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_limit_zone_conf_t *lzcf = conf;
+
+ ngx_int_t n;
+ ngx_str_t *value;
+
+ value = cf->args->elts;
+
+ lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0,
+ &ngx_http_limit_zone_module);
+ if (lzcf->shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ n = ngx_atoi(value[2].data, value[2].len);
+ if (n <= 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid number of connections \"%V\"", &value[2]);
+ return NGX_CONF_ERROR;
+ }
+
+ lzcf->conn = n;
+
+ return NGX_CONF_OK;
+}
+
+
+static ngx_int_t
+ngx_http_limit_zone_init(ngx_conf_t *cf)
+{
+ ngx_http_handler_pt *h;
+ ngx_http_core_main_conf_t *cmcf;
+
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_http_limit_zone_handler;
+
+ return NGX_OK;
+}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 9083ee82a..63ee8fd80 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2130,7 +2130,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
plcf->upstream.ssl->log = cf->log;
if (ngx_ssl_create(plcf->upstream.ssl,
- NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)
+ NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1, NULL)
!= NGX_OK)
{
return NGX_CONF_ERROR;
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index ab346f9ba..55af30096 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -45,7 +45,16 @@
typedef struct {
- ngx_str_t boundary_header;
+ off_t start;
+ off_t end;
+ ngx_str_t content_range;
+} ngx_http_range_t;
+
+
+typedef struct {
+ off_t offset;
+ ngx_str_t boundary_header;
+ ngx_array_t ranges;
} ngx_http_range_filter_ctx_t;
@@ -159,8 +168,13 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
return ngx_http_next_header_filter(r);
}
- if (ngx_array_init(&r->headers_out.ranges, r->pool, 2,
- sizeof(ngx_http_range_t)) == NGX_ERROR)
+ ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t));
+ if (ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ if (ngx_array_init(&ctx->ranges, r->pool, 1, sizeof(ngx_http_range_t))
+ == NGX_ERROR)
{
return NGX_ERROR;
}
@@ -201,7 +215,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
while (*p == ' ') { p++; }
if (*p == ',' || *p == '\0') {
- range = ngx_array_push(&r->headers_out.ranges);
+ range = ngx_array_push(&ctx->ranges);
if (range == NULL) {
return NGX_ERROR;
}
@@ -247,7 +261,7 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
break;
}
- range = ngx_array_push(&r->headers_out.ranges);
+ range = ngx_array_push(&ctx->ranges);
if (range == NULL) {
return NGX_ERROR;
}
@@ -275,7 +289,6 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
/* rc == NGX_HTTP_RANGE_NOT_SATISFIABLE */
r->headers_out.status = rc;
- r->headers_out.ranges.nelts = 0;
content_range = ngx_list_push(&r->headers_out.headers);
if (content_range == NULL) {
@@ -304,9 +317,11 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
return rc;
}
+ ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
+
r->headers_out.status = NGX_HTTP_PARTIAL_CONTENT;
- if (r->headers_out.ranges.nelts == 1) {
+ if (ctx->ranges.nelts == 1) {
content_range = ngx_list_push(&r->headers_out.headers);
if (content_range == NULL) {
@@ -335,20 +350,17 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
r->headers_out.content_length_n = range->end - range->start;
+ if (r->headers_out.content_length) {
+ r->headers_out.content_length->hash = 0;
+ r->headers_out.content_length = NULL;
+ }
+
return ngx_http_next_header_filter(r);
}
/* TODO: what if no content_type ?? */
- ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_range_filter_ctx_t));
- if (ctx == NULL) {
- return NGX_ERROR;
- }
-
- ngx_http_set_ctx(r, ctx, ngx_http_range_body_filter_module);
-
-
len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
+ sizeof(CRLF "Content-Type: ") - 1
+ r->headers_out.content_type.len
@@ -417,8 +429,8 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
len = sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN + sizeof("--" CRLF) - 1;
- range = r->headers_out.ranges.elts;
- for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+ range = ctx->ranges.elts;
+ for (i = 0; i < ctx->ranges.nelts; i++) {
/* the size of the range: "SSSS-EEEE/TTTT" CRLF CRLF */
@@ -440,7 +452,11 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
}
r->headers_out.content_length_n = len;
- r->headers_out.content_length = NULL;
+
+ if (r->headers_out.content_length) {
+ r->headers_out.content_length->hash = 0;
+ r->headers_out.content_length = NULL;
+ }
return ngx_http_next_header_filter(r);
}
@@ -449,106 +465,105 @@ ngx_http_range_header_filter(ngx_http_request_t *r)
static ngx_int_t
ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
+ off_t start, last;
+ ngx_buf_t *b, *buf;
ngx_uint_t i;
- ngx_buf_t *b;
ngx_chain_t *out, *hcl, *rcl, *dcl, **ll;
ngx_http_range_t *range;
ngx_http_range_filter_ctx_t *ctx;
- if (r->headers_out.ranges.nelts == 0) {
+ if (in == NULL) {
return ngx_http_next_body_filter(r, in);
}
- /*
- * the optimized version for the static files only
- * that are passed in the single file buf
- */
+ ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module);
- if (in && in->buf->in_file && in->buf->last_buf) {
- range = r->headers_out.ranges.elts;
+ if (ctx == NULL) {
+ return ngx_http_next_body_filter(r, in);
+ }
- if (r->headers_out.ranges.nelts == 1) {
- in->buf->file_pos = range->start;
- in->buf->file_last = range->end;
+ buf = in->buf;
- return ngx_http_next_body_filter(r, in);
- }
+ if (ngx_buf_special(in->buf)) {
+ return ngx_http_next_body_filter(r, in);
+ }
- ctx = ngx_http_get_module_ctx(r, ngx_http_range_body_filter_module);
- ll = &out;
+ if (ctx->offset) {
+ goto overlapped;
+ }
- for (i = 0; i < r->headers_out.ranges.nelts; i++) {
+ range = ctx->ranges.elts;
- /*
- * The boundary header of the range:
- * CRLF
- * "--0123456789" CRLF
- * "Content-Type: image/jpeg" CRLF
- * "Content-Range: bytes "
- */
+ if (!buf->last_buf) {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ if (buf->in_file) {
+ start = buf->file_pos + ctx->offset;
+ last = buf->file_last + ctx->offset;
- b->memory = 1;
- b->pos = ctx->boundary_header.data;
- b->last = ctx->boundary_header.data + ctx->boundary_header.len;
+ } else {
+ start = buf->pos - buf->start + ctx->offset;
+ last = buf->last - buf->start + ctx->offset;
+ }
- hcl = ngx_alloc_chain_link(r->pool);
- if (hcl == NULL) {
- return NGX_ERROR;
+ for (i = 0; i < ctx->ranges.nelts; i++) {
+ if (start > range[i].start || last < range[i].end) {
+ goto overlapped;
}
+ }
+ }
- hcl->buf = b;
+ /*
+ * the optimized version for the responses
+ * that are passed in the single buffer
+ */
+ ctx->offset = ngx_buf_size(buf);
- /* "SSSS-EEEE/TTTT" CRLF CRLF */
+ if (ctx->ranges.nelts == 1) {
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ if (buf->in_file) {
+ buf->file_pos = range->start;
+ buf->file_last = range->end;
+ }
- b->temporary = 1;
- b->pos = range[i].content_range.data;
- b->last = range[i].content_range.data + range[i].content_range.len;
+ if (ngx_buf_in_memory(buf)) {
+ buf->pos = buf->start + (size_t) range->start;
+ buf->last = buf->start + (size_t) range->end;
+ }
- rcl = ngx_alloc_chain_link(r->pool);
- if (rcl == NULL) {
- return NGX_ERROR;
- }
+ return ngx_http_next_body_filter(r, in);
+ }
- rcl->buf = b;
+ ll = &out;
+ for (i = 0; i < ctx->ranges.nelts; i++) {
- /* the range data */
+ /*
+ * The boundary header of the range:
+ * CRLF
+ * "--0123456789" CRLF
+ * "Content-Type: image/jpeg" CRLF
+ * "Content-Range: bytes "
+ */
- b = ngx_calloc_buf(r->pool);
- if (b == NULL) {
- return NGX_ERROR;
- }
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
- b->in_file = 1;
- b->file_pos = range[i].start;
- b->file_last = range[i].end;
- b->file = in->buf->file;
+ b->memory = 1;
+ b->pos = ctx->boundary_header.data;
+ b->last = ctx->boundary_header.data + ctx->boundary_header.len;
- dcl = ngx_alloc_chain_link(r->pool);
- if (dcl == NULL) {
- return NGX_ERROR;
- }
+ hcl = ngx_alloc_chain_link(r->pool);
+ if (hcl == NULL) {
+ return NGX_ERROR;
+ }
- dcl->buf = b;
+ hcl->buf = b;
- *ll = hcl;
- hcl->next = rcl;
- rcl->next = dcl;
- ll = &dcl->next;
- }
- /* the last boundary CRLF "--0123456789--" CRLF */
+ /* "SSSS-EEEE/TTTT" CRLF CRLF */
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
@@ -556,34 +571,91 @@ ngx_http_range_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
}
b->temporary = 1;
- b->last_buf = 1;
+ b->pos = range[i].content_range.data;
+ b->last = range[i].content_range.data + range[i].content_range.len;
- b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
- + sizeof("--" CRLF) - 1);
- if (b->pos == NULL) {
+ rcl = ngx_alloc_chain_link(r->pool);
+ if (rcl == NULL) {
return NGX_ERROR;
}
- b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10);
- *b->last++ = '-'; *b->last++ = '-';
- *b->last++ = CR; *b->last++ = LF;
+ rcl->buf = b;
- hcl = ngx_alloc_chain_link(r->pool);
- if (hcl == NULL) {
+
+ /* the range data */
+
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
return NGX_ERROR;
}
- hcl->buf = b;
- hcl->next = NULL;
+ b->in_file = buf->in_file;
+ b->temporary = buf->temporary;
+ b->memory = buf->memory;
+ b->mmap = buf->mmap;
+ b->file = buf->file;
+
+ if (buf->in_file) {
+ buf->file_pos = range[i].start;
+ buf->file_last = range[i].end;
+ }
+
+ if (ngx_buf_in_memory(buf)) {
+ buf->pos = buf->start + (size_t) range[i].start;
+ buf->last = buf->start + (size_t) range[i].end;
+ }
+
+ dcl = ngx_alloc_chain_link(r->pool);
+ if (dcl == NULL) {
+ return NGX_ERROR;
+ }
+
+ dcl->buf = b;
*ll = hcl;
+ hcl->next = rcl;
+ rcl->next = dcl;
+ ll = &dcl->next;
+ }
+
+ /* the last boundary CRLF "--0123456789--" CRLF */
+
+ b = ngx_calloc_buf(r->pool);
+ if (b == NULL) {
+ return NGX_ERROR;
+ }
+
+ b->temporary = 1;
+ b->last_buf = 1;
- return ngx_http_next_body_filter(r, out);
+ b->pos = ngx_palloc(r->pool, sizeof(CRLF "--") - 1 + NGX_ATOMIC_T_LEN
+ + sizeof("--" CRLF) - 1);
+ if (b->pos == NULL) {
+ return NGX_ERROR;
}
- /* TODO: alert */
+ b->last = ngx_cpymem(b->pos, ctx->boundary_header.data, 4 + 10);
+ *b->last++ = '-'; *b->last++ = '-';
+ *b->last++ = CR; *b->last++ = LF;
+
+ hcl = ngx_alloc_chain_link(r->pool);
+ if (hcl == NULL) {
+ return NGX_ERROR;
+ }
+
+ hcl->buf = b;
+ hcl->next = NULL;
+
+ *ll = hcl;
+
+ return ngx_http_next_body_filter(r, out);
+
+overlapped:
+
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
+ "range in overlapped buffers");
- return ngx_http_next_body_filter(r, in);
+ return NGX_ERROR;
}
diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c
index df5859880..91ba695fd 100644
--- a/src/http/modules/ngx_http_realip_module.c
+++ b/src/http/modules/ngx_http_realip_module.c
@@ -103,18 +103,18 @@ ngx_http_realip_handler(ngx_http_request_t *r)
ngx_http_realip_loc_conf_t *rlcf;
if (r->realip_set) {
- return NGX_OK;
+ return NGX_DECLINED;
}
rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module);
if (rlcf->from == NULL) {
- return NGX_OK;
+ return NGX_DECLINED;
}
if (rlcf->xfwd == 0) {
if (r->headers_in.x_real_ip == NULL) {
- return NGX_OK;
+ return NGX_DECLINED;
}
len = r->headers_in.x_real_ip->value.len;
@@ -122,7 +122,7 @@ ngx_http_realip_handler(ngx_http_request_t *r)
} else {
if (r->headers_in.x_forwarded_for == NULL) {
- return NGX_OK;
+ return NGX_DECLINED;
}
len = r->headers_in.x_forwarded_for->value.len;
@@ -158,11 +158,11 @@ ngx_http_realip_handler(ngx_http_request_t *r)
r->realip_set = 1;
- return NGX_OK;
+ return NGX_DECLINED;
}
}
- return NGX_OK;
+ return NGX_DECLINED;
}
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index 30c2d11de..e77e767ec 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -28,6 +28,9 @@ static void *ngx_http_ssl_create_srv_conf(ngx_conf_t *cf);
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child);
+static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+
#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
static char *ngx_http_ssl_nosupported(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -115,6 +118,13 @@ static ngx_command_t ngx_http_ssl_commands[] = {
ngx_http_ssl_nosupported, 0, 0, ngx_http_ssl_openssl097 },
#endif
+ { ngx_string("ssl_session_cache"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12,
+ ngx_http_ssl_session_cache,
+ NGX_HTTP_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -178,7 +188,7 @@ static ngx_http_variable_t ngx_http_ssl_vars[] = {
};
-static u_char ngx_http_session_id_ctx[] = "HTTP";
+static ngx_str_t ngx_http_ssl_sess_id_ctx = ngx_string("HTTP");
static ngx_int_t
@@ -257,35 +267,36 @@ ngx_http_ssl_add_variables(ngx_conf_t *cf)
static void *
ngx_http_ssl_create_srv_conf(ngx_conf_t *cf)
{
- ngx_http_ssl_srv_conf_t *scf;
+ ngx_http_ssl_srv_conf_t *sscf;
- scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
- if (scf == NULL) {
+ sscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_ssl_srv_conf_t));
+ if (sscf == NULL) {
return NGX_CONF_ERROR;
}
/*
* set by ngx_pcalloc():
*
- * scf->protocols = 0;
-
- * scf->certificate.len = 0;
- * scf->certificate.data = NULL;
- * scf->certificate_key.len = 0;
- * scf->certificate_key.data = NULL;
- * scf->client_certificate.len = 0;
- * scf->client_certificate.data = NULL;
- * scf->ciphers.len = 0;
- * scf->ciphers.data = NULL;
+ * sscf->protocols = 0;
+ * sscf->certificate.len = 0;
+ * sscf->certificate.data = NULL;
+ * sscf->certificate_key.len = 0;
+ * sscf->certificate_key.data = NULL;
+ * sscf->client_certificate.len = 0;
+ * sscf->client_certificate.data = NULL;
+ * sscf->ciphers.len = 0;
+ * sscf->ciphers.data = NULL;
+ * sscf->shm_zone = NULL;
*/
- scf->enable = NGX_CONF_UNSET;
- scf->session_timeout = NGX_CONF_UNSET;
- scf->verify = NGX_CONF_UNSET;
- scf->verify_depth = NGX_CONF_UNSET;
- scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ sscf->enable = NGX_CONF_UNSET;
+ sscf->verify = NGX_CONF_UNSET;
+ sscf->verify_depth = NGX_CONF_UNSET;
+ sscf->prefer_server_ciphers = NGX_CONF_UNSET;
+ sscf->builtin_session_cache = NGX_CONF_UNSET;
+ sscf->session_timeout = NGX_CONF_UNSET;
- return scf;
+ return sscf;
}
@@ -330,7 +341,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
conf->ssl.log = cf->log;
- if (ngx_ssl_create(&conf->ssl, conf->protocols) != NGX_OK) {
+ if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -343,7 +354,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
cln->data = &conf->ssl;
if (ngx_ssl_certificate(cf, &conf->ssl, &conf->certificate,
- &conf->certificate_key) != NGX_OK)
+ &conf->certificate_key)
+ != NGX_OK)
{
return NGX_CONF_ERROR;
}
@@ -359,7 +371,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
if (conf->verify) {
if (ngx_ssl_client_certificate(cf, &conf->ssl,
- &conf->client_certificate, conf->verify_depth)
+ &conf->client_certificate,
+ conf->verify_depth)
!= NGX_OK)
{
return NGX_CONF_ERROR;
@@ -379,14 +392,123 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- SSL_CTX_set_session_cache_mode(conf->ssl.ctx, SSL_SESS_CACHE_SERVER);
+ ngx_conf_merge_value(conf->builtin_session_cache,
+ prev->builtin_session_cache,
+ NGX_SSL_DFLT_BUILTIN_SCACHE);
+
+ if (conf->shm_zone == NULL) {
+ conf->shm_zone = prev->shm_zone;
+ }
+
+ if (ngx_ssl_session_cache(&conf->ssl, &ngx_http_ssl_sess_id_ctx,
+ conf->builtin_session_cache,
+ conf->shm_zone, conf->session_timeout)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_ssl_srv_conf_t *sscf = conf;
+
+ size_t len;
+ ngx_str_t *value, name, size;
+ ngx_int_t n;
+ ngx_uint_t i, j;
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strcmp(value[i].data, "builtin") == 0) {
+ sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
+ continue;
+ }
+
+ if (value[i].len > sizeof("builtin:") - 1
+ && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
+ == 0)
+ {
+ n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
+ value[i].len - (sizeof("builtin:") - 1));
+
+ if (n == NGX_ERROR) {
+ goto invalid;
+ }
+
+ sscf->builtin_session_cache = n;
+
+ continue;
+ }
+
+ if (value[i].len > sizeof("shared:") - 1
+ && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
+ == 0)
+ {
+ len = 0;
+
+ for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
+ if (value[i].data[j] == ':') {
+ break;
+ }
+
+ len++;
+ }
+
+ if (len == 0) {
+ goto invalid;
+ }
+
+ name.len = len;
+ name.data = value[i].data + sizeof("shared:") - 1;
+
+ size.len = value[i].len - j - 1;
+ size.data = name.data + len + 1;
+
+ n = ngx_parse_size(&size);
+
+ if (n == NGX_ERROR) {
+ goto invalid;
+ }
- SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_http_session_id_ctx,
- sizeof(ngx_http_session_id_ctx) - 1);
+ if (n < (ngx_int_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "session cache \"%V\" is too small",
+ &value[i]);
- SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout);
+ return NGX_CONF_ERROR;
+ }
+
+ sscf->shm_zone = ngx_shared_memory_add(cf, &name, n,
+ &ngx_http_ssl_module);
+ if (sscf->shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ goto invalid;
+ }
+
+ if (sscf->shm_zone && sscf->builtin_session_cache == NGX_CONF_UNSET) {
+ sscf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
+ }
return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid session cache \"%V\"", &value[i]);
+
+ return NGX_CONF_ERROR;
}
diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h
index 85803096e..1ef1ffe0f 100644
--- a/src/http/modules/ngx_http_ssl_module.h
+++ b/src/http/modules/ngx_http_ssl_module.h
@@ -14,24 +14,28 @@
typedef struct {
- ngx_flag_t enable;
+ ngx_flag_t enable;
- ngx_ssl_t ssl;
+ ngx_ssl_t ssl;
- ngx_flag_t prefer_server_ciphers;
+ ngx_flag_t prefer_server_ciphers;
- ngx_uint_t protocols;
+ ngx_uint_t protocols;
- ngx_int_t verify;
- ngx_int_t verify_depth;
+ ngx_int_t verify;
+ ngx_int_t verify_depth;
- time_t session_timeout;
+ ssize_t builtin_session_cache;
- ngx_str_t certificate;
- ngx_str_t certificate_key;
- ngx_str_t client_certificate;
+ time_t session_timeout;
- ngx_str_t ciphers;
+ ngx_str_t certificate;
+ ngx_str_t certificate_key;
+ ngx_str_t client_certificate;
+
+ ngx_str_t ciphers;
+
+ ngx_shm_zone_t *shm_zone;
} ngx_http_ssl_srv_conf_t;
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index 80c817d81..48018053c 100644
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
HTTP_INSUFFICIENT_STORAGE
);
-our $VERSION = '0.5.5';
+our $VERSION = '0.5.6';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index f6dcd6a56..74ca4b841 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -976,10 +976,10 @@ ngx_http_read_request_header(ngx_http_request_t *r)
}
if (n == 0 || n == NGX_ERROR) {
- c->error = rev->error;
- c->log->action = "sending response to client";
+ c->error = 1;
+ c->log->action = "reading client request headers";
- ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
return NGX_ERROR;
}
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 9df5bd2ff..5cdcb9498 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -215,13 +215,6 @@ typedef struct {
typedef struct {
- off_t start;
- off_t end;
- ngx_str_t content_range;
-} ngx_http_range_t;
-
-
-typedef struct {
ngx_list_t headers;
ngx_uint_t status;
@@ -245,7 +238,6 @@ typedef struct {
ngx_str_t content_type;
ngx_str_t charset;
- ngx_array_t ranges;
ngx_array_t cache_control;
off_t content_length_n;
@@ -438,6 +430,12 @@ struct ngx_http_request_s {
#endif
+ /*
+ * instead of using the request context data in ngx_http_limit_zone_module
+ * we use the single bit in the request structure
+ */
+ unsigned limit_zone_set:1;
+
#if 0
unsigned cachable:1;
#endif
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
index 0f7d84b10..5d952217b 100644
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -53,7 +53,7 @@ typedef struct {
typedef struct {
ngx_http_upstream_rr_peers_t *peers;
ngx_uint_t current;
- uintptr_t *tried;
+ uintptr_t *tried;
uintptr_t data;
} ngx_http_upstream_rr_peer_data_t;
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index ab43638f6..ac4a4a2f8 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -28,6 +28,8 @@ static ngx_int_t ngx_http_variable_unknown_header(ngx_http_variable_value_t *v,
static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_remote_port(ngx_http_request_t *r,
@@ -115,6 +117,9 @@ static ngx_http_variable_t ngx_http_core_variables[] = {
{ ngx_string("host"), NULL, ngx_http_variable_host, 0, 0, 0 },
+ { ngx_string("binary_remote_addr"), NULL,
+ ngx_http_variable_binary_remote_addr, 0, 0, 0 },
+
{ ngx_string("remote_addr"), NULL, ngx_http_variable_remote_addr, 0, 0, 0 },
{ ngx_string("remote_port"), NULL, ngx_http_variable_remote_port, 0, 0, 0 },
@@ -696,6 +701,26 @@ ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
static ngx_int_t
+ngx_http_variable_binary_remote_addr(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data)
+{
+ struct sockaddr_in *sin;
+
+ /* AF_INET only */
+
+ sin = (struct sockaddr_in *) r->connection->sockaddr;
+
+ v->len = sizeof(in_addr_t);
+ v->valid = 1;
+ v->no_cachable = 0;
+ v->not_found = 0;
+ v->data = (u_char *) &sin->sin_addr.s_addr;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_remote_addr(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c
index cb2b8caf5..ac4a08629 100644
--- a/src/imap/ngx_imap_ssl_module.c
+++ b/src/imap/ngx_imap_ssl_module.c
@@ -16,6 +16,8 @@
static void *ngx_imap_ssl_create_conf(ngx_conf_t *cf);
static char *ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child);
+static char *ngx_imap_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
@@ -99,6 +101,13 @@ static ngx_command_t ngx_imap_ssl_commands[] = {
ngx_imap_ssl_nosupported, 0, 0, ngx_imap_ssl_openssl097 },
#endif
+ { ngx_string("ssl_session_cache"),
+ NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE12,
+ ngx_imap_ssl_session_cache,
+ NGX_IMAP_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("ssl_session_timeout"),
NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_sec_slot,
@@ -135,7 +144,7 @@ ngx_module_t ngx_imap_ssl_module = {
};
-static u_char ngx_imap_session_id_ctx[] = "IMAP";
+static ngx_str_t ngx_imap_ssl_sess_id_ctx = ngx_string("IMAP");
static void *
@@ -152,19 +161,20 @@ ngx_imap_ssl_create_conf(ngx_conf_t *cf)
* set by ngx_pcalloc():
*
* scf->protocols = 0;
- *
* scf->certificate.len = 0;
* scf->certificate.data = NULL;
* scf->certificate_key.len = 0;
* scf->certificate_key.data = NULL;
* scf->ciphers.len = 0;
* scf->ciphers.data = NULL;
+ * scf->shm_zone = NULL;
*/
scf->enable = NGX_CONF_UNSET;
scf->starttls = NGX_CONF_UNSET;
- scf->session_timeout = NGX_CONF_UNSET;
scf->prefer_server_ciphers = NGX_CONF_UNSET;
+ scf->builtin_session_cache = NGX_CONF_UNSET;
+ scf->session_timeout = NGX_CONF_UNSET;
return scf;
}
@@ -206,7 +216,7 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
conf->ssl.log = cf->log;
- if (ngx_ssl_create(&conf->ssl, conf->protocols) != NGX_OK) {
+ if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) {
return NGX_CONF_ERROR;
}
@@ -248,17 +258,126 @@ ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child)
return NGX_CONF_ERROR;
}
- SSL_CTX_set_session_cache_mode(conf->ssl.ctx, SSL_SESS_CACHE_SERVER);
+ ngx_conf_merge_value(conf->builtin_session_cache,
+ prev->builtin_session_cache,
+ NGX_SSL_DFLT_BUILTIN_SCACHE);
- SSL_CTX_set_session_id_context(conf->ssl.ctx, ngx_imap_session_id_ctx,
- sizeof(ngx_imap_session_id_ctx) - 1);
+ if (conf->shm_zone == NULL) {
+ conf->shm_zone = prev->shm_zone;
+ }
- SSL_CTX_set_timeout(conf->ssl.ctx, conf->session_timeout);
+ if (ngx_ssl_session_cache(&conf->ssl, &ngx_imap_ssl_sess_id_ctx,
+ conf->builtin_session_cache,
+ conf->shm_zone, conf->session_timeout)
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
return NGX_CONF_OK;
}
+static char *
+ngx_imap_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_imap_ssl_conf_t *scf = conf;
+
+ size_t len;
+ ngx_str_t *value, name, size;
+ ngx_int_t n;
+ ngx_uint_t i, j;
+
+ value = cf->args->elts;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strcmp(value[i].data, "builtin") == 0) {
+ scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE;
+ continue;
+ }
+
+ if (value[i].len > sizeof("builtin:") - 1
+ && ngx_strncmp(value[i].data, "builtin:", sizeof("builtin:") - 1)
+ == 0)
+ {
+ n = ngx_atoi(value[i].data + sizeof("builtin:") - 1,
+ value[i].len - (sizeof("builtin:") - 1));
+
+ if (n == NGX_ERROR) {
+ goto invalid;
+ }
+
+ scf->builtin_session_cache = n;
+
+ continue;
+ }
+
+ if (value[i].len > sizeof("shared:") - 1
+ && ngx_strncmp(value[i].data, "shared:", sizeof("shared:") - 1)
+ == 0)
+ {
+ len = 0;
+
+ for (j = sizeof("shared:") - 1; j < value[i].len; j++) {
+ if (value[i].data[j] == ':') {
+ break;
+ }
+
+ len++;
+ }
+
+ if (len == 0) {
+ goto invalid;
+ }
+
+ name.len = len;
+ name.data = value[i].data + sizeof("shared:") - 1;
+
+ size.len = value[i].len - j - 1;
+ size.data = name.data + len + 1;
+
+ n = ngx_parse_size(&size);
+
+ if (n == NGX_ERROR) {
+ goto invalid;
+ }
+
+ if (n < (ngx_int_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "session cache \"%V\" is too small",
+ &value[i]);
+
+ return NGX_CONF_ERROR;
+ }
+
+ scf->shm_zone = ngx_shared_memory_add(cf, &name, n,
+ &ngx_imap_ssl_module);
+ if (scf->shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ goto invalid;
+ }
+
+ if (scf->shm_zone && scf->builtin_session_cache == NGX_CONF_UNSET) {
+ scf->builtin_session_cache = NGX_SSL_NO_BUILTIN_SCACHE;
+ }
+
+ return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid session cache \"%V\"", &value[i]);
+
+ return NGX_CONF_ERROR;
+}
+
+
#if !defined (SSL_OP_CIPHER_SERVER_PREFERENCE)
static char *
diff --git a/src/imap/ngx_imap_ssl_module.h b/src/imap/ngx_imap_ssl_module.h
index 7b05bce5c..8ab8af287 100644
--- a/src/imap/ngx_imap_ssl_module.h
+++ b/src/imap/ngx_imap_ssl_module.h
@@ -19,22 +19,25 @@
typedef struct {
- ngx_flag_t enable;
+ ngx_flag_t enable;
- ngx_ssl_t ssl;
+ ngx_ssl_t ssl;
- ngx_flag_t prefer_server_ciphers;
- ngx_flag_t starttls;
+ ngx_flag_t prefer_server_ciphers;
+ ngx_flag_t starttls;
- ngx_uint_t protocols;
+ ngx_uint_t protocols;
- time_t session_timeout;
+ ssize_t builtin_session_cache;
- ngx_str_t certificate;
- ngx_str_t certificate_key;
+ time_t session_timeout;
- ngx_str_t ciphers;
+ ngx_str_t certificate;
+ ngx_str_t certificate_key;
+ ngx_str_t ciphers;
+
+ ngx_shm_zone_t *shm_zone;
} ngx_imap_ssl_conf_t;
diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c
index 195d64d81..3a013a0bf 100644
--- a/src/os/unix/ngx_linux_init.c
+++ b/src/os/unix/ngx_linux_init.c
@@ -13,7 +13,7 @@ static ngx_int_t ngx_linux_procfs(char *name, char *buf, size_t len,
char ngx_linux_kern_ostype[50];
-char ngx_linux_kern_osrelease[20];
+char ngx_linux_kern_osrelease[50];
int ngx_linux_rtsig_max;