# HG changeset patch # User Igor Sysoev # Date 1330459200 -14400 # Node ID f5b859b2f097df1a0638a9e249ab8a7f8a23c7c4 # Parent dd668cf20818600a500bc8386dd0d99abafbcb2f nginx 1.1.16 *) Change: the simultaneous subrequest limit has been raised to 200. *) Feature: the "from" parameter of the "disable_symlinks" directive. *) Feature: the "return" and "error_page" directives can be used to return 307 redirections. *) Bugfix: a segmentation fault might occur in a worker process if the "resolver" directive was used and there was no "error_log" directive specified at global level. Thanks to Roman Arutyunyan. *) Bugfix: a segmentation fault might occur in a worker process if the "proxy_http_version 1.1" or "fastcgi_keep_conn on" directives were used. *) Bugfix: memory leaks. Thanks to Lanshun Zhou. *) Bugfix: in the "disable_symlinks" directive. *) Bugfix: on ZFS filesystem disk cache size might be calculated incorrectly; the bug had appeared in 1.0.1. *) Bugfix: nginx could not be built by the icc 12.1 compiler. *) Bugfix: nginx could not be built by gcc on Solaris; the bug had appeared in 1.1.15. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,36 @@ +Changes with nginx 1.1.16 29 Feb 2012 + + *) Change: the simultaneous subrequest limit has been raised to 200. + + *) Feature: the "from" parameter of the "disable_symlinks" directive. + + *) Feature: the "return" and "error_page" directives can be used to + return 307 redirections. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "resolver" directive was used and there was no "error_log" directive + specified at global level. + Thanks to Roman Arutyunyan. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "proxy_http_version 1.1" or "fastcgi_keep_conn on" directives were + used. + + *) Bugfix: memory leaks. + Thanks to Lanshun Zhou. + + *) Bugfix: in the "disable_symlinks" directive. + + *) Bugfix: on ZFS filesystem disk cache size might be calculated + incorrectly; the bug had appeared in 1.0.1. + + *) Bugfix: nginx could not be built by the icc 12.1 compiler. + + *) Bugfix: nginx could not be built by gcc on Solaris; the bug had + appeared in 1.1.15. + + Changes with nginx 1.1.15 15 Feb 2012 *) Feature: the "disable_symlinks" directive. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,37 @@ +Изменения в nginx 1.1.16 29.02.2012 + + *) Изменение: ограничение на количество одновременных подзапросов + поднято до 200. + + *) Добавление: параметр from в директиве disable_symlinks. + + *) Добавление: директивы return и error_page теперь могут использоваться + для возврата перенаправлений с кодом 307. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовалась директива resolver и на глобальном уровне не была + задана директива error_log. + Спасибо Роману Арутюняну. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовались директивы "proxy_http_version 1.1" или + "fastcgi_keep_conn on". + + *) Исправление: утечек памяти. + Спасибо Lanshun Zhou. + + *) Исправление: в директиве disable_symlinks. + + *) Исправление: при использовании ZFS размер кэша на диске мог считаться + некорректно; ошибка появилась в 1.0.1. + + *) Исправление: nginx не собирался компилятором icc 12.1. + + *) Исправление: nginx не собирался gcc на Solaris; ошибка появилась в + 1.1.15. + + Изменения в nginx 1.1.15 15.02.2012 *) Добавление: директива disable_symlinks. diff --git a/auto/cc/name b/auto/cc/name --- a/auto/cc/name +++ b/auto/cc/name @@ -64,16 +64,16 @@ if [ "$CC" = bcc32 ]; then echo " + using Borland C++ compiler" else +if `$CC -V 2>&1 | grep '^Intel(R) C' >/dev/null 2>&1`; then + NGX_CC_NAME=icc + echo " + using Intel C++ compiler" + +else if `$CC -v 2>&1 | grep 'gcc version' >/dev/null 2>&1`; then NGX_CC_NAME=gcc echo " + using GNU C compiler" else -if `$CC -V 2>&1 | grep '^Intel(R) C' >/dev/null 2>&1`; then - NGX_CC_NAME=icc - echo " + using Intel C++ compiler" - -else if `$CC -V 2>&1 | grep 'Sun C' >/dev/null 2>&1`; then NGX_CC_NAME=sunc echo " + using Sun C compiler" diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -9,8 +9,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1001015 -#define NGINX_VERSION "1.1.15" +#define nginx_version 1001016 +#define NGINX_VERSION "1.1.16" #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 @@ -229,6 +229,7 @@ ngx_open_cached_file(ngx_open_file_cache && now - file->created < of->valid #if (NGX_HAVE_OPENAT) && of->disable_symlinks == file->disable_symlinks + && of->disable_symlinks_from == file->disable_symlinks_from #endif )) { @@ -395,6 +396,7 @@ update: file->err = of->err; #if (NGX_HAVE_OPENAT) file->disable_symlinks = of->disable_symlinks; + file->disable_symlinks_from = of->disable_symlinks_from; #endif if (of->err == 0) { @@ -504,8 +506,8 @@ ngx_openat_file_owner(ngx_fd_t at_fd, co fd = ngx_openat_file(at_fd, name, mode, create, access); - if (fd == NGX_FILE_ERROR) { - return NGX_FILE_ERROR; + if (fd == NGX_INVALID_FILE) { + return NGX_INVALID_FILE; } if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW) @@ -565,7 +567,6 @@ ngx_open_file_wrapper(ngx_str_t *name, n u_char *p, *cp, *end; ngx_fd_t at_fd; ngx_str_t at_name; - ngx_file_info_t fi; if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { fd = ngx_open_file(name->data, mode, create, access); @@ -582,22 +583,45 @@ ngx_open_file_wrapper(ngx_str_t *name, n p = name->data; end = p + name->len; - at_fd = AT_FDCWD; at_name = *name; - if (p[0] == '/') { - at_fd = ngx_openat_file(at_fd, "/", - NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, - NGX_FILE_OPEN, 0); + if (of->disable_symlinks_from) { + + cp = p + of->disable_symlinks_from; + + *cp = '\0'; + + at_fd = ngx_open_file(p, NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0); + + *cp = '/'; - if (at_fd == NGX_FILE_ERROR) { + if (at_fd == NGX_INVALID_FILE) { + of->err = ngx_errno; + of->failed = ngx_open_file_n; + return NGX_INVALID_FILE; + } + + at_name.len = of->disable_symlinks_from; + p = cp + 1; + + } else if (*p == '/') { + + at_fd = ngx_open_file("/", + NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0); + + if (at_fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_openat_file_n; - return NGX_FILE_ERROR; + return NGX_INVALID_FILE; } at_name.len = 1; p++; + + } else { + at_fd = NGX_AT_FDCWD; } for ( ;; ) { @@ -615,12 +639,12 @@ ngx_open_file_wrapper(ngx_str_t *name, n if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { fd = ngx_openat_file_owner(at_fd, p, - NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, + NGX_FILE_SEARCH|NGX_FILE_NONBLOCK, NGX_FILE_OPEN, 0, log); } else { fd = ngx_openat_file(at_fd, p, - NGX_FILE_RDONLY|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW, + NGX_FILE_SEARCH|NGX_FILE_NONBLOCK|NGX_FILE_NOFOLLOW, NGX_FILE_OPEN, 0); } @@ -632,9 +656,9 @@ ngx_open_file_wrapper(ngx_str_t *name, n goto failed; } - if (at_fd != AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { + if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%V\" failed", at_name); + ngx_close_file_n " \"%V\" failed", &at_name); } p = cp + 1; @@ -642,47 +666,34 @@ ngx_open_file_wrapper(ngx_str_t *name, n at_name.len = cp - at_name.data; } - if (p == end && at_fd != AT_FDCWD) { + if (p == end) { /* - * If pathname ends with a trailing slash, check if last path - * component is a directory; if not, fail with ENOTDIR as per - * POSIX. + * If pathname ends with a trailing slash, assume the last path + * component is a directory and reopen it with requested flags; + * if not, fail with ENOTDIR as per POSIX. * - * We use separate check instead of O_DIRECTORY in the loop above, - * as O_DIRECTORY doesn't work on FreeBSD 8. - * - * Note this returns already opened file descriptor, with different - * mode/create/access. This is believed to be safe as we don't - * use this codepath to create directories. + * We cannot rely on O_DIRECTORY in the loop above to check + * that the last path component is a directory because + * O_DIRECTORY doesn't work on FreeBSD 8. Fortunately, by + * reopening a directory, we don't depend on it at all. */ - if (ngx_fd_info(at_fd, &fi) == NGX_FILE_ERROR) { - of->err = ngx_errno; - of->failed = ngx_fd_info_n; - fd = NGX_INVALID_FILE; - - goto failed; - } - - if (ngx_is_dir(&fi)) { - return at_fd; - } - - of->err = ENOTDIR; - of->failed = ngx_openat_file_n; - fd = NGX_INVALID_FILE; - - goto failed; + fd = ngx_openat_file(at_fd, ".", mode, create, access); + goto done; } - if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { + if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER + && !(create & (NGX_FILE_CREATE_OR_OPEN|NGX_FILE_TRUNCATE))) + { fd = ngx_openat_file_owner(at_fd, p, mode, create, access, log); } else { fd = ngx_openat_file(at_fd, p, mode|NGX_FILE_NOFOLLOW, create, access); } +done: + if (fd == NGX_INVALID_FILE) { of->err = ngx_errno; of->failed = ngx_openat_file_n; @@ -690,9 +701,9 @@ ngx_open_file_wrapper(ngx_str_t *name, n failed: - if (at_fd != AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { + if (at_fd != NGX_AT_FDCWD && ngx_close_file(at_fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%V\" failed", at_name); + ngx_close_file_n " \"%V\" failed", &at_name); } return fd; @@ -1131,20 +1142,15 @@ ngx_open_file_lookup(ngx_open_file_cache /* hash == node->key */ - do { - file = (ngx_cached_open_file_t *) node; + file = (ngx_cached_open_file_t *) node; - rc = ngx_strcmp(name->data, file->name); + rc = ngx_strcmp(name->data, file->name); - if (rc == 0) { - return file; - } + if (rc == 0) { + return file; + } - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; + node = (rc < 0) ? node->left : node->right; } return NULL; 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 @@ -33,6 +33,7 @@ typedef struct { ngx_uint_t min_uses; #if (NGX_HAVE_OPENAT) + size_t disable_symlinks_from; unsigned disable_symlinks:2; #endif @@ -69,6 +70,7 @@ struct ngx_cached_open_file_s { uint32_t uses; #if (NGX_HAVE_OPENAT) + size_t disable_symlinks_from; unsigned disable_symlinks:2; #endif 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 @@ -189,11 +189,6 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ uc->sockaddr = u.addrs->sockaddr; uc->socklen = u.addrs->socklen; uc->server = u.addrs->name; - - uc->log = cf->cycle->new_log; - uc->log.handler = ngx_resolver_log_error; - uc->log.data = uc; - uc->log.action = "resolving"; } return r; @@ -876,6 +871,12 @@ ngx_resolver_send_query(ngx_resolver_t * } if (uc->connection == NULL) { + + uc->log = *r->log; + uc->log.handler = ngx_resolver_log_error; + uc->log.data = uc; + uc->log.action = "resolving"; + if (ngx_udp_connect(uc) != NGX_OK) { return NGX_ERROR; } @@ -1688,20 +1689,15 @@ ngx_resolver_lookup_name(ngx_resolver_t /* hash == node->key */ - do { - rn = (ngx_resolver_node_t *) node; - - rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); - - if (rc == 0) { - return rn; - } - - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; + rn = (ngx_resolver_node_t *) node; + + rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen); + + if (rc == 0) { + return rn; + } + + node = (rc < 0) ? node->left : node->right; } /* not found */ diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -287,7 +287,7 @@ ngx_gmtime(time_t t, ngx_tm_t *tp) days = n / 86400; - /* Jaunary 1, 1970 was Thursday */ + /* January 1, 1970 was Thursday */ wday = (4 + days) % 7; diff --git a/src/event/ngx_event.h b/src/event/ngx_event.h --- a/src/event/ngx_event.h +++ b/src/event/ngx_event.h @@ -83,7 +83,7 @@ struct ngx_event_s { #endif #if (NGX_WIN32) - /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was succesfull */ + /* setsockopt(SO_UPDATE_ACCEPT_CONTEXT) was successful */ unsigned accept_context_updated:1; #endif 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 @@ -842,7 +842,7 @@ ngx_ssl_recv(ngx_connection_t *c, u_char case NGX_ERROR: c->read->error = 1; - /* fall thruogh */ + /* fall through */ case NGX_AGAIN: return c->ssl->last; @@ -1801,44 +1801,39 @@ ngx_ssl_get_cached_session(ngx_ssl_conn_ /* hash == node->key */ - do { - sess_id = (ngx_ssl_sess_id_t *) node; - - rc = ngx_memn2cmp(id, sess_id->id, - (size_t) len, (size_t) node->data); - if (rc == 0) { - - if (sess_id->expire > ngx_time()) { - ngx_memcpy(buf, sess_id->session, sess_id->len); - - ngx_shmtx_unlock(&shpool->mutex); - - p = buf; - sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); - - return sess; - } - - ngx_queue_remove(&sess_id->queue); - - ngx_rbtree_delete(&cache->session_rbtree, node); - - ngx_slab_free_locked(shpool, sess_id->session); + sess_id = (ngx_ssl_sess_id_t *) node; + + rc = ngx_memn2cmp(id, sess_id->id, (size_t) len, (size_t) node->data); + + if (rc == 0) { + + if (sess_id->expire > ngx_time()) { + ngx_memcpy(buf, sess_id->session, sess_id->len); + + ngx_shmtx_unlock(&shpool->mutex); + + p = buf; + sess = d2i_SSL_SESSION(NULL, &p, sess_id->len); + + return sess; + } + + 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) - ngx_slab_free_locked(shpool, sess_id->id); + ngx_slab_free_locked(shpool, sess_id->id); #endif - ngx_slab_free_locked(shpool, sess_id); - - sess = NULL; - - goto done; - } - - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; + ngx_slab_free_locked(shpool, sess_id); + + sess = NULL; + + goto done; + } + + node = (rc < 0) ? node->left : node->right; } done: @@ -1908,31 +1903,26 @@ ngx_ssl_remove_session(SSL_CTX *ssl, ngx /* hash == node->key */ - do { - sess_id = (ngx_ssl_sess_id_t *) node; - - rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data); - - if (rc == 0) { - - ngx_queue_remove(&sess_id->queue); - - ngx_rbtree_delete(&cache->session_rbtree, node); - - ngx_slab_free_locked(shpool, sess_id->session); + sess_id = (ngx_ssl_sess_id_t *) node; + + rc = ngx_memn2cmp(id, sess_id->id, len, (size_t) node->data); + + if (rc == 0) { + + 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) - ngx_slab_free_locked(shpool, sess_id->id); + ngx_slab_free_locked(shpool, sess_id->id); #endif - ngx_slab_free_locked(shpool, sess_id); - - goto done; - } - - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; + ngx_slab_free_locked(shpool, sess_id); + + goto done; + } + + node = (rc < 0) ? node->left : node->right; } done: 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 @@ -401,13 +401,14 @@ ngx_event_pipe_read_upstream(ngx_event_p if (cl->buf->last - cl->buf->pos >= p->length) { + p->free_raw_bufs = cl->next; + /* STUB */ cl->buf->num = p->num++; if (p->input_filter(p, cl->buf) == NGX_ERROR) { return NGX_ABORT; } - p->free_raw_bufs = cl->next; ngx_free_chain(p->pool, cl); } } @@ -968,7 +969,7 @@ ngx_event_pipe_add_free_buf(ngx_event_pi return NGX_OK; } - /* the first free buf is partialy filled, thus add the free buf after it */ + /* the first free buf is partially filled, thus add the free buf after it */ cl->next = p->free_raw_bufs->next; p->free_raw_bufs->next = cl; diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -95,8 +95,8 @@ static ngx_http_module_t ngx_http_autoi NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_autoindex_create_loc_conf, /* create location configration */ - ngx_http_autoindex_merge_loc_conf /* merge location configration */ + ngx_http_autoindex_create_loc_conf, /* create location configuration */ + ngx_http_autoindex_merge_loc_conf /* merge location configuration */ }; 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 @@ -109,9 +109,10 @@ ngx_http_flv_handler(ngx_http_request_t of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -129,9 +129,10 @@ ngx_http_gzip_static_handler(ngx_http_re of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- a/src/http/modules/ngx_http_headers_filter_module.c +++ b/src/http/modules/ngx_http_headers_filter_module.c @@ -149,7 +149,9 @@ ngx_http_headers_filter(ngx_http_request && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY && r->headers_out.status != NGX_HTTP_MOVED_TEMPORARILY - && r->headers_out.status != NGX_HTTP_NOT_MODIFIED)) + && r->headers_out.status != NGX_HTTP_SEE_OTHER + && r->headers_out.status != NGX_HTTP_NOT_MODIFIED + && r->headers_out.status != NGX_HTTP_TEMPORARY_REDIRECT)) { return ngx_http_next_header_filter(r); } 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 @@ -62,8 +62,8 @@ static ngx_http_module_t ngx_http_index NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_index_create_loc_conf, /* create location configration */ - ngx_http_index_merge_loc_conf /* merge location configration */ + ngx_http_index_create_loc_conf, /* create location configuration */ + ngx_http_index_merge_loc_conf /* merge location configuration */ }; @@ -209,9 +209,10 @@ ngx_http_index_handler(ngx_http_request_ of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -307,9 +308,10 @@ ngx_http_index_test_dir(ngx_http_request of.test_only = 1; of.valid = clcf->open_file_cache_valid; of.errors = clcf->open_file_cache_errors; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &dir, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) != NGX_OK) diff --git a/src/http/modules/ngx_http_limit_conn_module.c b/src/http/modules/ngx_http_limit_conn_module.c --- a/src/http/modules/ngx_http_limit_conn_module.c +++ b/src/http/modules/ngx_http_limit_conn_module.c @@ -118,8 +118,8 @@ static ngx_http_module_t ngx_http_limit NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_limit_conn_create_conf, /* create location configration */ - ngx_http_limit_conn_merge_conf /* merge location configration */ + ngx_http_limit_conn_create_conf, /* create location configuration */ + ngx_http_limit_conn_merge_conf /* merge location configuration */ }; @@ -325,20 +325,15 @@ ngx_http_limit_conn_lookup(ngx_rbtree_t /* hash == node->key */ - do { - lcn = (ngx_http_limit_conn_node_t *) &node->color; + lcn = (ngx_http_limit_conn_node_t *) &node->color; - rc = ngx_memn2cmp(vv->data, lcn->data, - (size_t) vv->len, (size_t) lcn->len); - if (rc == 0) { - return node; - } + rc = ngx_memn2cmp(vv->data, lcn->data, + (size_t) vv->len, (size_t) lcn->len); + if (rc == 0) { + return node; + } - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && hash == node->key); - - break; + node = (rc < 0) ? node->left : node->right; } return NULL; diff --git a/src/http/modules/ngx_http_limit_req_module.c b/src/http/modules/ngx_http_limit_req_module.c --- a/src/http/modules/ngx_http_limit_req_module.c +++ b/src/http/modules/ngx_http_limit_req_module.c @@ -121,8 +121,8 @@ static ngx_http_module_t ngx_http_limit NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_limit_req_create_conf, /* create location configration */ - ngx_http_limit_req_merge_conf /* merge location configration */ + ngx_http_limit_req_create_conf, /* create location configuration */ + ngx_http_limit_req_merge_conf /* merge location configuration */ }; @@ -385,47 +385,42 @@ ngx_http_limit_req_lookup(ngx_http_limit /* hash == node->key */ - do { - lr = (ngx_http_limit_req_node_t *) &node->color; - - rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); + lr = (ngx_http_limit_req_node_t *) &node->color; - if (rc == 0) { - ngx_queue_remove(&lr->queue); - ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); - - ms = (ngx_msec_int_t) (now - lr->last); - - excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; - - if (excess < 0) { - excess = 0; - } + rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); - *ep = excess; - - if ((ngx_uint_t) excess > limit->burst) { - return NGX_BUSY; - } + if (rc == 0) { + ngx_queue_remove(&lr->queue); + ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); - if (account) { - lr->excess = excess; - lr->last = now; - return NGX_OK; - } + ms = (ngx_msec_int_t) (now - lr->last); - lr->count++; + excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; - ctx->node = lr; - - return NGX_AGAIN; + if (excess < 0) { + excess = 0; } - node = (rc < 0) ? node->left : node->right; + *ep = excess; + + if ((ngx_uint_t) excess > limit->burst) { + return NGX_BUSY; + } - } while (node != sentinel && hash == node->key); + if (account) { + lr->excess = excess; + lr->last = now; + return NGX_OK; + } - break; + lr->count++; + + ctx->node = lr; + + return NGX_AGAIN; + } + + node = (rc < 0) ? node->left : node->right; } *ep = 0; diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -161,8 +161,8 @@ static ngx_http_module_t ngx_http_log_m NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_log_create_loc_conf, /* create location configration */ - ngx_http_log_merge_loc_conf /* merge location configration */ + ngx_http_log_create_loc_conf, /* create location configuration */ + ngx_http_log_merge_loc_conf /* merge location configuration */ }; @@ -377,10 +377,10 @@ ngx_http_log_script_write(ngx_http_reque if (!r->root_tested) { - /* test root directory existance */ + /* test root directory existence */ if (ngx_http_map_uri_to_path(r, &path, &root, 0) == NULL) { - /* simulate successfull logging */ + /* simulate successful logging */ return len; } @@ -394,22 +394,24 @@ ngx_http_log_script_write(ngx_http_reque of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + /* simulate successful logging */ + return len; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) { if (of.err == 0) { - /* simulate successfull logging */ + /* simulate successful logging */ return len; } ngx_log_error(NGX_LOG_ERR, r->connection->log, of.err, "testing \"%s\" existence failed", path.data); - /* simulate successfull logging */ + /* simulate successful logging */ return len; } @@ -417,7 +419,7 @@ ngx_http_log_script_write(ngx_http_reque ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ENOTDIR, "testing \"%s\" existence failed", path.data); - /* simulate successfull logging */ + /* simulate successful logging */ return len; } } @@ -426,7 +428,7 @@ ngx_http_log_script_write(ngx_http_reque script->values->elts) == NULL) { - /* simulate successfull logging */ + /* simulate successful logging */ return len; } @@ -444,16 +446,18 @@ ngx_http_log_script_write(ngx_http_reque of.valid = llcf->open_file_cache_valid; of.min_uses = llcf->open_file_cache_min_uses; of.directio = NGX_OPEN_FILE_DIRECTIO_OFF; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &log, &of) != NGX_OK) { + /* simulate successful logging */ + return len; + } if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) { ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, "%s \"%s\" failed", of.failed, log.data); - /* simulate successfull logging */ + /* simulate successful logging */ return len; } 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 @@ -115,8 +115,8 @@ static ngx_http_module_t ngx_http_memca NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_memcached_create_loc_conf, /* create location configration */ - ngx_http_memcached_merge_loc_conf /* merge location configration */ + ngx_http_memcached_create_loc_conf, /* create location configuration */ + ngx_http_memcached_merge_loc_conf /* merge location configuration */ }; diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- a/src/http/modules/ngx_http_mp4_module.c +++ b/src/http/modules/ngx_http_mp4_module.c @@ -440,9 +440,10 @@ ngx_http_mp4_handler(ngx_http_request_t of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_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 @@ -530,8 +530,8 @@ static ngx_http_module_t ngx_http_proxy NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_proxy_create_loc_conf, /* create location configration */ - ngx_http_proxy_merge_loc_conf /* merge location configration */ + ngx_http_proxy_create_loc_conf, /* create location configuration */ + ngx_http_proxy_merge_loc_conf /* merge location configuration */ }; diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c --- a/src/http/modules/ngx_http_random_index_module.c +++ b/src/http/modules/ngx_http_random_index_module.c @@ -49,8 +49,8 @@ static ngx_http_module_t ngx_http_rando NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_random_index_create_loc_conf, /* create location configration */ - ngx_http_random_index_merge_loc_conf /* merge location configration */ + ngx_http_random_index_create_loc_conf, /* create location configuration */ + ngx_http_random_index_merge_loc_conf /* merge location configuration */ }; diff --git a/src/http/modules/ngx_http_rewrite_module.c b/src/http/modules/ngx_http_rewrite_module.c --- a/src/http/modules/ngx_http_rewrite_module.c +++ b/src/http/modules/ngx_http_rewrite_module.c @@ -112,8 +112,8 @@ static ngx_http_module_t ngx_http_rewri NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_rewrite_create_loc_conf, /* create location configration */ - ngx_http_rewrite_merge_loc_conf /* merge location configration */ + ngx_http_rewrite_create_loc_conf, /* create location configuration */ + ngx_http_rewrite_merge_loc_conf /* merge location configuration */ }; 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 @@ -94,9 +94,10 @@ ngx_http_static_handler(ngx_http_request of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -166,8 +166,8 @@ static ngx_http_module_t ngx_http_useri NULL, /* create server configuration */ NULL, /* merge server configuration */ - ngx_http_userid_create_conf, /* create location configration */ - ngx_http_userid_merge_conf /* merge location configration */ + ngx_http_userid_create_conf, /* create location configuration */ + ngx_http_userid_merge_conf /* merge location configuration */ }; 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 @@ -21,7 +21,9 @@ our @EXPORT = qw( HTTP_MOVED_PERMANENTLY HTTP_MOVED_TEMPORARILY HTTP_REDIRECT + HTTP_SEE_OTHER HTTP_NOT_MODIFIED + HTTP_TEMPORARY_REDIRECT HTTP_BAD_REQUEST HTTP_UNAUTHORIZED @@ -48,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.15'; +our $VERSION = '1.1.16'; require XSLoader; XSLoader::load('nginx', $VERSION); @@ -67,7 +69,9 @@ use constant HTTP_PARTIAL_CONTENT use constant HTTP_MOVED_PERMANENTLY => 301; use constant HTTP_MOVED_TEMPORARILY => 302; use constant HTTP_REDIRECT => 302; +use constant HTTP_SEE_OTHER => 303; use constant HTTP_NOT_MODIFIED => 304; +use constant HTTP_TEMPORARY_REDIRECT => 307; use constant HTTP_BAD_REQUEST => 400; use constant HTTP_UNAUTHORIZED => 401; 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 @@ -662,9 +662,10 @@ sendfile(r, filename, offset = -1, bytes of.min_uses = clcf->open_file_cache_min_uses; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + XSRETURN_EMPTY; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) 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 @@ -76,6 +76,10 @@ static ngx_uint_t ngx_http_gzip_quantity static char *ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #endif +#if (NGX_HAVE_OPENAT) +static char *ngx_http_disable_symlinks(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); @@ -187,18 +191,6 @@ static ngx_str_t ngx_http_gzip_private #endif -#if (NGX_HAVE_OPENAT) - -static ngx_conf_enum_t ngx_http_core_disable_symlinks[] = { - { ngx_string("off"), NGX_DISABLE_SYMLINKS_OFF }, - { ngx_string("if_not_owner"), NGX_DISABLE_SYMLINKS_NOTOWNER }, - { ngx_string("on"), NGX_DISABLE_SYMLINKS_ON }, - { ngx_null_string, 0 } -}; - -#endif - - static ngx_command_t ngx_http_core_commands[] = { { ngx_string("variables_hash_max_size"), @@ -779,11 +771,11 @@ static ngx_command_t ngx_http_core_comm #if (NGX_HAVE_OPENAT) { ngx_string("disable_symlinks"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_disable_symlinks, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_core_loc_conf_t, disable_symlinks), - &ngx_http_core_disable_symlinks }, + 0, + NULL }, #endif @@ -1320,9 +1312,11 @@ ngx_http_core_try_files_phase(ngx_http_r of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_OK; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -1824,8 +1818,11 @@ ngx_http_send_response(ngx_http_request_ return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (status >= NGX_HTTP_MOVED_PERMANENTLY && status <= NGX_HTTP_SEE_OTHER) { - + if (status == NGX_HTTP_MOVED_PERMANENTLY + || status == NGX_HTTP_MOVED_TEMPORARILY + || status == NGX_HTTP_SEE_OTHER + || status == NGX_HTTP_TEMPORARY_REDIRECT) + { ngx_http_clear_location(r); r->headers_out.location = ngx_list_push(&r->headers_out.headers); @@ -2642,6 +2639,56 @@ ngx_http_cleanup_add(ngx_http_request_t } +ngx_int_t +ngx_http_set_disable_symlinks(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of) +{ +#if (NGX_HAVE_OPENAT) + u_char *p; + ngx_str_t from; + + of->disable_symlinks = clcf->disable_symlinks; + + if (clcf->disable_symlinks_from == NULL) { + return NGX_OK; + } + + if (ngx_http_complex_value(r, clcf->disable_symlinks_from, &from) + != NGX_OK) + { + return NGX_ERROR; + } + + if (from.len == 0 + || from.len > path->len + || ngx_memcmp(path->data, from.data, from.len) != 0) + { + return NGX_OK; + } + + if (from.len == path->len) { + of->disable_symlinks = NGX_DISABLE_SYMLINKS_OFF; + return NGX_OK; + } + + p = path->data + from.len; + + if (*p == '/') { + of->disable_symlinks_from = from.len; + return NGX_OK; + } + + p--; + + if (*p == '/') { + of->disable_symlinks_from = from.len - 1; + } +#endif + + return NGX_OK; +} + + static char * ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { @@ -3372,6 +3419,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t #if (NGX_HAVE_OPENAT) clcf->disable_symlinks = NGX_CONF_UNSET_UINT; + clcf->disable_symlinks_from = NGX_CONF_UNSET_PTR; #endif return clcf; @@ -3656,6 +3704,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t #if (NGX_HAVE_OPENAT) ngx_conf_merge_uint_value(conf->disable_symlinks, prev->disable_symlinks, NGX_DISABLE_SYMLINKS_OFF); + ngx_conf_merge_ptr_value(conf->disable_symlinks_from, + prev->disable_symlinks_from, NULL); #endif return NGX_CONF_OK; @@ -4791,6 +4841,100 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng #endif +#if (NGX_HAVE_OPENAT) + +static char * +ngx_http_disable_symlinks(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf = conf; + + ngx_str_t *value; + ngx_uint_t i; + ngx_http_compile_complex_value_t ccv; + + if (clcf->disable_symlinks != NGX_CONF_UNSET_UINT) { + return "is duplicate"; + } + + value = cf->args->elts; + + for (i = 1; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "off") == 0) { + clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_OFF; + continue; + } + + if (ngx_strcmp(value[i].data, "if_not_owner") == 0) { + clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_NOTOWNER; + continue; + } + + if (ngx_strcmp(value[i].data, "on") == 0) { + clcf->disable_symlinks = NGX_DISABLE_SYMLINKS_ON; + continue; + } + + if (ngx_strncmp(value[i].data, "from=", 5) == 0) { + value[i].len -= 5; + value[i].data += 5; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[i]; + ccv.complex_value = ngx_palloc(cf->pool, + sizeof(ngx_http_complex_value_t)); + if (ccv.complex_value == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + clcf->disable_symlinks_from = ccv.complex_value; + + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (clcf->disable_symlinks == NGX_CONF_UNSET_UINT) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" must have \"off\", \"on\" " + "or \"if_not_owner\" parameter", + &cmd->name); + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 2) { + clcf->disable_symlinks_from = NULL; + return NGX_CONF_OK; + } + + if (clcf->disable_symlinks_from == NGX_CONF_UNSET_PTR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate parameters \"%V %V\"", + &value[1], &value[2]); + return NGX_CONF_ERROR; + } + + if (clcf->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"from=\" cannot be used with \"off\" parameter"); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +#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 @@ -406,6 +406,7 @@ struct ngx_http_core_loc_conf_s { #if (NGX_HAVE_OPENAT) ngx_uint_t disable_symlinks; /* disable_symlinks */ + ngx_http_complex_value_t *disable_symlinks_from; #endif ngx_array_t *error_pages; /* error_page */ @@ -509,6 +510,10 @@ ngx_int_t ngx_http_output_filter(ngx_htt ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *chain); +ngx_int_t ngx_http_set_disable_symlinks(ngx_http_request_t *r, + ngx_http_core_loc_conf_t *clcf, ngx_str_t *path, ngx_open_file_info_t *of); + + extern ngx_module_t ngx_http_core_module; extern ngx_uint_t ngx_http_max_module; diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -799,21 +799,16 @@ ngx_http_file_cache_lookup(ngx_http_file /* node_key == node->key */ - do { - fcn = (ngx_http_file_cache_node_t *) node; + fcn = (ngx_http_file_cache_node_t *) node; - rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key, - NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); + rc = ngx_memcmp(&key[sizeof(ngx_rbtree_key_t)], fcn->key, + NGX_HTTP_CACHE_KEY_LEN - sizeof(ngx_rbtree_key_t)); - if (rc == 0) { - return fcn; - } + if (rc == 0) { + return fcn; + } - node = (rc < 0) ? node->left : node->right; - - } while (node != sentinel && node_key == node->key); - - break; + node = (rc < 0) ? node->left : node->right; } /* not found */ 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 @@ -71,12 +71,11 @@ static ngx_str_t ngx_http_status_lines[] ngx_string("302 Moved Temporarily"), ngx_string("303 See Other"), ngx_string("304 Not Modified"), + ngx_null_string, /* "305 Use Proxy" */ + ngx_null_string, /* "306 unused" */ + ngx_string("307 Temporary Redirect"), - /* ngx_null_string, */ /* "305 Use Proxy" */ - /* ngx_null_string, */ /* "306 unused" */ - /* ngx_null_string, */ /* "307 Temporary Redirect" */ - -#define NGX_HTTP_LAST_3XX 305 +#define NGX_HTTP_LAST_3XX 308 #define NGX_HTTP_OFF_4XX (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX) ngx_string("400 Bad Request"), diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -242,7 +242,7 @@ ngx_http_parse_time(u_char *value, size_ year -= 1; } - /* Gauss' formula for Grigorian days since March 1, 1 BC */ + /* Gauss' formula for Gregorian days since March 1, 1 BC */ time = (uint64_t) ( /* days in years including leap years since March 1, 1 BC */ 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 @@ -10,7 +10,7 @@ #define NGX_HTTP_MAX_URI_CHANGES 10 -#define NGX_HTTP_MAX_SUBREQUESTS 50 +#define NGX_HTTP_MAX_SUBREQUESTS 200 /* must be 2^n */ #define NGX_HTTP_LC_HEADER_LEN 32 @@ -75,6 +75,7 @@ #define NGX_HTTP_MOVED_TEMPORARILY 302 #define NGX_HTTP_SEE_OTHER 303 #define NGX_HTTP_NOT_MODIFIED 304 +#define NGX_HTTP_TEMPORARY_REDIRECT 307 #define NGX_HTTP_BAD_REQUEST 400 #define NGX_HTTP_UNAUTHORIZED 401 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 @@ -1505,9 +1505,12 @@ ngx_http_script_file_code(ngx_http_scrip of.test_only = 1; of.errors = clcf->open_file_cache_errors; of.events = clcf->open_file_cache_events; -#if (NGX_HAVE_OPENAT) - of.disable_symlinks = clcf->disable_symlinks; -#endif + + if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) { + e->ip = ngx_http_script_exit; + e->status = NGX_HTTP_INTERNAL_SERVER_ERROR; + return; + } if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -74,6 +74,14 @@ static char ngx_http_error_303_page[] = ; +static char ngx_http_error_307_page[] = +"" CRLF +"307 Temporary Redirect" CRLF +"" CRLF +"

307 Temporary Redirect

" CRLF +; + + static char ngx_http_error_400_page[] = "" CRLF "400 Bad Request" CRLF @@ -294,16 +302,20 @@ static ngx_str_t ngx_http_error_pages[] ngx_null_string, /* 201, 204 */ -#define NGX_HTTP_LAST_LEVEL_200 202 -#define NGX_HTTP_LEVEL_200 (NGX_HTTP_LAST_LEVEL_200 - 201) +#define NGX_HTTP_LAST_2XX 202 +#define NGX_HTTP_OFF_3XX (NGX_HTTP_LAST_2XX - 201) /* ngx_null_string, */ /* 300 */ ngx_string(ngx_http_error_301_page), ngx_string(ngx_http_error_302_page), ngx_string(ngx_http_error_303_page), + ngx_null_string, /* 304 */ + ngx_null_string, /* 305 */ + ngx_null_string, /* 306 */ + ngx_string(ngx_http_error_307_page), -#define NGX_HTTP_LAST_LEVEL_300 304 -#define NGX_HTTP_LEVEL_300 (NGX_HTTP_LAST_LEVEL_300 - 301) +#define NGX_HTTP_LAST_3XX 308 +#define NGX_HTTP_OFF_4XX (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX) ngx_string(ngx_http_error_400_page), ngx_string(ngx_http_error_401_page), @@ -323,8 +335,8 @@ static ngx_str_t ngx_http_error_pages[] ngx_string(ngx_http_error_415_page), ngx_string(ngx_http_error_416_page), -#define NGX_HTTP_LAST_LEVEL_400 417 -#define NGX_HTTP_LEVEL_400 (NGX_HTTP_LAST_LEVEL_400 - 400) +#define NGX_HTTP_LAST_4XX 417 +#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX) ngx_string(ngx_http_error_494_page), /* 494, request header too large */ ngx_string(ngx_http_error_495_page), /* 495, https certificate error */ @@ -342,7 +354,7 @@ static ngx_str_t ngx_http_error_pages[] ngx_null_string, /* 506 */ ngx_string(ngx_http_error_507_page) -#define NGX_HTTP_LAST_LEVEL_500 508 +#define NGX_HTTP_LAST_5XX 508 }; @@ -428,25 +440,22 @@ ngx_http_special_response_handler(ngx_ht err = 0; } else if (error >= NGX_HTTP_MOVED_PERMANENTLY - && error < NGX_HTTP_LAST_LEVEL_300) + && error < NGX_HTTP_LAST_3XX) { /* 3XX */ - err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_LEVEL_200; + err = error - NGX_HTTP_MOVED_PERMANENTLY + NGX_HTTP_OFF_3XX; } else if (error >= NGX_HTTP_BAD_REQUEST - && error < NGX_HTTP_LAST_LEVEL_400) + && error < NGX_HTTP_LAST_4XX) { /* 4XX */ - err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300; + err = error - NGX_HTTP_BAD_REQUEST + NGX_HTTP_OFF_4XX; } else if (error >= NGX_HTTP_NGINX_CODES - && error < NGX_HTTP_LAST_LEVEL_500) + && error < NGX_HTTP_LAST_5XX) { /* 49X, 5XX */ - err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_LEVEL_200 - + NGX_HTTP_LEVEL_300 - + NGX_HTTP_LEVEL_400; + err = error - NGX_HTTP_NGINX_CODES + NGX_HTTP_OFF_5XX; switch (error) { case NGX_HTTP_TO_HTTPS: case NGX_HTTPS_CERT_ERROR: @@ -570,12 +579,11 @@ ngx_http_send_error_page(ngx_http_reques return NGX_ERROR; } - if (overwrite >= NGX_HTTP_MOVED_PERMANENTLY - && overwrite <= NGX_HTTP_SEE_OTHER) + if (overwrite != NGX_HTTP_MOVED_PERMANENTLY + && overwrite != NGX_HTTP_MOVED_TEMPORARILY + && overwrite != NGX_HTTP_SEE_OTHER + && overwrite != NGX_HTTP_TEMPORARY_REDIRECT) { - r->err_status = overwrite; - - } else { r->err_status = NGX_HTTP_MOVED_TEMPORARILY; } @@ -595,7 +603,7 @@ ngx_http_send_error_page(ngx_http_reques return ngx_http_send_special_response(r, clcf, r->err_status - NGX_HTTP_MOVED_PERMANENTLY - + NGX_HTTP_LEVEL_200); + + NGX_HTTP_OFF_3XX); } @@ -626,7 +634,7 @@ ngx_http_send_special_response(ngx_http_ if (clcf->msie_padding && (r->headers_in.msie || r->headers_in.chrome) && r->http_version >= NGX_HTTP_VERSION_10 - && err >= NGX_HTTP_LEVEL_300) + && err >= NGX_HTTP_OFF_4XX) { r->headers_out.content_length_n += sizeof(ngx_http_msie_padding) - 1; 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 @@ -2293,7 +2293,7 @@ ngx_http_upstream_send_response(ngx_http } if (ngx_event_flags & NGX_USE_AIO_EVENT) { - /* the posted aio operation may currupt a shadow buffer */ + /* the posted aio operation may corrupt a shadow buffer */ p->single_buf = 1; } diff --git a/src/mail/ngx_mail_pop3_handler.c b/src/mail/ngx_mail_pop3_handler.c --- a/src/mail/ngx_mail_pop3_handler.c +++ b/src/mail/ngx_mail_pop3_handler.c @@ -218,7 +218,7 @@ ngx_mail_pop3_auth_state(ngx_event_t *re break; - /* suppress warinings */ + /* suppress warnings */ case ngx_pop3_passwd: break; diff --git a/src/os/unix/ngx_darwin_sendfile_chain.c b/src/os/unix/ngx_darwin_sendfile_chain.c --- a/src/os/unix/ngx_darwin_sendfile_chain.c +++ b/src/os/unix/ngx_darwin_sendfile_chain.c @@ -173,7 +173,7 @@ ngx_darwin_sendfile_chain(ngx_connection if (file && header.nelts == 0) { - /* create the tailer iovec and coalesce the neighbouring bufs */ + /* create the trailer iovec and coalesce the neighbouring bufs */ prev = NULL; iov = NULL; diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -78,8 +78,25 @@ typedef struct { #if (NGX_HAVE_OPENAT) #define NGX_FILE_NOFOLLOW O_NOFOLLOW + +#if defined(O_DIRECTORY) +#define NGX_FILE_DIRECTORY O_DIRECTORY +#else +#define NGX_FILE_DIRECTORY 0 #endif +#if defined(O_SEARCH) +#define NGX_FILE_SEARCH O_SEARCH|NGX_FILE_DIRECTORY + +#elif defined(O_EXEC) +#define NGX_FILE_SEARCH O_EXEC|NGX_FILE_DIRECTORY + +#else +#define NGX_FILE_SEARCH O_RDONLY|NGX_FILE_DIRECTORY +#endif + +#endif /* NGX_HAVE_OPENAT */ + #define NGX_FILE_DEFAULT_ACCESS 0644 #define NGX_FILE_OWNER_ACCESS 0600 @@ -163,7 +180,7 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_size(sb) (sb)->st_size -#define ngx_file_fs_size(sb) ((sb)->st_blocks * 512) +#define ngx_file_fs_size(sb) ngx_max((sb)->st_size, (sb)->st_blocks * 512) #define ngx_file_mtime(sb) (sb)->st_mtime #define ngx_file_uniq(sb) (sb)->st_ino @@ -259,7 +276,8 @@ ngx_de_info(u_char *name, ngx_dir_t *dir #define ngx_de_access(dir) (((dir)->info.st_mode) & 0777) #define ngx_de_size(dir) (dir)->info.st_size -#define ngx_de_fs_size(dir) ((dir)->info.st_blocks * 512) +#define ngx_de_fs_size(dir) \ + ngx_max((dir)->info.st_size, (dir)->info.st_blocks * 512) #define ngx_de_mtime(dir) (dir)->info.st_mtime @@ -340,6 +358,8 @@ size_t ngx_fs_bsize(u_char *name); #define ngx_file_at_info_n "fstatat()" +#define NGX_AT_FDCWD (ngx_fd_t) AT_FDCWD + #endif diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -178,7 +178,7 @@ ngx_freebsd_sendfile_chain(ngx_connectio if (file) { - /* create the tailer iovec and coalesce the neighbouring bufs */ + /* create the trailer iovec and coalesce the neighbouring bufs */ prev = NULL; iov = NULL; diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -250,6 +250,10 @@ ngx_master_process_cycle(ngx_cycle_t *cy ngx_start_worker_processes(cycle, ccf->worker_processes, NGX_PROCESS_JUST_RESPAWN); ngx_start_cache_manager_processes(cycle, 1); + + /* allow new processes to start */ + ngx_msleep(100); + live = 1; ngx_signal_worker_processes(cycle, ngx_signal_value(NGX_SHUTDOWN_SIGNAL)); diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -67,7 +67,7 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) - /* crypt() is a time consuming funtion, so we only try to lock */ + /* crypt() is a time consuming function, so we only try to lock */ if (ngx_mutex_trylock(ngx_crypt_mutex) != NGX_OK) { return NGX_AGAIN;