# HG changeset patch # User Igor Sysoev # Date 1168808400 -10800 # Node ID 052a7b1d40e5431ee281c89dfbd8d1c83588d081 # Parent 60df8db42ffbc879f51d7e0c39299d0e11620770 nginx 0.5.7 *) Feature: the ssl_session_cache storage optimization. *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives. *) Bugfix: the segmentation fault was occurred on start or while reconfiguration if the "ssl_session_cache" or "limit_zone" directives were used on 64-bit platforms. *) Bugfix: a segmentation fault occurred if the "add_before_body" or "add_after_body" directives were used and there was no "Content-Type" header line in response. *) Bugfix: the OpenSSL library was always built with the threads support. Thanks to Den Ivanov. *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,25 @@ +Changes with nginx 0.5.7 15 Jan 2007 + + *) Feature: the ssl_session_cache storage optimization. + + *) Bugfixes in the "ssl_session_cache" and "limit_zone" directives. + + *) Bugfix: the segmentation fault was occurred on start or while + reconfiguration if the "ssl_session_cache" or "limit_zone" + directives were used on 64-bit platforms. + + *) Bugfix: a segmentation fault occurred if the "add_before_body" or + "add_after_body" directives were used and there was no + "Content-Type" header line in response. + + *) Bugfix: the OpenSSL library was always built with the threads + support. + Thanks to Den Ivanov. + + *) Bugfix: the PCRE-6.5+ library and the icc compiler compatibility. + + Changes with nginx 0.5.6 09 Jan 2007 *) Change: now the ngx_http_index_module ignores all methods except the diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,25 @@ +Изменения в nginx 0.5.7 15.01.2007 + + *) Добавление: оптимизация использования памяти в ssl_session_cache. + + *) Исправление ошибок в директивах ssl_session_cache и limit_zone. + + *) Исправление: на старте или во время переконфигурации происходил + segmentation fault, если директивы ssl_session_cache или limit_zone + использовались на 64-битных платформах. + + *) Исправление: при использовании директив add_before_body или + add_after_body происходил segmentation fault, если в заголовке + ответа нет строки "Content-Type". + + *) Исправление: библиотека OpenSSL всегда собирался с поддержкой + потоков. + Спасибо Дену Иванову. + + *) Исправление: совместимость библиотеки PCRE-6.5+ и компилятора icc. + + Изменения в nginx 0.5.6 09.01.2007 *) Изменение: теперь модуль ngx_http_index_module игнорирует все diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -147,7 +147,7 @@ fi # warnings # -W requires at least -O -CFLAGS="$CFLAGS ${NGX_GCC_OPT:-O} -W" +CFLAGS="$CFLAGS ${NGX_GCC_OPT:--O} -W" CFLAGS="$CFLAGS -Wall -Wpointer-arith" #CFLAGS="$CFLAGS -Wconversion" diff --git a/auto/lib/openssl/make b/auto/lib/openssl/make --- a/auto/lib/openssl/make +++ b/auto/lib/openssl/make @@ -8,9 +8,10 @@ else NGX_OPENSSL_CONFIG="./config" fi -if test -n "$USE_THREADS"; then - NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" -fi +case $USE_THREADS in + NO) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG no-threads" ;; + *) NGX_OPENSSL_CONFIG="$NGX_OPENSSL_CONFIG threads" ;; +esac case "$NGX_PLATFORM" in *) diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -25,14 +25,24 @@ if [ $PCRE != NONE ]; then echo $ngx_n "checking for PCRE library ...$ngx_c" - ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ - | sed -e 's/^.*=\(.*\)$/\1/'` + if [ -e $PCRE/pcre.h ]; then + ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \ + | sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'` + + else + ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ + | sed -e 's/^.*=\(.*\)$/\1/'` + fi echo " $ngx_pcre_ver major version found" # to allow -ipo optimization we link with the *.o but not library case "$ngx_pcre_ver" in + 4|5) + CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" + ;; + 6) CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" @@ -44,8 +54,16 @@ if [ $PCRE != NONE ]; then ;; *) - CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_newline.o" ;; + esac ;; diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -6,6 +6,7 @@ types { image/gif gif; image/jpeg jpeg jpg; application/x-javascript js; + application/atom+xml atom; text/mathml mml; text/plain txt; diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.5.6" +#define NGINX_VERSION "0.5.7" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_crc32.c b/src/core/ngx_crc32.c --- a/src/core/ngx_crc32.c +++ b/src/core/ngx_crc32.c @@ -13,11 +13,11 @@ * described at http://www.w3.org/TR/PNG/ * * The 256 element lookup table takes 1024 bytes, and it may be completely - * cached after processing about 30-60 bytes. So for short messages + * cached after processing about 30-60 bytes of data. So for short data * we use the 16 element lookup table that takes only 64 bytes and align it * to CPU cache line size. Of course, the small table adds code inside - * CRC32 cycle, but cache misses overhead is bigger than overhead of - * the additional code. For example, ngx_crc32_short() of 16 byte message + * CRC32 loop, but the cache misses overhead is bigger than overhead of + * the additional code. For example, ngx_crc32_short() of 16 bytes of data * takes half as much CPU clocks than ngx_crc32_long(). */ diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -373,6 +373,11 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) goto failed; } + if (shm_zone[i].init == NULL) { + /* unused shared zone */ + continue; + } + shm_zone[i].shm.log = cycle->log; opart = &old_cycle->shared_memory.part; diff --git a/src/core/ngx_rbtree.c b/src/core/ngx_rbtree.c --- a/src/core/ngx_rbtree.c +++ b/src/core/ngx_rbtree.c @@ -13,12 +13,6 @@ * the "Introduction to Algorithms" by Cormen, Leiserson and Rivest. */ -#define ngx_rbt_red(node) ((node)->color = 1) -#define ngx_rbt_black(node) ((node)->color = 0) -#define ngx_rbt_is_red(node) ((node)->color) -#define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node)) -#define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color) - static ngx_inline void ngx_rbtree_left_rotate(ngx_rbtree_node_t **root, ngx_rbtree_node_t *sentinel, ngx_rbtree_node_t *node); diff --git a/src/core/ngx_rbtree.h b/src/core/ngx_rbtree.h --- a/src/core/ngx_rbtree.h +++ b/src/core/ngx_rbtree.h @@ -50,9 +50,16 @@ void ngx_rbtree_insert_timer_value(ngx_r ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +#define ngx_rbt_red(node) ((node)->color = 1) +#define ngx_rbt_black(node) ((node)->color = 0) +#define ngx_rbt_is_red(node) ((node)->color) +#define ngx_rbt_is_black(node) (!ngx_rbt_is_red(node)) +#define ngx_rbt_copy_color(n1, n2) (n1->color = n2->color) + + /* a sentinel must be black */ -#define ngx_rbtree_sentinel_init(node) node->color = 0 +#define ngx_rbtree_sentinel_init(node) ngx_rbt_black(node) static ngx_inline ngx_rbtree_node_t * diff --git a/src/core/ngx_shmtx.h b/src/core/ngx_shmtx.h --- a/src/core/ngx_shmtx.h +++ b/src/core/ngx_shmtx.h @@ -30,11 +30,7 @@ ngx_int_t ngx_shmtx_create(ngx_shmtx_t * static ngx_inline ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx) { - if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) { - return 1; - } - - return 0; + return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)); } #define ngx_shmtx_lock(mtx) ngx_spinlock((mtx)->lock, ngx_pid, 1024) diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -128,7 +128,7 @@ ngx_slab_init(ngx_slab_pool_t *pool) pool->pages->prev = (uintptr_t) &pool->free; pool->start = (u_char *) - ngx_align((uintptr_t) p + pages * sizeof(ngx_slab_page_t), + ngx_align_ptr((uintptr_t) p + pages * sizeof(ngx_slab_page_t), ngx_pagesize); m = pages - (pool->end - pool->start) / ngx_pagesize; @@ -295,7 +295,7 @@ ngx_slab_alloc_locked(ngx_slab_pool_t *p n = ngx_pagesize_shift - (page->slab & NGX_SLAB_SHIFT_MASK); n = 1 << n; - n = (1 << n) - 1; + n = ((uintptr_t) 1 << n) - 1; mask = n << NGX_SLAB_MAP_SHIFT; do { @@ -421,8 +421,8 @@ 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; + uintptr_t slab, m, *bitmap; + ngx_uint_t n, type, slot, shift, map; ngx_slab_page_t *slots, *page; ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, ngx_cycle->log, 0, "slab free: %p", p); @@ -450,7 +450,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po } n = ((uintptr_t) p & (ngx_pagesize - 1)) >> shift; - m = 1 << (n & (sizeof(uintptr_t) * 8 - 1)); + m = (uintptr_t) 1 << (n & (sizeof(uintptr_t) * 8 - 1)); n /= (sizeof(uintptr_t) * 8); bitmap = (uintptr_t *) ((uintptr_t) p & ~(ngx_pagesize - 1)); @@ -476,7 +476,7 @@ ngx_slab_free_locked(ngx_slab_pool_t *po n = 1; } - if (bitmap[0] & ~((1 << n) - 1)) { + if (bitmap[0] & ~(((uintptr_t) 1 << n) - 1)) { goto done; } @@ -497,7 +497,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *po case NGX_SLAB_EXACT: - m = 1 << (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift); + m = (uintptr_t) 1 << + (((uintptr_t) p & (ngx_pagesize - 1)) >> ngx_slab_exact_shift); size = ngx_slab_exact_size; if ((uintptr_t) p & (size - 1)) { @@ -539,8 +540,8 @@ ngx_slab_free_locked(ngx_slab_pool_t *po goto wrong_chunk; } - m = 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift) - + NGX_SLAB_MAP_SHIFT); + m = (uintptr_t) 1 << ((((uintptr_t) p & (ngx_pagesize - 1)) >> shift) + + NGX_SLAB_MAP_SHIFT); if (slab & m) { diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -487,6 +487,31 @@ ngx_rstrncasecmp(u_char *s1, u_char *s2, ngx_int_t +ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2) +{ + size_t n; + ngx_int_t m, z; + + if (n1 <= n2) { + n = n1; + z = -1; + + } else { + n = n2; + z = 1; + } + + m = ngx_memcmp(s1, s2, n); + + if (m || n1 == n2) { + return m; + } + + return z; +} + + +ngx_int_t ngx_atoi(u_char *line, size_t n) { ngx_int_t value; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -130,6 +130,7 @@ u_char *ngx_vsnprintf(u_char *buf, size_ ngx_int_t ngx_rstrncmp(u_char *s1, u_char *s2, size_t n); ngx_int_t ngx_rstrncasecmp(u_char *s1, u_char *s2, size_t n); +ngx_int_t ngx_memn2cmp(u_char *s1, u_char *s2, size_t n1, size_t n2); ngx_int_t ngx_atoi(u_char *line, size_t n); ssize_t ngx_atosz(u_char *line, size_t n); diff --git a/src/event/modules/ngx_aio_module.c b/src/event/modules/ngx_aio_module.c --- a/src/event/modules/ngx_aio_module.c +++ b/src/event/modules/ngx_aio_module.c @@ -166,61 +166,3 @@ ngx_aio_process_events(ngx_cycle_t *cycl } #endif /* NGX_HAVE_KQUEUE */ - - -#if 0 - -/* 1 */ -int ngx_posix_aio_process_events(ngx_log_t *log) -{ - listen via SIGIO; - aio_* via SIGxxx; - - sigsuspend()/sigwaitinfo()/sigtimedwait(); -} - -/* 2 */ -int ngx_posix_aio_process_events(ngx_log_t *log) -{ - unmask signal - - listen via SIGIO; - - /* BUG: SIGIO can be delivered before aio_*() */ - - aio_suspend()/aiowait()/aio_waitcomplete() with timeout - - mask signal - - if (ngx_socket_errno == NGX_EINTR) - look listen - select()/accept() nb listen sockets - else - aio -} - -/* 3 */ -int ngx_posix_aio_process_events(ngx_log_t *log) -{ -#if 0 - unmask signal - - /* BUG: AIO signal can be delivered before select() */ - - select(listen); - - mask signal -#endif - - pselect(listen, mask); - - if (ngx_socket_errno == NGX_EINTR) - look ready array -} - -void aio_sig_handler(int signo, siginfo_t *siginfo, void *context) -{ - push siginfo->si_value.sival_ptr -} - -#endif diff --git a/src/event/modules/ngx_aio_module.h b/src/event/modules/ngx_aio_module.h deleted file mode 100644 --- a/src/event/modules/ngx_aio_module.h +++ /dev/null @@ -1,20 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_AIO_MODULE_H_INCLUDED_ -#define _NGX_AIO_MODULE_H_INCLUDED_ - - -#include -#include -#include - - -int ngx_aio_init(int max_connections, ngx_log_t *log); -int ngx_aio_process_events(ngx_log_t *log); - - -#endif /* _NGX_AIO_MODULE_H_INCLUDED_ */ diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -32,6 +32,8 @@ static ngx_ssl_session_t *ngx_ssl_get_ca 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_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static void *ngx_openssl_create_conf(ngx_cycle_t *cycle); static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf); @@ -1160,10 +1162,10 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng 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); } + SSL_CTX_set_timeout(ssl->ctx, timeout); + if (shm_zone) { shm_zone->init = ngx_ssl_session_cache_init; @@ -1223,7 +1225,7 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ cache->session_rbtree->root = sentinel; cache->session_rbtree->sentinel = sentinel; - cache->session_rbtree->insert = ngx_rbtree_insert_value; + cache->session_rbtree->insert = ngx_ssl_session_rbtree_insert_value; shm_zone->data = cache; @@ -1232,6 +1234,18 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ /* + * The length of the session id is 16 bytes for SSLv2 sessions and + * between 1 and 32 bytes for SSLv3/TLSv1, typically 32 bytes. + * It seems that the typical length of the external ASN1 representation + * of a session is 118 or 119 bytes for SSLv3/TSLv1. + * + * Thus on 32-bit platforms we allocate separately an rbtree node, + * a session id, and an ASN1 representation, they take accordingly + * 64, 32, and 128 bytes. + * + * On 64-bit platforms we allocate separately an rbtree node + session_id, + * and an ASN1 representation, they take accordingly 128 and 128 bytes. + * * OpenSSL's i2d_SSL_SESSION() and d2i_SSL_SESSION are slow, * so they are outside the code locked by shared pool mutex */ @@ -1240,7 +1254,7 @@ static int ngx_ssl_new_session(ngx_ssl_conn_t *ssl_conn, ngx_ssl_session_t *sess) { int len; - u_char *p, *id; + u_char *p, *id, *cached_sess; uint32_t hash; SSL_CTX *ssl_ctx; ngx_time_t *tp; @@ -1248,7 +1262,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ 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]; @@ -1276,8 +1289,7 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ /* 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); + cached_sess = ngx_slab_alloc_locked(shpool, len); if (cached_sess == NULL) { @@ -1285,26 +1297,33 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ ngx_ssl_expire_sessions(cache, shpool, 0); - cached_sess = ngx_slab_alloc_locked(shpool, - offsetof(ngx_ssl_cached_sess_t, asn1) + len); + cached_sess = ngx_slab_alloc_locked(shpool, len); if (cached_sess == NULL) { - id = NULL; + sess_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); +#if (NGX_PTR_SIZE == 8) + + id = sess_id->sess_id; + +#else + + id = ngx_slab_alloc_locked(shpool, sess->session_id_length); + if (id == NULL) { + goto failed; + } + +#endif + + ngx_memcpy(cached_sess, buf, len); ngx_memcpy(id, sess->session_id, sess->session_id_length); @@ -1314,21 +1333,20 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ "http ssl new session: %08XD:%d:%d", hash, sess->session_id_length, len); + tp = ngx_timeofday(); + 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; + sess_id->expire = tp->sec + SSL_CTX_get_timeout(ssl_ctx); + + sess_id->next = cache->session_cache_head.next; + sess_id->next->prev = sess_id; + sess_id->prev = &cache->session_cache_head; + cache->session_cache_head.next = sess_id; ngx_rbtree_insert(cache->session_rbtree, &sess_id->node); @@ -1342,8 +1360,8 @@ failed: ngx_slab_free_locked(shpool, cached_sess); } - if (id) { - ngx_slab_free_locked(shpool, id); + if (sess_id) { + ngx_slab_free_locked(shpool, sess_id); } ngx_shmtx_unlock(&shpool->mutex); @@ -1364,6 +1382,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ #endif u_char *p; uint32_t hash; + ngx_int_t rc; ngx_time_t *tp; ngx_shm_zone_t *shm_zone; ngx_slab_pool_t *shpool; @@ -1371,13 +1390,12 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ 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); + hash = ngx_crc32_short(id, (size_t) len); *copy = 0; ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, @@ -1413,17 +1431,19 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ continue; } - if (hash == node->key && (u_char) len == node->data) { + /* hash == node->key */ + + do { sess_id = (ngx_ssl_sess_id_t *) node; - if (ngx_strncmp(id, sess_id->id, len) == 0) { - - cached_sess = sess_id->session; + rc = ngx_memn2cmp(id, sess_id->id, + (size_t) len, (size_t) node->data); + if (rc == 0) { tp = ngx_timeofday(); - if (cached_sess->expire > tp->sec) { - ngx_memcpy(buf, &cached_sess->asn1[0], sess_id->len); + if (sess_id->expire > tp->sec) { + ngx_memcpy(buf, sess_id->session, sess_id->len); ngx_shmtx_unlock(&shpool->mutex); @@ -1433,24 +1453,31 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ return sess; } - cached_sess->next->prev = cached_sess->prev; - cached_sess->prev->next = cached_sess->next; + sess_id->next->prev = sess_id->prev; + sess_id->prev->next = sess_id->next; ngx_rbtree_delete(cache->session_rbtree, node); - ngx_slab_free_locked(shpool, cached_sess); + ngx_slab_free_locked(shpool, sess_id->session); +#if (NGX_PTR_SIZE == 4) ngx_slab_free_locked(shpool, sess_id->id); +#endif ngx_slab_free_locked(shpool, sess_id); sess = NULL; - break; + goto done; } - } - - node = node->right; + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; } +done: + ngx_shmtx_unlock(&shpool->mutex); return sess; @@ -1460,13 +1487,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ static void ngx_ssl_remove_session(SSL_CTX *ssl, ngx_ssl_session_t *sess) { - u_char *id, len; + size_t len; + u_char *id; uint32_t hash; + ngx_int_t rc; 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); @@ -1474,12 +1502,12 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx cache = shm_zone->data; id = sess->session_id; - len = (u_char) sess->session_id_length; - - hash = ngx_crc32_short(id, (size_t) len); + len = (size_t) sess->session_id_length; + + hash = ngx_crc32_short(id, len); ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, - "http ssl remove session: %08XD:%d", hash, len); + "http ssl remove session: %08XD:%uz", hash, len); shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; @@ -1500,29 +1528,37 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx continue; } - if (hash == node->key && len == node->data) { + /* hash == node->key */ + + do { 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; + rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data); + + if (rc == 0) { + sess_id->next->prev = sess_id->prev; + sess_id->prev->next = sess_id->next; ngx_rbtree_delete(cache->session_rbtree, node); - ngx_slab_free_locked(shpool, cached_sess); + ngx_slab_free_locked(shpool, sess_id->session); +#if (NGX_PTR_SIZE == 4) ngx_slab_free_locked(shpool, sess_id->id); +#endif ngx_slab_free_locked(shpool, sess_id); - break; + goto done; } - } - - node = node->right; + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; } +done: + ngx_shmtx_unlock(&shpool->mutex); } @@ -1531,41 +1567,101 @@ 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; + ngx_time_t *tp; + ngx_ssl_sess_id_t *sess_id; tp = ngx_timeofday(); while (n < 3) { - sess = cache->session_cache_tail.prev; - - if (sess == &cache->session_cache_head) { + sess_id = cache->session_cache_tail.prev; + + if (sess_id == &cache->session_cache_head) { return; } - if (n++ != 0 && sess->expire > tp->sec) { + if (n++ != 0 && sess_id->expire > tp->sec) { break; } - sess->next->prev = sess->prev; - sess->prev->next = sess->next; - - sess_id = sess->sess_id; + sess_id->next->prev = sess_id->prev; + sess_id->prev->next = sess_id->next; 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->session); +#if (NGX_PTR_SIZE == 4) ngx_slab_free_locked(shpool, sess_id->id); +#endif ngx_slab_free_locked(shpool, sess_id); } } +static void +ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_ssl_sess_id_t *sess_id, *sess_id_temp; + + for ( ;; ) { + + if (node->key < temp->key) { + + if (temp->left == sentinel) { + temp->left = node; + break; + } + + temp = temp->left; + + } else if (node->key > temp->key) { + + if (temp->right == sentinel) { + temp->right = node; + break; + } + + temp = temp->right; + + } else { /* node->key == temp->key */ + + sess_id = (ngx_ssl_sess_id_t *) node; + sess_id_temp = (ngx_ssl_sess_id_t *) temp; + + if (ngx_memn2cmp(sess_id->id, sess_id_temp->id, + (size_t) node->data, (size_t) temp->data) + < 0) + { + if (temp->left == sentinel) { + temp->left = node; + break; + } + + temp = temp->left; + + } else { + + if (temp->right == sentinel) { + temp->right = node; + break; + } + + temp = temp->right; + } + } + } + + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + void ngx_ssl_cleanup_ctx(void *data) { diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -55,33 +55,29 @@ typedef struct { #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) -#define NGX_SSL_MAX_SESSION_SIZE (4096 - offsetof(ngx_ssl_cached_sess_t, asn1)) +typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t; - -typedef struct { +struct ngx_ssl_sess_id_s { 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; + u_char *session; + ngx_ssl_sess_id_t *prev; + ngx_ssl_sess_id_t *next; time_t expire; - ngx_ssl_sess_id_t *sess_id; - u_char asn1[1]; +#if (NGX_PTR_SIZE == 8) + void *stub; + u_char sess_id[32]; +#endif }; 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_sess_id_t session_cache_head; + ngx_ssl_sess_id_t session_cache_tail; } ngx_ssl_session_cache_t; diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -531,6 +531,12 @@ ngx_event_pipe_write_to_downstream(ngx_e } else if (!p->cachable && p->in) { cl = p->in; + ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, + "pipe write buf ls:%d %p %z", + cl->buf->last_shadow, + cl->buf->pos, + cl->buf->last - cl->buf->pos); + if (cl->buf->recycled && cl->buf->last_shadow && bsize + cl->buf->last - cl->buf->pos > p->busy_size) diff --git a/src/event/ngx_event_timer.c b/src/event/ngx_event_timer.c --- a/src/event/ngx_event_timer.c +++ b/src/event/ngx_event_timer.c @@ -17,6 +17,11 @@ ngx_mutex_t *ngx_event_timer_mutex; ngx_thread_volatile ngx_rbtree_t ngx_event_timer_rbtree; static ngx_rbtree_node_t ngx_event_timer_sentinel; +/* + * the event timer rbtree may contain the duplicate keys, however, + * it should not be a problem, because we use the rbtree to find + * a minimum timer value only + */ ngx_int_t ngx_event_timer_init(ngx_log_t *log) diff --git a/src/http/modules/ngx_http_addition_filter_module.c b/src/http/modules/ngx_http_addition_filter_module.c --- a/src/http/modules/ngx_http_addition_filter_module.c +++ b/src/http/modules/ngx_http_addition_filter_module.c @@ -87,7 +87,10 @@ ngx_http_addition_header_filter(ngx_http ngx_http_addition_ctx_t *ctx; ngx_http_addition_conf_t *conf; - if (r->headers_out.status != NGX_HTTP_OK || r != r->main) { + if (r->headers_out.status != NGX_HTTP_OK + || r != r->main + || r->headers_out.content_type.data == NULL) + { return ngx_http_next_header_filter(r); } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -1310,6 +1310,9 @@ ngx_http_fastcgi_input_filter(ngx_event_ ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "input buf #%d", b->num); + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, + "input buf %p %z", b->pos, b->last - b->pos); + if (f->pos + f->length < f->last) { @@ -1350,6 +1353,9 @@ ngx_http_fastcgi_input_filter(ngx_event_ b->shadow = buf; b->last_shadow = 1; + ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0, + "input buf last %p %z", b->pos, b->last - b->pos); + return NGX_OK; } diff --git a/src/http/modules/ngx_http_limit_zone_module.c b/src/http/modules/ngx_http_limit_zone_module.c --- a/src/http/modules/ngx_http_limit_zone_module.c +++ b/src/http/modules/ngx_http_limit_zone_module.c @@ -104,6 +104,7 @@ ngx_http_limit_zone_handler(ngx_http_req { size_t len, n; uint32_t hash; + ngx_int_t rc; ngx_slab_pool_t *shpool; ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; @@ -131,9 +132,21 @@ ngx_http_limit_zone_handler(ngx_http_req return NGX_DECLINED; } - r->limit_zone_set = 1; + len = vv->len; + + if (len == 0) { + return NGX_DECLINED; + } - len = vv->len; + if (len > 255) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "the value of the \"%V\" variable " + "is more than 255 bytes: \"%V\"", + &ctx->var, vv); + return NGX_DECLINED; + } + + r->main->limit_zone_set = 1; hash = ngx_crc32_short(vv->data, len); @@ -161,12 +174,14 @@ ngx_http_limit_zone_handler(ngx_http_req continue; } - if (hash == node->key ){ + /* hash == node->key */ + + do { lz = (ngx_http_limit_zone_node_t *) &node->color; - if (len == (size_t) lz->len - && ngx_strncmp(lz->data, vv->data, len) == 0) - { + rc = ngx_memn2cmp(lz->data, vv->data, (size_t) lz->len, len); + + if (rc == 0) { if ((ngx_uint_t) lz->conn < lzcf->conn) { lz->conn++; goto done; @@ -176,7 +191,12 @@ ngx_http_limit_zone_handler(ngx_http_req return NGX_HTTP_SERVICE_UNAVAILABLE; } - } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; } n = offsetof(ngx_rbtree_node_t, color) @@ -216,6 +236,65 @@ done: static void +ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_http_limit_zone_node_t *lzn, *lznt; + + for ( ;; ) { + + if (node->key < temp->key) { + + if (temp->left == sentinel) { + temp->left = node; + break; + } + + temp = temp->left; + + } else if (node->key > temp->key) { + + if (temp->right == sentinel) { + temp->right = node; + break; + } + + temp = temp->right; + + } else { /* node->key == temp->key */ + + lzn = (ngx_http_limit_zone_node_t *) &node->color; + lznt = (ngx_http_limit_zone_node_t *) &temp->color; + + if (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) { + + if (temp->left == sentinel) { + temp->left = node; + break; + } + + temp = temp->left; + + } else { + + if (temp->right == sentinel) { + temp->right = node; + break; + } + + temp = temp->right; + } + } + } + + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static void ngx_http_limit_zone_cleanup(void *data) { ngx_http_limit_zone_cleanup_t *lzcln = data; @@ -260,7 +339,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo 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 " + "limit_zone \"%V\" uses the \"%V\" variable " "while previously it used the \"%V\" variable", &shm_zone->name, &ctx->var, &octx->var); return NGX_ERROR; @@ -287,7 +366,7 @@ ngx_http_limit_zone_init_zone(ngx_shm_zo ctx->rbtree->root = sentinel; ctx->rbtree->sentinel = sentinel; - ctx->rbtree->insert = ngx_rbtree_insert_value; + ctx->rbtree->insert = ngx_http_limit_zone_rbtree_insert_value; return NGX_OK; } @@ -419,6 +498,12 @@ ngx_http_limit_conn(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } + if (n > 65535) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "connection limit must be less 65536"); + return NGX_CONF_ERROR; + } + lzcf->conn = n; return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -2381,7 +2381,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n noregex = 0; flags = NGX_HTTP_SSI_ADD_ZERO; last--; - p++; + p++; } else { noregex = 1; diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -171,14 +171,14 @@ ngx_http_upstream_get_ip_hash_peer(ngx_p if (!peer->down) { - if (peer->max_fails == 0 || peer->fails < peer->max_fails) { - break; - } + if (peer->max_fails == 0 || peer->fails < peer->max_fails) { + break; + } - if (now - peer->accessed > peer->fail_timeout) { - peer->fails = 0; - break; - } + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + break; + } } else { iphp->rrp.tried[n] |= m; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.5.6'; +our $VERSION = '0.5.7'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -199,7 +199,7 @@ ngx_http_perl_handle_request(ngx_http_re ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_perl_ctx_t)); if (ctx == NULL) { ngx_http_finalize_request(r, NGX_ERROR); - return; + return; } ngx_http_set_ctx(r, ctx, ngx_http_perl_module); diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -935,7 +935,8 @@ ngx_http_core_find_location(ngx_http_req if (clcfp[i]->auto_redirect && r->uri.len == clcfp[i]->name.len - 1 && ngx_strncmp(r->uri.data, clcfp[i]->name.data, - clcfp[i]->name.len - 1) == 0) + clcfp[i]->name.len - 1) + == 0) { /* the locations are lexicographically sorted */ diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -1356,7 +1356,7 @@ ngx_http_upstream_send_response(ngx_http rc = ngx_http_send_header(r); - if (rc == NGX_ERROR || rc > NGX_OK || r->post_action) { + if (rc == NGX_ERROR || rc > NGX_OK || r->post_action || r->header_only) { ngx_http_upstream_finalize_request(r, u, rc); return; } diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -1191,7 +1191,7 @@ ngx_imap_do_auth(ngx_imap_session_t *s) s->state = 0; if (s->connection->read->timer_set) { - ngx_del_timer(s->connection->read); + ngx_del_timer(s->connection->read); } s->login_attempt++; diff --git a/src/os/unix/ngx_gcc_atomic_amd64.h b/src/os/unix/ngx_gcc_atomic_amd64.h --- a/src/os/unix/ngx_gcc_atomic_amd64.h +++ b/src/os/unix/ngx_gcc_atomic_amd64.h @@ -24,8 +24,11 @@ * * * The "r" is any register, %rax (%r0) - %r16. - * The "=a" and "a" are the %rax register. Although we can return result - * in any register, we use %rax because it is used in cmpxchgq anyway. + * The "=a" and "a" are the %rax register. + * Although we can return result in any register, we use "a" because it is + * used in cmpxchgq anyway. The result is actually in %al but not in $rax, + * however as the code is inlined gcc can test %al as well as %rax. + * * The "cc" means that flags were changed. */ @@ -33,14 +36,13 @@ static ngx_inline ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, ngx_atomic_uint_t set) { - ngx_atomic_uint_t res; + u_char res; __asm__ volatile ( NGX_SMP_LOCK " cmpxchgq %3, %1; " - " setz %b0; " - " movzbq %b0, %0; " + " sete %0; " : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); @@ -68,7 +70,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value NGX_SMP_LOCK " xaddq %0, %1; " - : "+q" (add) : "m" (*value) : "cc", "memory"); + : "+r" (add) : "m" (*value) : "cc", "memory"); return add; } diff --git a/src/os/unix/ngx_gcc_atomic_x86.h b/src/os/unix/ngx_gcc_atomic_x86.h --- a/src/os/unix/ngx_gcc_atomic_x86.h +++ b/src/os/unix/ngx_gcc_atomic_x86.h @@ -23,9 +23,13 @@ * } * * - * The "q" is any of the %eax, %ebx, %ecx, or %edx registers. - * The "=a" and "a" are the %eax register. Although we can return result - * in any register, we use %eax because it is used in cmpxchgl anyway. + * The "r" means the general register. + * The "=a" and "a" are the %eax register. + * Although we can return result in any register, we use "a" because it is + * used in cmpxchgl anyway. The result is actually in %al but not in %eax, + * however, as the code is inlined gcc can test %al as well as %eax, + * and icc adds "movzbl %al, %eax" by itself. + * * The "cc" means that flags were changed. */ @@ -33,16 +37,15 @@ static ngx_inline ngx_atomic_uint_t ngx_atomic_cmp_set(ngx_atomic_t *lock, ngx_atomic_uint_t old, ngx_atomic_uint_t set) { - ngx_atomic_uint_t res; + u_char res; __asm__ volatile ( NGX_SMP_LOCK " cmpxchgl %3, %1; " - " setz %b0; " - " movzbl %b0, %0; " + " sete %0; " - : "=a" (res) : "m" (*lock), "a" (old), "q" (set) : "cc", "memory"); + : "=a" (res) : "m" (*lock), "a" (old), "r" (set) : "cc", "memory"); return res; } @@ -56,7 +59,7 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n * r = temp; * * - * The "+q" is any of the %eax, %ebx, %ecx, or %edx registers. + * The "+r" means the general register. * The "cc" means that flags were changed. */ @@ -80,7 +83,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value NGX_SMP_LOCK " xaddl %0, %1; " - : "+q" (add) : "m" (*value) : "cc", "memory"); + : "+r" (add) : "m" (*value) : "cc", "memory"); return add; } @@ -89,9 +92,9 @@ ngx_atomic_fetch_add(ngx_atomic_t *value #else /* - * gcc 2.7 does not support "+q", so we have to use the fixed %eax ("=a" and - * "a") and this adds two superfluous instructions in the end of code, - * something like this: "mov %eax, %edx / mov %edx, %eax". + * gcc 2.7 does not support "+r", so we have to use the fixed + * %eax ("=a" and "a") and this adds two superfluous instructions in the end + * of code, something like this: "mov %eax, %edx / mov %edx, %eax". */ static ngx_inline ngx_atomic_int_t