# HG changeset patch # User Igor Sysoev # Date 1198702800 -10800 # Node ID 9121a0a91f470755095d53c8691d1c3ea58784b8 # Parent 16d557a7535694435868ef2e0a9f9bebdbc53f50 nginx 0.6.23 *) Change: the "off" parameter in the "ssl_session_cache" directive; now this is default parameter. *) Change: the "open_file_cache_retest" directive was renamed to the "open_file_cache_valid". *) Feature: the "open_file_cache_min_uses" directive. *) Feature: the ngx_http_gzip_static_module. *) Feature: the "gzip_disable" directive. *) Feature: the "memcached_pass" directive may be used inside the "if" block. *) Bugfix: a segmentation fault occurred in worker process, if the "memcached_pass" and "if" directives were used in the same location. *) Bugfix: if a "satisfy_any on" directive was used and not all access and auth modules directives were set, then other given access and auth directives were not tested; *) Bugfix: regex parameters in a "valid_referers" directive were not inherited from previous level. *) Bugfix: a "post_action" directive did run if a request was completed with 499 status code. *) Bugfix: optimization of 16K buffer usage in a SSL connection. Thanks to Ben Maurer. *) Bugfix: the STARTTLS in SMTP mode did not work. Thanks to Oleg Motienko. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error; bug appeared in 0.5.13. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,44 @@ +Changes with nginx 0.6.23 27 Dec 2007 + + *) Change: the "off" parameter in the "ssl_session_cache" directive; + now this is default parameter. + + *) Change: the "open_file_cache_retest" directive was renamed to the + "open_file_cache_valid". + + *) Feature: the "open_file_cache_min_uses" directive. + + *) Feature: the ngx_http_gzip_static_module. + + *) Feature: the "gzip_disable" directive. + + *) Feature: the "memcached_pass" directive may be used inside the "if" + block. + + *) Bugfix: a segmentation fault occurred in worker process, if the + "memcached_pass" and "if" directives were used in the same location. + + *) Bugfix: if a "satisfy_any on" directive was used and not all access + and auth modules directives were set, then other given access and + auth directives were not tested; + + *) Bugfix: regex parameters in a "valid_referers" directive were not + inherited from previous level. + + *) Bugfix: a "post_action" directive did run if a request was completed + with 499 status code. + + *) Bugfix: optimization of 16K buffer usage in a SSL connection. + Thanks to Ben Maurer. + + *) Bugfix: the STARTTLS in SMTP mode did not work. + Thanks to Oleg Motienko. + + *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" + error; bug appeared in 0.5.13. + + Changes with nginx 0.6.22 19 Dec 2007 *) Change: now all ngx_http_perl_module methods return values copied to diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,46 @@ +Изменения в nginx 0.6.23 27.12.2007 + + *) Изменение: параметр "off" в директиве ssl_session_cache; теперь этот + параметр используется по умолчанию. + + *) Изменение: директива open_file_cache_retest переименована в + open_file_cache_valid. + + *) Добавление: директива open_file_cache_min_uses. + + *) Добавление: модуль ngx_http_gzip_static_module. + + *) Добавление: директива gzip_disable. + + *) Добавление: директиву memcached_pass можно использовать внутри блока + if. + + *) Исправление: если внутри одного location'а использовались директивы + "memcached_pass" и "if", то в рабочем процессе происходил + segmentation fault. + + *) Исправление: если при использовании директивы satisfy_any on" были + заданы директивы не всех модулей доступа, то заданные директивы не + проверялись. + + *) Исправление: параметры, заданные регулярным выражением в директиве + valid_referers, не наследовалась с предыдущего уровня. + + *) Исправление: директива post_action не работала, если запрос + завершался с кодом 499. + + *) Исправление: оптимизация использования 16K буфера для + SSL-соединения. + Спасибо Ben Maurer. + + *) Исправление: STARTTLS в режиме SMTP не работал. + Спасибо Олегу Мотиенко. + + *) Исправление: при использовании HTTPS запросы могли завершаться с + ошибкой "bad write retry"; ошибка появилась в 0.5.13. + + Изменения в nginx 0.6.22 19.12.2007 *) Изменение: теперь все методы модуля ngx_http_perl_module возвращают @@ -79,7 +121,7 @@ *) Добавление: директива proxy_pass поддерживает переменные. - *) Добавление: директива resolver и resolver_timeout. + *) Добавление: директивы resolver и resolver_timeout. *) Добавление: теперь директива "add_header last-modified ''" удаляет в заголовке ответа строку "Last-Modified". diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -265,6 +265,12 @@ if [ $HTTP_FLV = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS" fi +if [ $HTTP_GZIP_STATIC = YES ]; then + have=NGX_HTTP_GZIP . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_GZIP_STATIC_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_GZIP_STATIC_SRCS" +fi + if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -76,6 +76,7 @@ HTTP_LIMIT_ZONE=YES HTTP_EMPTY_GIF=YES HTTP_BROWSER=YES HTTP_FLV=NO +HTTP_GZIP_STATIC=NO HTTP_UPSTREAM_IP_HASH=YES # STUB @@ -162,6 +163,7 @@ do --with-http_sub_module) HTTP_SUB=YES ;; --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; + --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -273,6 +275,7 @@ cat << END --with-http_sub_module enable ngx_http_sub_module --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module + --with-http_gzip_static_module enable ngx_http_gzip_static_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -178,7 +178,7 @@ UNIX_SRCS="$CORE_SRCS $EVENT_SRCS \ POSIX_DEPS=src/os/unix/ngx_posix_config.h -FREEBSD_DEPS=src/os/unix/ngx_freebsd_config.h +FREEBSD_DEPS="src/os/unix/ngx_freebsd_config.h src/os/unix/ngx_freebsd.h" FREEBSD_SRCS=src/os/unix/ngx_freebsd_init.c FREEBSD_SENDFILE_SRCS=src/os/unix/ngx_freebsd_sendfile_chain.c FREEBSD_RFORK_DEPS="src/os/unix/ngx_freebsd_rfork_thread.h" @@ -187,12 +187,12 @@ FREEBSD_RFORK_THREAD_SRCS="src/os/unix/r PTHREAD_SRCS="src/os/unix/ngx_pthread_thread.c" -LINUX_DEPS=src/os/unix/ngx_linux_config.h +LINUX_DEPS="src/os/unix/ngx_linux_config.h src/os/unix/ngx_linux.h" LINUX_SRCS=src/os/unix/ngx_linux_init.c LINUX_SENDFILE_SRCS=src/os/unix/ngx_linux_sendfile_chain.c -SOLARIS_DEPS=src/os/unix/ngx_solaris_config.h +SOLARIS_DEPS="src/os/unix/ngx_solaris_config.h src/os/unix/ngx_solaris.h" SOLARIS_SRCS=src/os/unix/ngx_solaris_init.c SOLARIS_SENDFILEV_SRCS=src/os/unix/ngx_solaris_sendfilev_chain.c @@ -417,6 +417,10 @@ HTTP_FLV_MODULE=ngx_http_flv_module HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c +HTTP_GZIP_STATIC_MODULE=ngx_http_gzip_static_module +HTTP_GZIP_STATIC_SRCS=src/http/modules/ngx_http_gzip_static_module.c + + HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c 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.6.22" +#define NGINX_VERSION "0.6.23" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -18,22 +18,27 @@ static void ngx_open_file_cache_cleanup(void *data); +static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, + ngx_log_t *log); +static void ngx_open_file_add_event(ngx_open_file_cache_t *cache, + ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log); static void ngx_open_file_cleanup(void *data); static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_log_t *log); -static ngx_int_t ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, - ngx_log_t *log); + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log); +static void ngx_open_file_del_event(ngx_cached_open_file_t *file); static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, ngx_log_t *log); static void ngx_open_file_cache_rbtree_insert_value(ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +static ngx_cached_open_file_t * + ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, + uint32_t hash); static void ngx_open_file_cache_remove(ngx_event_t *ev); ngx_open_file_cache_t * ngx_open_file_cache_init(ngx_pool_t *pool, ngx_uint_t max, time_t inactive) { - ngx_rbtree_node_t *sentinel; ngx_pool_cleanup_t *cln; ngx_open_file_cache_t *cache; @@ -42,19 +47,10 @@ ngx_open_file_cache_init(ngx_pool_t *poo return NULL; } - cache->list_head.prev = NULL; - cache->list_head.next = &cache->list_tail; - - cache->list_tail.prev = &cache->list_head; - cache->list_tail.next = NULL; + ngx_rbtree_init(&cache->rbtree, &cache->sentinel, + ngx_open_file_cache_rbtree_insert_value); - sentinel = ngx_palloc(pool, sizeof(ngx_rbtree_node_t)); - if (sentinel == NULL) { - return NULL; - } - - ngx_rbtree_init(&cache->rbtree, sentinel, - ngx_open_file_cache_rbtree_insert_value); + ngx_queue_init(&cache->expire_queue); cache->current = 0; cache->max = max; @@ -77,6 +73,7 @@ ngx_open_file_cache_cleanup(void *data) { ngx_open_file_cache_t *cache = data; + ngx_queue_t *q; ngx_cached_open_file_t *file; ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, @@ -84,14 +81,15 @@ ngx_open_file_cache_cleanup(void *data) for ( ;; ) { - file = cache->list_tail.prev; - - if (file == &cache->list_head) { + if (ngx_queue_empty(&cache->expire_queue)) { break; } - file->next->prev = file->prev; - file->prev->next = file->next; + q = ngx_queue_last(&cache->expire_queue); + + file = ngx_queue_data(q, ngx_cached_open_file_t, queue); + + ngx_queue_remove(q); ngx_rbtree_delete(&cache->rbtree, &file->node); @@ -103,7 +101,7 @@ ngx_open_file_cache_cleanup(void *data) if (!file->err && !file->is_dir) { file->close = 1; file->count = 0; - ngx_close_cached_file(cache, file, ngx_cycle->log); + ngx_close_cached_file(cache, file, 0, ngx_cycle->log); } else { ngx_free(file->name); @@ -132,11 +130,9 @@ ngx_open_cached_file(ngx_open_file_cache time_t now; uint32_t hash; ngx_int_t rc; - ngx_rbtree_node_t *node, *sentinel; ngx_pool_cleanup_t *cln; ngx_cached_open_file_t *file; ngx_pool_cleanup_file_t *clnf; - ngx_open_file_cache_event_t *fev; ngx_open_file_cache_cleanup_t *ofcln; of->err = 0; @@ -167,145 +163,147 @@ ngx_open_cached_file(ngx_open_file_cache return NGX_ERROR; } - hash = ngx_crc32_long(name->data, name->len); - - node = cache->rbtree.root; - sentinel = cache->rbtree.sentinel; - now = ngx_time(); - while (node != sentinel) { + hash = ngx_crc32_long(name->data, name->len); + + file = ngx_open_file_lookup(cache, name, hash); + + if (file) { + + file->uses++; + + ngx_queue_remove(&file->queue); - if (hash < node->key) { - node = node->left; - continue; - } + if (file->fd == NGX_INVALID_FILE && file->err == 0 && !file->is_dir) { + + /* file was not used often enough to keep open */ + + rc = ngx_open_and_stat_file(name->data, of, pool->log); - if (hash > node->key) { - node = node->right; - continue; + if (rc != NGX_OK && (of->err == 0 || !of->errors)) { + goto failed; + } + + goto add_event; } - /* hash == node->key */ - - do { - file = (ngx_cached_open_file_t *) node; - - rc = ngx_strcmp(name->data, file->name); - - if (rc == 0) { - - file->next->prev = file->prev; - file->prev->next = file->next; - - if (file->event || now - file->created < of->retest) { - if (file->err == 0) { - of->fd = file->fd; - of->uniq = file->uniq; - of->mtime = file->mtime; - of->size = file->size; - - of->is_dir = file->is_dir; - of->is_file = file->is_file; - of->is_link = file->is_link; - of->is_exec = file->is_exec; + if ((file->event && file->use_event) + || (file->event == NULL && now - file->created < of->valid)) + { + if (file->err == 0) { - if (!file->is_dir) { - file->count++; - } - - } else { - of->err = file->err; - } - - goto found; - } + of->fd = file->fd; + of->uniq = file->uniq; + of->mtime = file->mtime; + of->size = file->size; - ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, - "retest open file: %s, fd:%d, c:%d, e:%d", - file->name, file->fd, file->count, file->err); - - if (file->is_dir) { + of->is_dir = file->is_dir; + of->is_file = file->is_file; + of->is_link = file->is_link; + of->is_exec = file->is_exec; - /* - * chances that directory became file are very small - * so test_dir flag allows to use a single ngx_file_info() - * syscall instead of three syscalls - */ - - of->test_dir = 1; + if (!file->is_dir) { + file->count++; + ngx_open_file_add_event(cache, file, of, pool->log); } - rc = ngx_open_and_stat_file(name->data, of, pool->log); + } else { + of->err = file->err; + } + + goto found; + } + + ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, + "retest open file: %s, fd:%d, c:%d, e:%d", + file->name, file->fd, file->count, file->err); + + if (file->is_dir) { + + /* + * chances that directory became file are very small + * so test_dir flag allows to use a single syscall + * in ngx_file_info() instead of three syscalls + */ + + of->test_dir = 1; + } + + rc = ngx_open_and_stat_file(name->data, of, pool->log); - if (rc != NGX_OK && (of->err == 0 || !of->errors)) { - goto failed; + if (rc != NGX_OK && (of->err == 0 || !of->errors)) { + goto failed; + } + + if (of->is_dir) { + + if (file->is_dir || file->err) { + goto update; + } + + /* file became directory */ + + } else if (of->err == 0) { /* file */ + + if (file->is_dir || file->err) { + goto add_event; + } + + if (of->uniq == file->uniq + && of->mtime == file->mtime + && of->size == file->size) + { + if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + name->data); } - if (of->is_dir) { - if (file->is_dir || file->err) { - goto update; - } - - /* file became directory */ - - } else if (of->err == 0) { /* file */ - - if (file->is_dir || file->err) { - goto update; - } + of->fd = file->fd; + file->count++; - if (of->uniq == file->uniq - && of->mtime == file->mtime - && of->size == file->size) - { - if (ngx_close_file(of->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - name->data); - } - - of->fd = file->fd; - file->count++; - - goto renew; - } - - /* file was changed */ - - } else { /* error to cache */ - - if (file->err || file->is_dir) { - goto update; - } - - /* file was removed, etc. */ + if (file->event) { + file->use_event = 1; + goto renew; } - if (file->count == 0) { - if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, - ngx_close_file_n " \"%s\" failed", - name->data); - } + ngx_open_file_add_event(cache, file, of, pool->log); + + goto renew; + } - goto update; - } - - ngx_rbtree_delete(&cache->rbtree, &file->node); + /* file was changed */ - cache->current--; + } else { /* error to cache */ - file->close = 1; - - goto create; + if (file->err || file->is_dir) { + goto update; } - node = (rc < 0) ? node->left : node->right; + /* file was removed, etc. */ + } + + if (file->count == 0) { + + ngx_open_file_del_event(file); - } while (node != sentinel && hash == node->key); + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, pool->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", + name->data); + } - break; + goto add_event; + } + + ngx_rbtree_delete(&cache->rbtree, &file->node); + + cache->current--; + + file->close = 1; + + goto create; } /* not found */ @@ -346,51 +344,17 @@ create: cache->current++; + file->uses = 1; file->count = 0; + file->use_event = 0; + file->event = NULL; + +add_event: + + ngx_open_file_add_event(cache, file, of, pool->log); update: - if (of->events - && (ngx_event_flags & NGX_USE_VNODE_EVENT) - && of->fd != NGX_INVALID_FILE) - { - file->event = ngx_calloc(sizeof(ngx_event_t), pool->log); - if (file->event== NULL) { - goto failed; - } - - fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), pool->log); - if (fev == NULL) { - goto failed; - } - - fev->fd = of->fd; - fev->file = file; - fev->cache = cache; - - file->event->handler = ngx_open_file_cache_remove; - file->event->data = fev; - - /* - * although vnode event may be called while ngx_cycle->poll - * destruction; however, cleanup procedures are run before any - * memory freeing and events will be canceled. - */ - - file->event->log = ngx_cycle->log; - - if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) - != NGX_OK) - { - ngx_free(file->event->data); - ngx_free(file->event); - goto failed; - } - - } else { - file->event = NULL; - } - file->fd = of->fd; file->err = of->err; @@ -419,16 +383,11 @@ found: file->accessed = now; - /* add to the inactive list head */ + ngx_queue_insert_head(&cache->expire_queue, &file->queue); - file->next = cache->list_head.next; - file->next->prev = file; - file->prev = &cache->list_head; - cache->list_head.next = file; - - ngx_log_debug4(NGX_LOG_DEBUG_CORE, pool->log, 0, - "cached open file: %s, fd:%d, c:%d, e:%d", - file->name, file->fd, file->count, file->err); + ngx_log_debug5(NGX_LOG_DEBUG_CORE, pool->log, 0, + "cached open file: %s, fd:%d, c:%d, e:%d, u:%d", + file->name, file->fd, file->count, file->err, file->uses); if (of->err == 0) { @@ -438,6 +397,7 @@ found: ofcln->cache = cache; ofcln->file = file; + ofcln->min_uses = of->min_uses; ofcln->log = pool->log; } @@ -543,6 +503,72 @@ ngx_open_and_stat_file(u_char *name, ngx } +/* + * we ignore any possible event setting error and + * fallback to usual periodic file retests + */ + +static void +ngx_open_file_add_event(ngx_open_file_cache_t *cache, + ngx_cached_open_file_t *file, ngx_open_file_info_t *of, ngx_log_t *log) +{ + ngx_open_file_cache_event_t *fev; + + if (!(ngx_event_flags & NGX_USE_VNODE_EVENT) + || !of->events + || file->event + || of->fd == NGX_INVALID_FILE + || file->uses < of->min_uses) + { + return; + } + + file->event = ngx_calloc(sizeof(ngx_event_t), log); + if (file->event== NULL) { + return; + } + + fev = ngx_alloc(sizeof(ngx_open_file_cache_event_t), log); + if (fev == NULL) { + ngx_free(file->event); + file->event = NULL; + return; + } + + fev->fd = of->fd; + fev->file = file; + fev->cache = cache; + + file->event->handler = ngx_open_file_cache_remove; + file->event->data = fev; + + /* + * although vnode event may be called while ngx_cycle->poll + * destruction, however, cleanup procedures are run before any + * memory freeing and events will be canceled. + */ + + file->event->log = ngx_cycle->log; + + if (ngx_add_event(file->event, NGX_VNODE_EVENT, NGX_ONESHOT_EVENT) + != NGX_OK) + { + ngx_free(file->event->data); + ngx_free(file->event); + file->event = NULL; + return; + } + + /* + * we do not file->use_event here because there may be a race + * condition between opening file and adding event, so we rely + * upon event notification only after first file revalidation + */ + + return; +} + + static void ngx_open_file_cleanup(void *data) { @@ -550,7 +576,7 @@ ngx_open_file_cleanup(void *data) c->file->count--; - ngx_close_cached_file(c->cache, c->file, c->log); + ngx_close_cached_file(c->cache, c->file, c->min_uses, c->log); /* drop one or two expired open files */ ngx_expire_old_cached_files(c->cache, 1, c->log); @@ -559,50 +585,43 @@ ngx_open_file_cleanup(void *data) static void ngx_close_cached_file(ngx_open_file_cache_t *cache, - ngx_cached_open_file_t *file, ngx_log_t *log) + ngx_cached_open_file_t *file, ngx_uint_t min_uses, ngx_log_t *log) { - ngx_log_debug4(NGX_LOG_DEBUG_CORE, log, 0, - "close cached open file: %s, fd:%d, c:%d, %d", - file->name, file->fd, file->count, file->close); + ngx_log_debug5(NGX_LOG_DEBUG_CORE, log, 0, + "close cached open file: %s, fd:%d, c:%d, u:%d, %d", + file->name, file->fd, file->count, file->uses, file->close); if (!file->close) { file->accessed = ngx_time(); - if (cache->list_head.next != file) { + ngx_queue_remove(&file->queue); - /* delete from inactive list */ - - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_insert_head(&cache->expire_queue, &file->queue); - /* add to the inactive list head */ - - file->next = cache->list_head.next; - file->next->prev = file; - file->prev = &cache->list_head; - cache->list_head.next = file; + if (file->uses >= min_uses || file->count) { + return; } - - return; } - if (file->event) { - (void) ngx_del_event(file->event, NGX_VNODE_EVENT, - file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); - - ngx_free(file->event->data); - ngx_free(file->event); - file->event = NULL; - } + ngx_open_file_del_event(file); if (file->count) { return; } - if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", file->name); + if (file->fd != NGX_INVALID_FILE) { + + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file->name); + } + + file->fd = NGX_INVALID_FILE; + } + + if (!file->close) { + return; } ngx_free(file->name); @@ -611,10 +630,28 @@ ngx_close_cached_file(ngx_open_file_cach static void +ngx_open_file_del_event(ngx_cached_open_file_t *file) +{ + if (file->event == NULL) { + return; + } + + (void) ngx_del_event(file->event, NGX_VNODE_EVENT, + file->count ? NGX_FLUSH_EVENT : NGX_CLOSE_EVENT); + + ngx_free(file->event->data); + ngx_free(file->event); + file->event = NULL; + file->use_event = 0; +} + + +static void ngx_expire_old_cached_files(ngx_open_file_cache_t *cache, ngx_uint_t n, ngx_log_t *log) { time_t now; + ngx_queue_t *q; ngx_cached_open_file_t *file; now = ngx_time(); @@ -627,18 +664,19 @@ ngx_expire_old_cached_files(ngx_open_fil while (n < 3) { - file = cache->list_tail.prev; - - if (file == &cache->list_head) { + if (ngx_queue_empty(&cache->expire_queue)) { return; } + q = ngx_queue_last(&cache->expire_queue); + + file = ngx_queue_data(q, ngx_cached_open_file_t, queue); + if (n++ != 0 && now - file->accessed <= cache->inactive) { return; } - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_remove(q); ngx_rbtree_delete(&cache->rbtree, &file->node); @@ -649,7 +687,7 @@ ngx_expire_old_cached_files(ngx_open_fil if (!file->err && !file->is_dir) { file->close = 1; - ngx_close_cached_file(cache, file, log); + ngx_close_cached_file(cache, file, 0, log); } else { ngx_free(file->name); @@ -700,6 +738,51 @@ ngx_open_file_cache_rbtree_insert_value( } +static ngx_cached_open_file_t * +ngx_open_file_lookup(ngx_open_file_cache_t *cache, ngx_str_t *name, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_cached_open_file_t *file; + + node = cache->rbtree.root; + sentinel = cache->rbtree.sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + do { + file = (ngx_cached_open_file_t *) node; + + rc = ngx_strcmp(name->data, file->name); + + if (rc == 0) { + return file; + } + + node = (rc < 0) ? node->left : node->right; + + } while (node != sentinel && hash == node->key); + + break; + } + + return NULL; +} + + static void ngx_open_file_cache_remove(ngx_event_t *ev) { @@ -709,8 +792,7 @@ ngx_open_file_cache_remove(ngx_event_t * fev = ev->data; file = fev->file; - file->next->prev = file->prev; - file->prev->next = file->next; + ngx_queue_remove(&file->queue); ngx_rbtree_delete(&fev->cache->rbtree, &file->node); @@ -721,7 +803,7 @@ ngx_open_file_cache_remove(ngx_event_t * file->close = 1; - ngx_close_cached_file(fev->cache, file, ev->log); + ngx_close_cached_file(fev->cache, file, 0, ev->log); /* free memory only when fev->cache and fev->file are already not needed */ diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -19,7 +19,9 @@ typedef struct { off_t size; ngx_err_t err; - time_t retest; + time_t valid; + + ngx_uint_t min_uses; unsigned test_dir:1; unsigned errors:1; @@ -36,8 +38,7 @@ typedef struct ngx_cached_open_file_s n struct ngx_cached_open_file_s { ngx_rbtree_node_t node; - ngx_cached_open_file_t *prev; - ngx_cached_open_file_t *next; + ngx_queue_t queue; u_char *name; time_t created; @@ -49,8 +50,11 @@ struct ngx_cached_open_file_s { off_t size; ngx_err_t err; + uint32_t uses; + unsigned count:24; unsigned close:1; + unsigned use_event:1; unsigned is_dir:1; unsigned is_file:1; @@ -63,8 +67,8 @@ struct ngx_cached_open_file_s { typedef struct { ngx_rbtree_t rbtree; - ngx_cached_open_file_t list_head; - ngx_cached_open_file_t list_tail; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; ngx_uint_t current; ngx_uint_t max; @@ -75,6 +79,7 @@ typedef struct { typedef struct { ngx_open_file_cache_t *cache; ngx_cached_open_file_t *file; + ngx_uint_t min_uses; ngx_log_t *log; } ngx_open_file_cache_cleanup_t; diff --git a/src/core/ngx_queue.h b/src/core/ngx_queue.h --- a/src/core/ngx_queue.h +++ b/src/core/ngx_queue.h @@ -22,7 +22,7 @@ struct ngx_queue_s { #define ngx_queue_init(q) \ (q)->prev = q; \ - (q)->next = q; + (q)->next = q #define ngx_queue_empty(h) \ 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 @@ -242,13 +242,13 @@ ngx_rbtree_delete(ngx_thread_volatile ng if (subst->right != sentinel) { subst->right->parent = subst; } + } - /* DEBUG stuff */ - node->left = NULL; - node->right = NULL; - node->parent = NULL; - node->key = 0; - } + /* DEBUG stuff */ + node->left = NULL; + node->right = NULL; + node->parent = NULL; + node->key = 0; if (red) { return; diff --git a/src/core/ngx_regex.c b/src/core/ngx_regex.c --- a/src/core/ngx_regex.c +++ b/src/core/ngx_regex.c @@ -114,6 +114,39 @@ ngx_regex_exec(ngx_regex_t *re, ngx_str_ } +ngx_int_t +ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log) +{ + ngx_int_t n; + ngx_uint_t i; + ngx_regex_elt_t *re; + + re = a->elts; + + for (i = 0; i < a->nelts; i++) { + + n = ngx_regex_exec(re[i].regex, s, NULL, 0); + + if (n == NGX_REGEX_NO_MATCHED) { + continue; + } + + if (n < 0) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + ngx_regex_exec_n " failed: %d on \"%V\" using \"%s\"", + n, s, re[i].name); + return NGX_ERROR; + } + + /* match */ + + return NGX_OK; + } + + return NGX_DECLINED; +} + + static void * ngx_libc_cdecl ngx_regex_malloc(size_t size) { diff --git a/src/core/ngx_regex.h b/src/core/ngx_regex.h --- a/src/core/ngx_regex.h +++ b/src/core/ngx_regex.h @@ -20,12 +20,20 @@ typedef pcre ngx_regex_t; +typedef struct { + ngx_regex_t *regex; + u_char *name; +} ngx_regex_elt_t; + + void ngx_regex_init(void); ngx_regex_t *ngx_regex_compile(ngx_str_t *pattern, ngx_int_t options, ngx_pool_t *pool, ngx_str_t *err); ngx_int_t ngx_regex_capture_count(ngx_regex_t *re); ngx_int_t ngx_regex_exec(ngx_regex_t *re, ngx_str_t *s, int *captures, ngx_int_t size); +ngx_int_t ngx_regex_exec_array(ngx_array_t *a, ngx_str_t *s, ngx_log_t *log); + #define ngx_regex_exec_n "pcre_exec()" #define ngx_regex_capture_count_n "pcre_fullinfo()" diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -669,17 +669,8 @@ ngx_resolver_expire(ngx_resolver_t *r, n return; } -#if (NGX_DEBUG) - { - ngx_str_t s; - - s.len = rn->nlen; - s.data = rn->name; - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver expire \"%V\"", &s); - } -#endif + ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name); ngx_queue_remove(q); @@ -783,17 +774,9 @@ ngx_resolver_resend(ngx_resolver_t *r, n return rn->expire - now; } -#if (NGX_DEBUG) - { - ngx_str_t s; - - s.len = rn->nlen; - s.data = rn->name; - - ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver resend \"%V\" %p", &s, rn->waiting); - } -#endif + ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, + "resolver resend \"%*s\" %p", + (size_t) rn->nlen, rn->name, rn->waiting); ngx_queue_remove(q); 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 @@ -58,9 +58,22 @@ #if (NGX_DEBUG_MALLOC) -#define ngx_slab_junk(p, size) ngx_memset(p, 0xD0, size) + +#define ngx_slab_junk(p, size) ngx_memset(p, 0xD0, size) + #else + +#if (NGX_FREEBSD) + +#define ngx_slab_junk(p, size) \ + if (ngx_freebsd_debug_malloc) ngx_memset(p, 0xD0, size) + +#else + #define ngx_slab_junk(p, size) + +#endif + #endif static ngx_slab_page_t *ngx_slab_alloc_pages(ngx_slab_pool_t *pool, 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 @@ -63,6 +63,7 @@ ngx_pstrdup(ngx_pool_t *pool, ngx_str_t * %V ngx_str_t * * %v ngx_variable_value_t * * %s null-terminated string + * %*s length and string * %Z '\0' * %N '\n' * %c char @@ -112,7 +113,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c * but icc issues the warning */ int d; - size_t len; + size_t len, slen; uint32_t ui32; int64_t i64; uint64_t ui64; @@ -146,6 +147,7 @@ ngx_vsnprintf(u_char *buf, size_t max, c sign = 1; hexadecimal = 0; max_width = 0; + slen = 0; p = temp + NGX_INT64_LEN; @@ -179,6 +181,11 @@ ngx_vsnprintf(u_char *buf, size_t max, c fmt++; continue; + case '*': + slen = va_arg(args, u_int); + fmt++; + continue; + default: break; } @@ -214,9 +221,15 @@ ngx_vsnprintf(u_char *buf, size_t max, c case 's': p = va_arg(args, u_char *); - while (*p && buf < last) { - *buf++ = *p++; + if (slen == 0) { + while (*p && buf < last) { + *buf++ = *p++; + } + + } else { + buf = ngx_cpymem(buf, p, slen); } + fmt++; continue; 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 @@ -22,6 +22,7 @@ static void ngx_ssl_read_handler(ngx_eve 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 void ngx_ssl_clear_error(ngx_log_t *log); static ngx_int_t ngx_ssl_session_cache_init(ngx_shm_zone_t *shm_zone, void *data); @@ -186,8 +187,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_ SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]); } - SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); - SSL_CTX_set_read_ahead(ssl->ctx, 1); return NGX_OK; @@ -345,14 +344,7 @@ ngx_ssl_create_connection(ngx_ssl_t *ssl return NGX_ERROR; } - if (flags & NGX_SSL_BUFFER) { - sc->buffer = 1; - - sc->buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); - if (sc->buf == NULL) { - return NGX_ERROR; - } - } + sc->buffer = ((flags & NGX_SSL_BUFFER) != 0); sc->connection = SSL_new(ssl->ctx); @@ -404,6 +396,8 @@ ngx_ssl_handshake(ngx_connection_t *c) int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + n = SSL_do_handshake(c->ssl->connection); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); @@ -605,6 +599,8 @@ ngx_ssl_recv(ngx_connection_t *c, u_char bytes = 0; + ngx_ssl_clear_error(c->log); + /* * SSL_read() may return data in parts, so try to read * until SSL_read() would return no data @@ -801,8 +797,28 @@ ngx_ssl_send_chain(ngx_connection_t *c, limit = NGX_MAX_UINT32_VALUE - ngx_pagesize; } - buf = c->ssl->buf; + + if (buf == NULL) { + buf = ngx_create_temp_buf(c->pool, NGX_SSL_BUFSIZE); + if (buf == NULL) { + return NGX_CHAIN_ERROR; + } + + c->ssl->buf = buf; + } + + if (buf->start == NULL) { + buf->start = ngx_palloc(c->pool, NGX_SSL_BUFSIZE); + if (buf->start == NULL) { + return NGX_CHAIN_ERROR; + } + + buf->pos = buf->start; + buf->last = buf->start; + buf->end = buf->start + NGX_SSL_BUFSIZE; + } + send = 0; flush = (in == NULL) ? 1 : 0; @@ -895,6 +911,8 @@ ngx_ssl_write(ngx_connection_t *c, u_cha int n, sslerr; ngx_err_t err; + ngx_ssl_clear_error(c->log); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); n = SSL_write(c->ssl->connection, data, size); @@ -975,12 +993,20 @@ ngx_ssl_read_handler(ngx_event_t *rev) } +void +ngx_ssl_free_buffer(ngx_connection_t *c) +{ + if (ngx_pfree(c->pool, c->ssl->buf->start) == NGX_OK) { + c->ssl->buf->start = NULL; + } +} + + ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { - int n, sslerr, mode; - ngx_err_t err; - ngx_uint_t again; + int n, sslerr, mode; + ngx_err_t err; if (c->timedout) { mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN; @@ -999,40 +1025,34 @@ ngx_ssl_shutdown(ngx_connection_t *c) SSL_set_shutdown(c->ssl->connection, mode); - again = 0; + ngx_ssl_clear_error(c->log); + + n = SSL_shutdown(c->ssl->connection); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); + sslerr = 0; - for ( ;; ) { - n = SSL_shutdown(c->ssl->connection); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_shutdown: %d", n); - - if (n == 1 || (n == 0 && c->timedout)) { - SSL_free(c->ssl->connection); - c->ssl = NULL; - - return NGX_OK; - } - - if (n == 0) { - again = 1; - break; - } - - break; - } - - if (!again) { + /* SSL_shutdown() never return -1, on error it return 0 */ + + if (n != 1) { sslerr = SSL_get_error(c->ssl->connection, n); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr); } - if (again - || sslerr == SSL_ERROR_WANT_READ - || sslerr == SSL_ERROR_WANT_WRITE) + if (n == 1 + || sslerr == SSL_ERROR_ZERO_RETURN + || (sslerr == 0 && c->timedout)) { + SSL_free(c->ssl->connection); + c->ssl = NULL; + + return NGX_OK; + } + + if (sslerr == SSL_ERROR_WANT_READ || sslerr == SSL_ERROR_WANT_WRITE) { c->read->handler = ngx_ssl_shutdown_handler; c->write->handler = ngx_ssl_shutdown_handler; @@ -1044,7 +1064,7 @@ ngx_ssl_shutdown(ngx_connection_t *c) return NGX_ERROR; } - if (again || sslerr == SSL_ERROR_WANT_READ) { + if (sslerr == SSL_ERROR_WANT_READ) { ngx_add_timer(c->read, 30000); } @@ -1125,6 +1145,15 @@ ngx_ssl_connection_error(ngx_connection_ } +static void +ngx_ssl_clear_error(ngx_log_t *log) +{ + if (ERR_peek_error()) { + ngx_ssl_error(NGX_LOG_ALERT, log, 0, "ignoring stale global SSL error"); + } +} + + void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...) { @@ -1167,6 +1196,11 @@ ngx_ssl_session_cache(ngx_ssl_t *ssl, ng { long cache_mode; + if (builtin_session_cache == NGX_SSL_NO_SCACHE) { + SSL_CTX_set_session_cache_mode(ssl->ctx, SSL_SESS_CACHE_OFF); + return NGX_OK; + } + cache_mode = SSL_SESS_CACHE_SERVER; if (shm_zone && builtin_session_cache == NGX_SSL_NO_BUILTIN_SCACHE) { @@ -1210,7 +1244,6 @@ 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) { @@ -1225,25 +1258,11 @@ ngx_ssl_session_cache_init(ngx_shm_zone_ 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_init(cache->session_rbtree, sentinel, + ngx_rbtree_init(&cache->session_rbtree, &cache->sentinel, ngx_ssl_session_rbtree_insert_value); + ngx_queue_init(&cache->expire_queue); + shm_zone->data = cache; return NGX_OK; @@ -1274,7 +1293,6 @@ ngx_ssl_new_session(ngx_ssl_conn_t *ssl_ u_char *p, *id, *cached_sess; 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; @@ -1350,22 +1368,17 @@ 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; - 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); + sess_id->expire = ngx_time() + SSL_CTX_get_timeout(ssl_ctx); + + ngx_queue_insert_head(&cache->expire_queue, &sess_id->queue); + + ngx_rbtree_insert(&cache->session_rbtree, &sess_id->node); ngx_shmtx_unlock(&shpool->mutex); @@ -1400,7 +1413,6 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ 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; ngx_connection_t *c; @@ -1423,18 +1435,14 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ 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; + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { @@ -1457,9 +1465,7 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ (size_t) len, (size_t) node->data); if (rc == 0) { - tp = ngx_timeofday(); - - if (sess_id->expire > tp->sec) { + if (sess_id->expire > ngx_time()) { ngx_memcpy(buf, sess_id->session, sess_id->len); ngx_shmtx_unlock(&shpool->mutex); @@ -1470,10 +1476,9 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ return sess; } - sess_id->next->prev = sess_id->prev; - sess_id->prev->next = sess_id->next; - - ngx_rbtree_delete(cache->session_rbtree, node); + ngx_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) @@ -1530,8 +1535,8 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx ngx_shmtx_lock(&shpool->mutex); - node = cache->session_rbtree->root; - sentinel = cache->session_rbtree->sentinel; + node = cache->session_rbtree.root; + sentinel = cache->session_rbtree.sentinel; while (node != sentinel) { @@ -1553,10 +1558,10 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx 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_queue_remove(&sess_id->queue); + + ngx_rbtree_delete(&cache->session_rbtree, node); ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) @@ -1584,31 +1589,33 @@ 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; + time_t now; + ngx_queue_t *q; ngx_ssl_sess_id_t *sess_id; - tp = ngx_timeofday(); + now = ngx_time(); while (n < 3) { - sess_id = cache->session_cache_tail.prev; - - if (sess_id == &cache->session_cache_head) { + if (ngx_queue_empty(&cache->expire_queue)) { return; } - if (n++ != 0 && sess_id->expire > tp->sec) { + q = ngx_queue_last(&cache->expire_queue); + + sess_id = ngx_queue_data(q, ngx_ssl_sess_id_t, queue); + + if (n++ != 0 && sess_id->expire > now) { return; } - sess_id->next->prev = sess_id->prev; - sess_id->prev->next = sess_id->next; - - ngx_rbtree_delete(cache->session_rbtree, &sess_id->node); + ngx_queue_remove(q); ngx_log_debug1(NGX_LOG_DEBUG_EVENT, ngx_cycle->log, 0, "expire session: %08Xi", sess_id->node.key); + ngx_rbtree_delete(&cache->session_rbtree, &sess_id->node); + ngx_slab_free_locked(shpool, sess_id->session); #if (NGX_PTR_SIZE == 4) ngx_slab_free_locked(shpool, sess_id->id); 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 @@ -53,9 +53,10 @@ typedef struct { #define NGX_SSL_DFLT_BUILTIN_SCACHE -2 #define NGX_SSL_NO_BUILTIN_SCACHE -3 +#define NGX_SSL_NO_SCACHE -4 -#define NGX_SSL_MAX_SESSION_SIZE (4096) +#define NGX_SSL_MAX_SESSION_SIZE 4096 typedef struct ngx_ssl_sess_id_s ngx_ssl_sess_id_t; @@ -64,8 +65,7 @@ struct ngx_ssl_sess_id_s { u_char *id; size_t len; u_char *session; - ngx_ssl_sess_id_t *prev; - ngx_ssl_sess_id_t *next; + ngx_queue_t queue; time_t expire; #if (NGX_PTR_SIZE == 8) void *stub; @@ -75,9 +75,9 @@ struct ngx_ssl_sess_id_s { typedef struct { - ngx_rbtree_t *session_rbtree; - ngx_ssl_sess_id_t session_cache_head; - ngx_ssl_sess_id_t session_cache_tail; + ngx_rbtree_t session_rbtree; + ngx_rbtree_node_t sentinel; + ngx_queue_t expire_queue; } ngx_ssl_session_cache_t; @@ -132,6 +132,7 @@ ssize_t ngx_ssl_write(ngx_connection_t * ssize_t ngx_ssl_recv_chain(ngx_connection_t *c, ngx_chain_t *cl); ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); +void ngx_ssl_free_buffer(ngx_connection_t *c); ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); void ngx_cdecl ngx_ssl_error(ngx_uint_t level, ngx_log_t *log, ngx_err_t err, char *fmt, ...); diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -98,7 +98,7 @@ ngx_http_access_handler(ngx_http_request alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); if (alcf->rules == NULL) { - return NGX_OK; + return NGX_DECLINED; } /* AF_INET only */ @@ -128,7 +128,7 @@ ngx_http_access_handler(ngx_http_request } } - return NGX_OK; + return NGX_DECLINED; } diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -113,7 +113,7 @@ ngx_http_auth_basic_handler(ngx_http_req alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); if (alcf->realm.len == 0 || alcf->user_file.len == 0) { - return NGX_OK; + return NGX_DECLINED; } ctx = ngx_http_get_module_ctx(r, ngx_http_auth_basic_module); diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -37,7 +37,6 @@ static ngx_int_t ngx_http_dav_handler(ng static void ngx_http_dav_put_handler(ngx_http_request_t *r); static ngx_int_t ngx_http_dav_delete_handler(ngx_http_request_t *r); -static ngx_int_t ngx_http_dav_no_init(void *ctx, void *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); @@ -409,13 +408,6 @@ ngx_http_dav_delete_handler(ngx_http_req static ngx_int_t -ngx_http_dav_no_init(void *ctx, void *prev) -{ - return NGX_OK; -} - - -static ngx_int_t ngx_http_dav_noop(ngx_tree_ctx_t *ctx, ngx_str_t *path) { return NGX_OK; @@ -710,7 +702,7 @@ overwrite_done: copy.len = path.len; - tree.init_handler = ngx_http_dav_no_init; + tree.init_handler = NULL; tree.file_handler = ngx_http_dav_copy_file; tree.pre_tree_handler = ngx_http_dav_copy_dir; tree.post_tree_handler = ngx_http_dav_copy_dir_time; @@ -960,7 +952,7 @@ ngx_http_dav_delete_path(ngx_http_reques if (dir) { - tree.init_handler = ngx_http_dav_no_init; + tree.init_handler = NULL; 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; diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -106,7 +106,8 @@ ngx_http_flv_handler(ngx_http_request_t clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c --- a/src/http/modules/ngx_http_gzip_filter_module.c +++ b/src/http/modules/ngx_http_gzip_filter_module.c @@ -14,15 +14,11 @@ typedef struct { ngx_flag_t enable; ngx_flag_t no_buffer; - ngx_flag_t vary; ngx_array_t *types; /* array of ngx_str_t */ ngx_bufs_t bufs; - ngx_uint_t http_version; - ngx_uint_t proxied; - ngx_int_t level; size_t wbits; size_t memlevel; @@ -30,17 +26,6 @@ typedef struct { } ngx_http_gzip_conf_t; -#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 -#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 -#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 -#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 -#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 -#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 -#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 -#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 -#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 - - typedef struct { ngx_chain_t *in; ngx_chain_t *free; @@ -70,8 +55,6 @@ typedef struct { } ngx_http_gzip_ctx_t; -static ngx_int_t ngx_http_gzip_proxied(ngx_http_request_t *r, - ngx_http_gzip_conf_t *conf); static void *ngx_http_gzip_filter_alloc(void *opaque, u_int items, u_int size); static void ngx_http_gzip_filter_free(void *opaque, void *address); @@ -99,27 +82,6 @@ static ngx_conf_post_handler_pt ngx_htt static ngx_conf_post_handler_pt ngx_http_gzip_hash_p = ngx_http_gzip_hash; -static ngx_conf_enum_t ngx_http_gzip_http_version[] = { - { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, - { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, - { ngx_null_string, 0 } -}; - - -static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { - { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, - { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, - { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, - { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, - { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, - { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, - { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, - { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, - { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, - { ngx_null_string, 0 } -}; - - static ngx_command_t ngx_http_gzip_filter_commands[] = { { ngx_string("gzip"), @@ -172,20 +134,6 @@ static ngx_command_t ngx_http_gzip_filt offsetof(ngx_http_gzip_conf_t, no_buffer), NULL }, - { ngx_string("gzip_http_version"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, http_version), - &ngx_http_gzip_http_version }, - - { ngx_string("gzip_proxied"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, - ngx_conf_set_bitmask_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, proxied), - &ngx_http_gzip_proxied_mask }, - { ngx_string("gzip_min_length"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -193,13 +141,6 @@ static ngx_command_t ngx_http_gzip_filt offsetof(ngx_http_gzip_conf_t, min_length), NULL }, - { ngx_string("gzip_vary"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_gzip_conf_t, vary), - NULL }, - ngx_null_command }; @@ -255,10 +196,6 @@ struct gztrailer { static ngx_str_t ngx_http_gzip_ratio = ngx_string("gzip_ratio"); -static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); -static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); -static ngx_str_t ngx_http_gzip_private = ngx_string("private"); - static ngx_http_output_header_filter_pt ngx_http_next_header_filter; static ngx_http_output_body_filter_pt ngx_http_next_body_filter; @@ -267,11 +204,12 @@ static ngx_http_output_body_filter_pt static ngx_int_t ngx_http_gzip_header_filter(ngx_http_request_t *r) { - ngx_str_t *type; - ngx_uint_t i; - ngx_table_elt_t *header; - ngx_http_gzip_ctx_t *ctx; - ngx_http_gzip_conf_t *conf; + ngx_str_t *type; + ngx_uint_t i; + ngx_table_elt_t *h; + ngx_http_gzip_ctx_t *ctx; + ngx_http_gzip_conf_t *conf; + ngx_http_core_loc_conf_t *clcf; conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module); @@ -280,23 +218,16 @@ ngx_http_gzip_header_filter(ngx_http_req && r->headers_out.status != NGX_HTTP_FORBIDDEN && r->headers_out.status != NGX_HTTP_NOT_FOUND) || r->header_only - || r != r->main - || r->http_version < conf->http_version || r->headers_out.content_type.len == 0 || (r->headers_out.content_encoding && r->headers_out.content_encoding->value.len) - || r->headers_in.accept_encoding == NULL || (r->headers_out.content_length_n != -1 && r->headers_out.content_length_n < conf->min_length) - || ngx_strcasestrn(r->headers_in.accept_encoding->value.data, - "gzip", 4 - 1) - == NULL - ) + || ngx_http_gzip_ok(r) != NGX_OK) { return ngx_http_next_header_filter(r); } - type = conf->types->elts; for (i = 0; i < conf->types->nelts; i++) { if (r->headers_out.content_type.len >= type[i].len @@ -309,32 +240,8 @@ ngx_http_gzip_header_filter(ngx_http_req return ngx_http_next_header_filter(r); - found: - if (r->headers_in.via) { - if (conf->proxied & NGX_HTTP_GZIP_PROXIED_OFF) { - return ngx_http_next_header_filter(r); - } - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_ANY) - && ngx_http_gzip_proxied(r, conf) == NGX_DECLINED) - { - return ngx_http_next_header_filter(r); - } - } - - - /* - * if the URL (without the "http://" prefix) is longer than 253 bytes - * then MSIE 4.x can not handle the compressed stream - it waits too long, - * hangs up or crashes - */ - - if (r->headers_in.msie4 && r->unparsed_uri.len > 200) { - return ngx_http_next_header_filter(r); - } - ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_gzip_ctx_t)); if (ctx == NULL) { return NGX_ERROR; @@ -342,33 +249,34 @@ found: ngx_http_set_ctx(r, ctx, ngx_http_gzip_filter_module); - ctx->request = r; - header = ngx_list_push(&r->headers_out.headers); - if (header == NULL) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { return NGX_ERROR; } - header->hash = 1; - header->key.len = sizeof("Content-Encoding") - 1; - header->key.data = (u_char *) "Content-Encoding"; - header->value.len = sizeof("gzip") - 1; - header->value.data = (u_char *) "gzip"; + h->hash = 1; + h->key.len = sizeof("Content-Encoding") - 1; + h->key.data = (u_char *) "Content-Encoding"; + h->value.len = sizeof("gzip") - 1; + h->value.data = (u_char *) "gzip"; - r->headers_out.content_encoding = header; + r->headers_out.content_encoding = h; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (conf->vary) { - header = ngx_list_push(&r->headers_out.headers); - if (header == NULL) { + if (clcf->gzip_vary) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { return NGX_ERROR; } - header->hash = 1; - header->key.len = sizeof("Vary") - 1; - header->key.data = (u_char *) "Vary"; - header->value.len = sizeof("Accept-Encoding") - 1; - header->value.data = (u_char *) "Accept-Encoding"; + h->hash = 1; + h->key.len = sizeof("Vary") - 1; + h->key.data = (u_char *) "Vary"; + h->value.len = sizeof("Accept-Encoding") - 1; + h->value.data = (u_char *) "Accept-Encoding"; } ctx->length = r->headers_out.content_length_n; @@ -383,89 +291,6 @@ found: static ngx_int_t -ngx_http_gzip_proxied(ngx_http_request_t *r, ngx_http_gzip_conf_t *conf) -{ - time_t date, expires; - - if (r->headers_in.authorization - && (conf->proxied & NGX_HTTP_GZIP_PROXIED_AUTH)) - { - return NGX_OK; - } - - if (r->headers_out.expires) { - - if (!(conf->proxied & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { - return NGX_DECLINED; - } - - expires = ngx_http_parse_time(r->headers_out.expires->value.data, - r->headers_out.expires->value.len); - if (expires == NGX_ERROR) { - return NGX_DECLINED; - } - - if (r->headers_out.date) { - date = ngx_http_parse_time(r->headers_out.date->value.data, - r->headers_out.date->value.len); - if (date == NGX_ERROR) { - return NGX_DECLINED; - } - - } else { - date = ngx_time(); - } - - if (expires < date) { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if (r->headers_out.cache_control.elts) { - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_CACHE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_no_cache, NULL) >= 0) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_STORE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_no_store, NULL) >= 0) - { - return NGX_OK; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_PRIVATE) - && ngx_http_parse_multi_header_lines(&r->headers_out.cache_control, - &ngx_http_gzip_private, NULL) >= 0) - { - return NGX_OK; - } - - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_LM) - && r->headers_out.last_modified) - { - return NGX_DECLINED; - } - - if ((conf->proxied & NGX_HTTP_GZIP_PROXIED_NO_ETAG) - && r->headers_out.etag) - { - return NGX_DECLINED; - } - - return NGX_OK; -} - - -static ngx_int_t ngx_http_gzip_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { int rc, wbits, memlevel; @@ -1017,15 +842,11 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf * set by ngx_pcalloc(): * * conf->bufs.num = 0; - * conf->proxied = 0; * conf->types = NULL; */ conf->enable = NGX_CONF_UNSET; conf->no_buffer = NGX_CONF_UNSET; - conf->vary = NGX_CONF_UNSET; - - conf->http_version = NGX_CONF_UNSET_UINT; conf->level = NGX_CONF_UNSET; conf->wbits = (size_t) NGX_CONF_UNSET; @@ -1048,18 +869,12 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf, ngx_conf_merge_bufs_value(conf->bufs, prev->bufs, 4, ngx_pagesize); - ngx_conf_merge_uint_value(conf->http_version, prev->http_version, - NGX_HTTP_VERSION_11); - ngx_conf_merge_bitmask_value(conf->proxied, prev->proxied, - (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); - ngx_conf_merge_value(conf->level, prev->level, 1); ngx_conf_merge_size_value(conf->wbits, prev->wbits, MAX_WBITS); ngx_conf_merge_size_value(conf->memlevel, prev->memlevel, MAX_MEM_LEVEL - 1); ngx_conf_merge_value(conf->min_length, prev->min_length, 20); ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0); - ngx_conf_merge_value(conf->vary, prev->vary, 0); if (conf->types == NULL) { if (prev->types == NULL) { diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -0,0 +1,302 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enable; +} ngx_http_gzip_static_conf_t; + + +static ngx_int_t ngx_http_gzip_static_handler(ngx_http_request_t *r); +static void *ngx_http_gzip_static_create_conf(ngx_conf_t *cf); +static char *ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_gzip_static_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_gzip_static_commands[] = { + + { ngx_string("gzip_static"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_gzip_static_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_gzip_static_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_gzip_static_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_gzip_static_create_conf, /* create location configuration */ + ngx_http_gzip_static_merge_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_gzip_static_module = { + NGX_MODULE_V1, + &ngx_http_gzip_static_module_ctx, /* module context */ + ngx_http_gzip_static_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_gzip_static_handler(ngx_http_request_t *r) +{ + u_char *p; + size_t root; + ngx_str_t path; + ngx_int_t rc; + ngx_uint_t level; + ngx_log_t *log; + ngx_buf_t *b; + ngx_chain_t out; + ngx_table_elt_t *h; + ngx_open_file_info_t of; + ngx_http_core_loc_conf_t *clcf; + ngx_http_gzip_static_conf_t *gzcf; + + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) { + return NGX_HTTP_NOT_ALLOWED; + } + + if (r->uri.data[r->uri.len - 1] == '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module); + + if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) { + return NGX_DECLINED; + } + + log = r->connection->log; + + p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".gz") - 1); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + *p++ = '.'; + *p++ = 'g'; + *p++ = 'z'; + *p = '\0'; + + path.len = p - path.data; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, + "http filename: \"%s\"", path.data); + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + of.test_dir = 0; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; + of.errors = clcf->open_file_cache_errors; + of.events = clcf->open_file_cache_events; + + rc = ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool); + + if (rc == NGX_ERROR) { + + switch (of.err) { + + case 0: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + + case NGX_ENOENT: + case NGX_ENOTDIR: + case NGX_ENAMETOOLONG: + + return NGX_DECLINED; + + case NGX_EACCES: + + level = NGX_LOG_ERR; + rc = NGX_DECLINED; + break; + + default: + + level = NGX_LOG_CRIT; + rc = NGX_DECLINED; + break; + } + + ngx_log_error(level, log, of.err, + ngx_open_file_n " \"%s\" failed", path.data); + + return rc; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd); + + if (of.is_dir) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir"); + return NGX_DECLINED; + } + +#if !(NGX_WIN32) /* the not regular files are probably Unix specific */ + + if (!of.is_file) { + ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, + "\"%s\" is not a regular file", path.data); + + return NGX_HTTP_NOT_FOUND; + } + +#endif + + rc = ngx_http_discard_request_body(r); + + if (rc != NGX_OK) { + return rc; + } + + log->action = "sending response to client"; + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = of.size; + r->headers_out.last_modified_time = of.mtime; + + if (ngx_http_set_content_type(r) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = 1; + h->key.len = sizeof("Content-Encoding") - 1; + h->key.data = (u_char *) "Content-Encoding"; + h->value.len = sizeof("gzip") - 1; + h->value.data = (u_char *) "gzip"; + + r->headers_out.content_encoding = h; + + if (clcf->gzip_vary) { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + h->hash = 1; + h->key.len = sizeof("Vary") - 1; + h->key.data = (u_char *) "Vary"; + h->value.len = sizeof("Accept-Encoding") - 1; + h->value.data = (u_char *) "Accept-Encoding"; + } + + /* we need to allocate all before the header would be sent */ + + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t)); + if (b->file == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + b->file_pos = 0; + b->file_last = of.size; + + b->in_file = b->file_last ? 1 : 0; + b->last_buf = 1; + b->last_in_chain = 1; + + b->file->fd = of.fd; + b->file->name = path; + b->file->log = log; + + out.buf = b; + out.next = NULL; + + return ngx_http_output_filter(r, &out); +} + + +static void * +ngx_http_gzip_static_create_conf(ngx_conf_t *cf) +{ + ngx_http_gzip_static_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_gzip_static_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_gzip_static_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_gzip_static_conf_t *prev = parent; + ngx_http_gzip_static_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_gzip_static_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_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_gzip_static_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -209,7 +209,8 @@ ngx_http_index_handler(ngx_http_request_ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "open index \"%V\"", &path); of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; @@ -292,7 +293,8 @@ ngx_http_index_test_dir(ngx_http_request "http index check dir: \"%V\"", &dir); of.test_dir = 1; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = 0; of.errors = clcf->open_file_cache_errors; if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -58,7 +58,7 @@ static ngx_conf_bitmask_t ngx_http_memc static ngx_command_t ngx_http_memcached_commands[] = { { ngx_string("memcached_pass"), - NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_TAKE1, ngx_http_memcached_pass, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -524,8 +524,6 @@ ngx_http_memcached_create_loc_conf(ngx_c * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; - * - * conf->index = 0; */ conf->upstream.connect_timeout = NGX_CONF_UNSET_MSEC; @@ -548,6 +546,8 @@ ngx_http_memcached_create_loc_conf(ngx_c conf->upstream.pass_request_headers = 0; conf->upstream.pass_request_body = 0; + conf->index = NGX_CONF_UNSET; + return conf; } @@ -582,6 +582,15 @@ ngx_http_memcached_merge_loc_conf(ngx_co |NGX_HTTP_UPSTREAM_FT_OFF; } + if (conf->upstream.upstream == NULL) { + conf->upstream.upstream = prev->upstream.upstream; + conf->upstream.schema = prev->upstream.schema; + } + + if (conf->index == NGX_CONF_UNSET) { + conf->index = prev->index; + } + return NGX_CONF_OK; } diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c --- a/src/http/modules/ngx_http_proxy_module.c +++ b/src/http/modules/ngx_http_proxy_module.c @@ -880,16 +880,9 @@ ngx_http_proxy_create_request(ngx_http_r b->last = e.pos; } -#if (NGX_DEBUG) - { - ngx_str_t s; - - s.len = b->last - b->pos; - s.data = b->pos; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http proxy header:\n\"%V\"", &s); - } -#endif + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http proxy header:\n\"%*s\"", + (size_t) (b->last - b->pos), b->pos); if (plcf->body_set == NULL && plcf->upstream.pass_request_body) { diff --git a/src/http/modules/ngx_http_referer_module.c b/src/http/modules/ngx_http_referer_module.c --- a/src/http/modules/ngx_http_referer_module.c +++ b/src/http/modules/ngx_http_referer_module.c @@ -11,14 +11,7 @@ #define NGX_HTTP_REFERER_NO_URI_PART ((void *) 4) -#if (NGX_PCRE) - -typedef struct { - ngx_regex_t *regex; - ngx_str_t name; -} ngx_http_referer_regex_t; - -#else +#if !(NGX_PCRE) #define ngx_regex_t void @@ -168,34 +161,23 @@ ngx_http_referer_variable(ngx_http_reque #if (NGX_PCRE) if (rlcf->regex) { - ngx_int_t n; - ngx_str_t referer; - ngx_http_referer_regex_t *regex; + ngx_int_t rc; + ngx_str_t referer; referer.len = len - 7; referer.data = ref; - regex = rlcf->regex->elts; - - for (i = 0; i < rlcf->regex->nelts; i++) { - n = ngx_regex_exec(regex[i].regex, &referer, NULL, 0); - - if (n == NGX_REGEX_NO_MATCHED) { - continue; - } + rc = ngx_regex_exec_array(rlcf->regex, &referer, r->connection->log); - if (n < 0) { - ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, - ngx_regex_exec_n - " failed: %d on \"%V\" using \"%V\"", - n, &referer, ®ex[i].name); - return NGX_ERROR; - } - - /* match */ - + if (rc == NGX_OK) { goto valid; } + + if (rc == NGX_ERROR) { + return rc; + } + + /* NGX_DECLINED */ } #endif @@ -242,6 +224,10 @@ ngx_http_referer_create_conf(ngx_conf_t return NGX_CONF_ERROR; } +#if (NGX_PCRE) + conf->regex = NGX_CONF_UNSET_PTR; +#endif + conf->no_referer = NGX_CONF_UNSET; conf->blocked_referer = NGX_CONF_UNSET; @@ -260,6 +246,7 @@ ngx_http_referer_merge_conf(ngx_conf_t * if (conf->keys == NULL) { conf->hash = prev->hash; + ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); ngx_conf_merge_value(conf->no_referer, prev->no_referer, 0); ngx_conf_merge_value(conf->blocked_referer, prev->blocked_referer, 0); @@ -335,6 +322,8 @@ ngx_http_referer_merge_conf(ngx_conf_t * conf->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } + ngx_conf_merge_ptr_value(conf->regex, prev->regex, NULL); + if (conf->no_referer == NGX_CONF_UNSET) { conf->no_referer = 0; } @@ -509,26 +498,25 @@ ngx_http_add_regex_referer(ngx_conf_t *c ngx_str_t *name, ngx_regex_t *regex) { #if (NGX_PCRE) - ngx_str_t err; - ngx_http_referer_regex_t *rr; - u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_str_t err; + ngx_regex_elt_t *re; + u_char errstr[NGX_MAX_CONF_ERRSTR]; - if (rlcf->regex == NULL) { - rlcf->regex = ngx_array_create(cf->pool, 2, - sizeof(ngx_http_referer_regex_t)); + if (rlcf->regex == NGX_CONF_UNSET_PTR) { + rlcf->regex = ngx_array_create(cf->pool, 2, sizeof(ngx_regex_elt_t)); if (rlcf->regex == NULL) { return NGX_CONF_ERROR; } } - rr = ngx_array_push(rlcf->regex); - if (rr == NULL) { + re = ngx_array_push(rlcf->regex); + if (re == NULL) { return NGX_CONF_ERROR; } if (regex) { - rr->regex = regex; - rr->name = *name; + re->regex = regex; + re->name = name->data; return NGX_CONF_OK; } @@ -539,14 +527,14 @@ ngx_http_add_regex_referer(ngx_conf_t *c name->len--; name->data++; - rr->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); + re->regex = ngx_regex_compile(name, NGX_REGEX_CASELESS, cf->pool, &err); - if (rr->regex == NULL) { + if (re->regex == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); return NGX_CONF_ERROR; } - rr->name = *name; + re->name = name->data; return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -415,8 +415,7 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * } ngx_conf_merge_value(conf->builtin_session_cache, - prev->builtin_session_cache, - NGX_SSL_DFLT_BUILTIN_SCACHE); + prev->builtin_session_cache, NGX_SSL_NO_SCACHE); if (conf->shm_zone == NULL) { conf->shm_zone = prev->shm_zone; @@ -448,6 +447,11 @@ ngx_http_ssl_session_cache(ngx_conf_t *c for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[i].data, "off") == 0) { + sscf->builtin_session_cache = NGX_SSL_NO_SCACHE; + continue; + } + if (ngx_strcmp(value[i].data, "builtin") == 0) { sscf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -97,7 +97,8 @@ ngx_http_static_handler(ngx_http_request clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; 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.6.22'; +our $VERSION = '0.6.23'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -643,7 +643,8 @@ sendfile(r, filename, offset = -1, bytes clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; diff --git a/src/http/ngx_http_copy_filter_module.c b/src/http/ngx_http_copy_filter_module.c --- a/src/http/ngx_http_copy_filter_module.c +++ b/src/http/ngx_http_copy_filter_module.c @@ -121,11 +121,8 @@ ngx_http_copy_filter(ngx_http_request_t r->out = ctx->in; } -#if (NGX_DEBUG) ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "copy filter: %i \"%V?%V\"", rc, &r->uri, &r->args); -#endif - } return rc; 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 @@ -71,6 +71,10 @@ static char *ngx_http_core_internal(ngx_ void *conf); static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +#if (NGX_HTTP_GZIP) +static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +#endif static char *ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_core_pool_size(ngx_conf_t *cf, void *post, void *data); @@ -85,6 +89,10 @@ static ngx_conf_deprecated_t ngx_conf_d ngx_conf_deprecated, "optimize_host_names", "optimize_server_names" }; +static ngx_conf_deprecated_t ngx_conf_deprecated_open_file_cache_retest = { + ngx_conf_deprecated, "open_file_cache_retest", "open_file_cache_valid" +}; + static ngx_conf_enum_t ngx_http_core_request_body_in_file[] = { { ngx_string("off"), NGX_HTTP_REQUEST_BODY_FILE_OFF }, @@ -94,6 +102,36 @@ static ngx_conf_enum_t ngx_http_core_re }; +#if (NGX_HTTP_GZIP) + +static ngx_conf_enum_t ngx_http_gzip_http_version[] = { + { ngx_string("1.0"), NGX_HTTP_VERSION_10 }, + { ngx_string("1.1"), NGX_HTTP_VERSION_11 }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_bitmask_t ngx_http_gzip_proxied_mask[] = { + { ngx_string("off"), NGX_HTTP_GZIP_PROXIED_OFF }, + { ngx_string("expired"), NGX_HTTP_GZIP_PROXIED_EXPIRED }, + { ngx_string("no-cache"), NGX_HTTP_GZIP_PROXIED_NO_CACHE }, + { ngx_string("no-store"), NGX_HTTP_GZIP_PROXIED_NO_STORE }, + { ngx_string("private"), NGX_HTTP_GZIP_PROXIED_PRIVATE }, + { ngx_string("no_last_modified"), NGX_HTTP_GZIP_PROXIED_NO_LM }, + { ngx_string("no_etag"), NGX_HTTP_GZIP_PROXIED_NO_ETAG }, + { ngx_string("auth"), NGX_HTTP_GZIP_PROXIED_AUTH }, + { ngx_string("any"), NGX_HTTP_GZIP_PROXIED_ANY }, + { ngx_null_string, 0 } +}; + + +static ngx_str_t ngx_http_gzip_no_cache = ngx_string("no-cache"); +static ngx_str_t ngx_http_gzip_no_store = ngx_string("no-store"); +static ngx_str_t ngx_http_gzip_private = ngx_string("private"); + +#endif + + static ngx_command_t ngx_http_core_commands[] = { { ngx_string("variables_hash_max_size"), @@ -473,11 +511,25 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, open_file_cache), NULL }, + { ngx_string("open_file_cache_valid"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_sec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), + NULL }, + { ngx_string("open_file_cache_retest"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_sec_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, open_file_cache_retest), + offsetof(ngx_http_core_loc_conf_t, open_file_cache_valid), + &ngx_conf_deprecated_open_file_cache_retest }, + + { ngx_string("open_file_cache_min_uses"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, open_file_cache_min_uses), NULL }, { ngx_string("open_file_cache_errors"), @@ -508,6 +560,38 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, resolver_timeout), NULL }, +#if (NGX_HTTP_GZIP) + + { ngx_string("gzip_vary"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, gzip_vary), + NULL }, + + { ngx_string("gzip_http_version"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, gzip_http_version), + &ngx_http_gzip_http_version }, + + { ngx_string("gzip_proxied"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, gzip_proxied), + &ngx_http_gzip_proxied_mask }, + + { ngx_string("gzip_disable"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_gzip_disable, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + +#endif + ngx_null_command }; @@ -600,6 +684,7 @@ ngx_http_handler(ngx_http_request_t *r) } r->valid_location = 1; + r->gzip = 0; r->write_event_handler = ngx_http_core_run_phases; ngx_http_core_run_phases(r); @@ -1386,6 +1471,164 @@ ngx_http_auth_basic_user(ngx_http_reques } +#if (NGX_HTTP_GZIP) + +ngx_int_t +ngx_http_gzip_ok(ngx_http_request_t *r) +{ + time_t date, expires; + ngx_uint_t p; + ngx_array_t *cc; + ngx_table_elt_t *e, *d; + ngx_http_core_loc_conf_t *clcf; + + if (r->gzip == 1) { + return NGX_OK; + } + + if (r->gzip == 2) { + return NGX_DECLINED; + } + + r->gzip = 2; + + if (r != r->main + || r->headers_in.accept_encoding == NULL + || ngx_strcasestrn(r->headers_in.accept_encoding->value.data, + "gzip", 4 - 1) + == NULL + + /* + * if the URL (without the "http://" prefix) is longer than 253 bytes, + * then MSIE 4.x can not handle the compressed stream - it waits + * too long, hangs up or crashes + */ + + || (r->headers_in.msie4 && r->unparsed_uri.len > 200)) + { + return NGX_DECLINED; + } + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (r->http_version < clcf->gzip_http_version) { + return NGX_DECLINED; + } + + if (r->headers_in.via == NULL) { + goto ok; + } + + p = clcf->gzip_proxied; + + if (p & NGX_HTTP_GZIP_PROXIED_OFF) { + return NGX_DECLINED; + } + + if (p & NGX_HTTP_GZIP_PROXIED_ANY) { + goto ok; + } + + if (r->headers_in.authorization && (p & NGX_HTTP_GZIP_PROXIED_AUTH)) { + goto ok; + } + + e = r->headers_out.expires; + + if (e) { + + if (!(p & NGX_HTTP_GZIP_PROXIED_EXPIRED)) { + return NGX_DECLINED; + } + + expires = ngx_http_parse_time(e->value.data, e->value.len); + if (expires == NGX_ERROR) { + return NGX_DECLINED; + } + + d = r->headers_out.date; + + if (d) { + date = ngx_http_parse_time(d->value.data, d->value.len); + if (date == NGX_ERROR) { + return NGX_DECLINED; + } + + } else { + date = ngx_time(); + } + + if (expires < date) { + goto ok; + } + + return NGX_DECLINED; + } + + cc = &r->headers_out.cache_control; + + if (cc->elts) { + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_CACHE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_cache, + NULL) + >= 0) + { + goto ok; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_STORE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_no_store, + NULL) + >= 0) + { + goto ok; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_PRIVATE) + && ngx_http_parse_multi_header_lines(cc, &ngx_http_gzip_private, + NULL) + >= 0) + { + goto ok; + } + + return NGX_DECLINED; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_LM) && r->headers_out.last_modified) { + return NGX_DECLINED; + } + + if ((p & NGX_HTTP_GZIP_PROXIED_NO_ETAG) && r->headers_out.etag) { + return NGX_DECLINED; + } + +ok: + +#if (NGX_PCRE) + + if (clcf->gzip_disable && r->headers_in.user_agent) { + + if (ngx_regex_exec_array(clcf->gzip_disable, + &r->headers_in.user_agent->value, + r->connection->log) + != NGX_DECLINED) + { + return NGX_DECLINED; + } + } + +#endif + + r->gzip = 1; + + return NGX_OK; +} + +#endif + + ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **psr, @@ -2386,6 +2629,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t * lcf->exact_match = 0; * lcf->auto_redirect = 0; * lcf->alias = 0; + * lcf->gzip_proxied = 0; */ lcf->client_max_body_size = NGX_CONF_UNSET; @@ -2416,11 +2660,19 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->server_tokens = NGX_CONF_UNSET; lcf->types_hash_max_size = NGX_CONF_UNSET_UINT; lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT; + lcf->open_file_cache = NGX_CONF_UNSET_PTR; - lcf->open_file_cache_retest = NGX_CONF_UNSET; + lcf->open_file_cache_valid = NGX_CONF_UNSET; + lcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT; lcf->open_file_cache_errors = NGX_CONF_UNSET; lcf->open_file_cache_events = NGX_CONF_UNSET; +#if (NGX_HTTP_GZIP) + lcf->gzip_vary = NGX_CONF_UNSET; + lcf->gzip_http_version = NGX_CONF_UNSET_UINT; + lcf->gzip_disable = NGX_CONF_UNSET_PTR; +#endif + return lcf; } @@ -2618,16 +2870,30 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1); ngx_conf_merge_ptr_value(conf->open_file_cache, - prev->open_file_cache, NULL); - - ngx_conf_merge_sec_value(conf->open_file_cache_retest, - prev->open_file_cache_retest, 60); + prev->open_file_cache, NULL); + + ngx_conf_merge_sec_value(conf->open_file_cache_valid, + prev->open_file_cache_valid, 60); + + ngx_conf_merge_uint_value(conf->open_file_cache_min_uses, + prev->open_file_cache_min_uses, 1); ngx_conf_merge_sec_value(conf->open_file_cache_errors, - prev->open_file_cache_errors, 0); + prev->open_file_cache_errors, 0); ngx_conf_merge_sec_value(conf->open_file_cache_events, - prev->open_file_cache_events, 0); + prev->open_file_cache_events, 0); +#if (NGX_HTTP_GZIP) + + ngx_conf_merge_value(conf->gzip_vary, prev->gzip_vary, 0); + ngx_conf_merge_uint_value(conf->gzip_http_version, prev->gzip_http_version, + NGX_HTTP_VERSION_11); + ngx_conf_merge_bitmask_value(conf->gzip_proxied, prev->gzip_proxied, + (NGX_CONF_BITMASK_SET|NGX_HTTP_GZIP_PROXIED_OFF)); + + ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL); + +#endif return NGX_CONF_OK; } @@ -2869,8 +3135,7 @@ ngx_http_core_server_name(ngx_conf_t *cf sn->regex = NULL; #endif sn->core_srv_conf = cscf; - sn->name.len = value[i].len; - sn->name.data = value[i].data; + sn->name = value[i]; if (value[i].data[0] != '~') { continue; @@ -2895,8 +3160,7 @@ ngx_http_core_server_name(ngx_conf_t *cf return NGX_CONF_ERROR; } - sn->name.len = value[i].len; - sn->name.data = value[i].data; + sn->name = value[i]; } #else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3418,6 +3682,63 @@ ngx_http_core_resolver(ngx_conf_t *cf, n } +#if (NGX_HTTP_GZIP) + +static char * +ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ +#if (NGX_PCRE) + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t err, *value; + ngx_uint_t i; + ngx_regex_elt_t *re; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + if (clcf->gzip_disable == NGX_CONF_UNSET_PTR) { + clcf->gzip_disable = ngx_array_create(cf->pool, 2, + sizeof(ngx_regex_elt_t)); + if (clcf->gzip_disable == NULL) { + return NGX_CONF_ERROR; + } + } + + value = cf->args->elts; + + err.len = NGX_MAX_CONF_ERRSTR; + err.data = errstr; + + for (i = 1; i < cf->args->nelts; i++) { + + re = ngx_array_push(clcf->gzip_disable); + if (re == NULL) { + return NGX_CONF_ERROR; + } + + re->regex = ngx_regex_compile(&value[i], NGX_REGEX_CASELESS, cf->pool, + &err); + + if (re->regex == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "%s", err.data); + return NGX_CONF_ERROR; + } + + re->name = value[i].data; + } + + return NGX_CONF_OK; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"gzip_disable\" requires PCRE library"); + + return NGX_CONF_ERROR; +#endif +} + +#endif + + static char * ngx_http_core_lowat_check(ngx_conf_t *cf, void *post, void *data) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -13,6 +13,17 @@ #include +#define NGX_HTTP_GZIP_PROXIED_OFF 0x0002 +#define NGX_HTTP_GZIP_PROXIED_EXPIRED 0x0004 +#define NGX_HTTP_GZIP_PROXIED_NO_CACHE 0x0008 +#define NGX_HTTP_GZIP_PROXIED_NO_STORE 0x0010 +#define NGX_HTTP_GZIP_PROXIED_PRIVATE 0x0020 +#define NGX_HTTP_GZIP_PROXIED_NO_LM 0x0040 +#define NGX_HTTP_GZIP_PROXIED_NO_ETAG 0x0080 +#define NGX_HTTP_GZIP_PROXIED_AUTH 0x0100 +#define NGX_HTTP_GZIP_PROXIED_ANY 0x0200 + + typedef struct { unsigned default_server:1; unsigned bind:1; @@ -290,12 +301,24 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t recursive_error_pages; /* recursive_error_pages */ ngx_flag_t server_tokens; /* server_tokens */ +#if (NGX_HTTP_GZIP) + ngx_flag_t gzip_vary; /* gzip_vary */ + + ngx_uint_t gzip_http_version; /* gzip_http_version */ + ngx_uint_t gzip_proxied; /* gzip_proxied */ + +#if (NGX_PCRE) + ngx_array_t *gzip_disable; /* gzip_disable */ +#endif +#endif + ngx_array_t *error_pages; /* error_page */ ngx_path_t *client_body_temp_path; /* client_body_temp_path */ ngx_open_file_cache_t *open_file_cache; - time_t open_file_cache_retest; + time_t open_file_cache_valid; + ngx_uint_t open_file_cache_min_uses; ngx_flag_t open_file_cache_errors; ngx_flag_t open_file_cache_events; @@ -329,6 +352,10 @@ ngx_int_t ngx_http_set_exten(ngx_http_re u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name, size_t *root_length, size_t reserved); ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r); +#if (NGX_HTTP_GZIP) +ngx_int_t ngx_http_gzip_ok(ngx_http_request_t *r); +#endif + ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args, ngx_http_request_t **sr, diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -521,10 +521,8 @@ ngx_http_header_filter(ngx_http_request_ *b->last++ = CR; *b->last++ = LF; } -#if (NGX_DEBUG) - *b->last = '\0'; - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "%s\n", b->pos); -#endif + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "%*s\n", (size_t) (b->last - b->pos), b->pos); /* the end of HTTP header */ *b->last++ = CR; *b->last++ = LF; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -1595,7 +1595,11 @@ ngx_http_finalize_request(ngx_http_reque rc = r->post_subrequest->handler(r, r->post_subrequest->data, rc); } - if (rc == NGX_ERROR || rc == NGX_HTTP_REQUEST_TIME_OUT || c->error) { + if (rc == NGX_ERROR + || rc == NGX_HTTP_REQUEST_TIME_OUT + || rc == NGX_HTTP_CLIENT_CLOSED_REQUEST + || c->error) + { if (rc > 0 && r->headers_out.status == 0) { r->headers_out.status = rc; } @@ -1677,8 +1681,8 @@ ngx_http_finalize_request(ngx_http_reque } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0, - "http fast subrequest: \"%V?%V\" done", - &r->uri, &r->args); + "http fast subrequest: \"%V?%V\" done", + &r->uri, &r->args); return; } @@ -2112,6 +2116,12 @@ ngx_http_set_keepalive(ngx_http_request_ hc->nbusy = 0; } +#if (NGX_HTTP_SSL) + if (c->ssl) { + ngx_ssl_free_buffer(c); + } +#endif + rev->handler = ngx_http_keepalive_handler; if (wev->active && (ngx_event_flags & NGX_USE_LEVEL_EVENT)) { diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -430,6 +430,8 @@ struct ngx_http_request_s { unsigned header_timeout_set:1; + unsigned gzip:2; + unsigned proxy:1; unsigned bypass_cache:1; unsigned no_cache:1; diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -976,7 +976,8 @@ ngx_http_script_file_code(ngx_http_scrip clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); of.test_dir = 0; - of.retest = clcf->open_file_cache_retest; + of.valid = clcf->open_file_cache_valid; + of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; 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 @@ -2123,7 +2123,9 @@ ngx_http_upstream_store(ngx_http_request ngx_str_t *temp, path, *last_modified; ngx_temp_file_t *tf; - if (u->pipe->temp_file->file.fd == NGX_INVALID_FILE) { + tf = u->pipe->temp_file; + + if (tf->file.fd == NGX_INVALID_FILE) { /* create file for empty 200 response */ @@ -2148,7 +2150,7 @@ ngx_http_upstream_store(ngx_http_request u->pipe->temp_file = tf; } - temp = &u->pipe->temp_file->file.name; + temp = &tf->file.name; #if !(NGX_WIN32) @@ -2171,9 +2173,7 @@ ngx_http_upstream_store(ngx_http_request lm = ngx_http_parse_time(last_modified->data, last_modified->len); if (lm != NGX_ERROR) { - if (ngx_set_file_time(temp->data, u->pipe->temp_file->file.fd, lm) - != NGX_OK) - { + if (ngx_set_file_time(temp->data, tf->file.fd, lm) != NGX_OK) { err = ngx_errno; failed = ngx_set_file_time_n; name = temp->data; diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c --- a/src/mail/ngx_mail_smtp_handler.c +++ b/src/mail/ngx_mail_smtp_handler.c @@ -29,6 +29,7 @@ static void ngx_mail_smtp_log_rejected_c static u_char smtp_ok[] = "250 2.0.0 OK" CRLF; static u_char smtp_bye[] = "221 2.0.0 Bye" CRLF; +static u_char smtp_starttls[] = "220 2.0.0 Start TLS" CRLF; static u_char smtp_next[] = "334 " CRLF; static u_char smtp_username[] = "334 VXNlcm5hbWU6" CRLF; static u_char smtp_password[] = "334 UGFzc3dvcmQ6" CRLF; @@ -250,6 +251,8 @@ ngx_mail_smtp_auth_state(ngx_event_t *re case NGX_SMTP_STARTTLS: rc = ngx_mail_smtp_starttls(s, c); + s->out.len = sizeof(smtp_starttls) - 1; + s->out.data = smtp_starttls; break; default: diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -208,10 +208,10 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFLAUT_CERTIFICATE); + NGX_DEFLAUT_CERTIFICATE); ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFLAUT_CERTIFICATE_KEY); + NGX_DEFLAUT_CERTIFICATE_KEY); ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, NGX_DEFLAUT_CIPHERS); @@ -261,8 +261,7 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, } ngx_conf_merge_value(conf->builtin_session_cache, - prev->builtin_session_cache, - NGX_SSL_DFLT_BUILTIN_SCACHE); + prev->builtin_session_cache, NGX_SSL_NO_SCACHE); if (conf->shm_zone == NULL) { conf->shm_zone = prev->shm_zone; @@ -294,6 +293,11 @@ ngx_mail_ssl_session_cache(ngx_conf_t *c for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[i].data, "off") == 0) { + scf->builtin_session_cache = NGX_SSL_NO_SCACHE; + continue; + } + if (ngx_strcmp(value[i].data, "builtin") == 0) { scf->builtin_session_cache = NGX_SSL_DFLT_BUILTIN_SCACHE; continue; diff --git a/src/os/unix/ngx_freebsd.h b/src/os/unix/ngx_freebsd.h --- a/src/os/unix/ngx_freebsd.h +++ b/src/os/unix/ngx_freebsd.h @@ -11,13 +11,14 @@ ngx_chain_t *ngx_freebsd_sendfile_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); -extern int ngx_freebsd_kern_osreldate; -extern int ngx_freebsd_hw_ncpu; -extern u_long ngx_freebsd_net_inet_tcp_sendspace; -extern int ngx_freebsd_kern_ipc_zero_copy_send; +extern int ngx_freebsd_kern_osreldate; +extern int ngx_freebsd_hw_ncpu; +extern u_long ngx_freebsd_net_inet_tcp_sendspace; +extern int ngx_freebsd_kern_ipc_zero_copy_send; -extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; -extern ngx_uint_t ngx_freebsd_use_tcp_nopush; +extern ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +extern ngx_uint_t ngx_freebsd_use_tcp_nopush; +extern ngx_uint_t ngx_freebsd_debug_malloc; #endif /* _NGX_FREEBSD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -23,8 +23,9 @@ int ngx_freebsd_machdep_hlt_logical_ int ngx_freebsd_kern_ipc_zero_copy_send; -ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; -ngx_uint_t ngx_freebsd_use_tcp_nopush; +ngx_uint_t ngx_freebsd_sendfile_nbytes_bug; +ngx_uint_t ngx_freebsd_use_tcp_nopush; +ngx_uint_t ngx_freebsd_debug_malloc; static ngx_os_io_t ngx_freebsd_io = { @@ -86,6 +87,16 @@ ngx_debug_init() malloc_options = "J"; #endif + ngx_freebsd_debug_malloc = 1; + +#else + char *mo; + + mo = getenv("MALLOC_OPTIONS"); + + if (mo && ngx_strchr(mo, 'J')) { + ngx_freebsd_debug_malloc = 1; + } #endif }