# HG changeset patch # User Igor Sysoev # Date 1329249600 -14400 # Node ID e5fa0a4a7d272db8961f3e096eedec05501a5d1c # Parent b49c1751031c0afa887ddc09de5e9da8313240a7 nginx 1.1.15 *) Feature: the "disable_symlinks" directive. *) Feature: the "proxy_cookie_domain" and "proxy_cookie_path" directives. *) Bugfix: nginx might log incorrect error "upstream prematurely closed connection" instead of correct "upstream sent too big header" one. Thanks to Feibo Li. *) Bugfix: nginx could not be built with the ngx_http_perl_module if the --with-openssl option was used. *) Bugfix: internal redirects to named locations were not limited. *) Bugfix: calling $r->flush() multiple times might cause errors in the ngx_http_gzip_filter_module. *) Bugfix: temporary files might be not removed if the "proxy_store" directive were used with SSI includes. *) Bugfix: in some cases non-cacheable variables (such as the $args variable) returned old empty cached value. *) Bugfix: a segmentation fault might occur in a worker process if too many SSI subrequests were issued simultaneously; the bug had appeared in 0.7.25. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,34 @@ +Changes with nginx 1.1.15 15 Feb 2012 + + *) Feature: the "disable_symlinks" directive. + + *) Feature: the "proxy_cookie_domain" and "proxy_cookie_path" + directives. + + *) Bugfix: nginx might log incorrect error "upstream prematurely closed + connection" instead of correct "upstream sent too big header" one. + Thanks to Feibo Li. + + *) Bugfix: nginx could not be built with the ngx_http_perl_module if the + --with-openssl option was used. + + *) Bugfix: internal redirects to named locations were not limited. + + *) Bugfix: calling $r->flush() multiple times might cause errors in the + ngx_http_gzip_filter_module. + + *) Bugfix: temporary files might be not removed if the "proxy_store" + directive were used with SSI includes. + + *) Bugfix: in some cases non-cacheable variables (such as the $args + variable) returned old empty cached value. + + *) Bugfix: a segmentation fault might occur in a worker process if too + many SSI subrequests were issued simultaneously; the bug had appeared + in 0.7.25. + + Changes with nginx 1.1.14 30 Jan 2012 *) Feature: multiple "limit_req" limits may be used simultaneously. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,34 @@ +Изменения в nginx 1.1.15 15.02.2012 + + *) Добавление: директива disable_symlinks. + + *) Добавление: директивы proxy_cookie_domain и proxy_cookie_path. + + *) Исправление: nginx мог некорректно сообщать об ошибке "upstream + prematurely closed connection" вместо "upstream sent too big header". + Спасибо Feibo Li. + + *) Исправление: nginx не собирался с модулем ngx_http_perl_module, если + использовался параметр --with-openssl. + + *) Исправление: количество внутренних перенаправлений в именованные + location'ы не ограничивалось. + + *) Исправление: вызов $r->flush() несколько раз подряд мог приводить к + ошибкам в модуле ngx_http_gzip_filter_module. + + *) Исправление: при использовании директивы proxy_store с + SSI-подзапросами временные файлы могли не удаляться. + + *) Исправление: в некоторых случаях некэшируемые переменные (такие, как + $args) возвращали старое пустое закэшированное значение. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если одновременно создавалось слишком много SSI-подзапросов; ошибка + появилась в 0.7.25. + + Изменения в nginx 1.1.14 30.01.2012 *) Добавление: теперь можно указать несколько ограничений limit_req diff --git a/auto/lib/perl/make b/auto/lib/perl/make --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -28,6 +28,7 @@ cat << END && NGX_PM_CFLAGS="\$(NGX_PM_CFLAGS) -g $NGX_CC_OPT" \ NGX_PCRE=$PCRE \ NGX_OBJS=$NGX_OBJS \ + NGX_OPENSSL=$OPENSSL \ $NGX_PERL Makefile.PL \ LIB=$NGX_PERL_MODULES \ INSTALLSITEMAN3DIR=$NGX_PERL_MODULES_MAN diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -721,3 +721,27 @@ ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct dirent dir; dir.d_type = DT_REG" . auto/feature + + +ngx_feature="sysconf(_SC_NPROCESSORS_ONLN)" +ngx_feature_name="NGX_HAVE_SC_NPROCESSORS_ONLN" +ngx_feature_run=no +ngx_feature_incs= +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="sysconf(_SC_NPROCESSORS_ONLN)" +. auto/feature + + +ngx_feature="openat(), fstatat()" +ngx_feature_name="NGX_HAVE_OPENAT" +ngx_feature_run=no +ngx_feature_incs="#include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct stat sb; + openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW); + fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);" +. auto/feature 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 1001014 -#define NGINX_VERSION "1.1.14" +#define nginx_version 1001015 +#define NGINX_VERSION "1.1.15" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -1295,10 +1295,6 @@ ngx_conf_set_msec_slot(ngx_conf_t *cf, n return "invalid value"; } - if (*msp == (ngx_msec_t) NGX_PARSE_LARGE_TIME) { - return "value must be less than 597 hours"; - } - if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, msp); @@ -1326,14 +1322,10 @@ ngx_conf_set_sec_slot(ngx_conf_t *cf, ng value = cf->args->elts; *sp = ngx_parse_time(&value[1], 1); - if (*sp == NGX_ERROR) { + if (*sp == (time_t) NGX_ERROR) { return "invalid value"; } - if (*sp == NGX_PARSE_LARGE_TIME) { - return "value must be less than 68 years"; - } - if (cmd->post) { post = cmd->post; return post->post_handler(cf, post, sp); diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -91,5 +91,10 @@ typedef void (*ngx_connection_handler_pt void ngx_cpuinfo(void); +#if (NGX_HAVE_OPENAT) +#define NGX_DISABLE_SYMLINKS_OFF 0 +#define NGX_DISABLE_SYMLINKS_ON 1 +#define NGX_DISABLE_SYMLINKS_NOTOWNER 2 +#endif #endif /* _NGX_CORE_H_INCLUDED_ */ 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 @@ -22,8 +22,17 @@ 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); +#if (NGX_HAVE_OPENAT) +static ngx_fd_t ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log); +#endif +static ngx_fd_t ngx_open_file_wrapper(ngx_str_t *name, + ngx_open_file_info_t *of, ngx_int_t mode, ngx_int_t create, + ngx_int_t access, ngx_log_t *log); +static ngx_int_t ngx_file_info_wrapper(ngx_str_t *name, + ngx_open_file_info_t *of, ngx_file_info_t *fi, ngx_log_t *log); +static ngx_int_t ngx_open_and_stat_file(ngx_str_t *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); @@ -147,9 +156,9 @@ ngx_open_cached_file(ngx_open_file_cache if (of->test_only) { - if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { - of->err = ngx_errno; - of->failed = ngx_file_info_n; + if (ngx_file_info_wrapper(name, of, &fi, pool->log) + == NGX_FILE_ERROR) + { return NGX_ERROR; } @@ -170,7 +179,7 @@ ngx_open_cached_file(ngx_open_file_cache return NGX_ERROR; } - rc = ngx_open_and_stat_file(name->data, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool->log); if (rc == NGX_OK && !of->is_dir) { cln->handler = ngx_pool_cleanup_file; @@ -205,7 +214,7 @@ ngx_open_cached_file(ngx_open_file_cache /* file was not used often enough to keep open */ - rc = ngx_open_and_stat_file(name->data, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -217,7 +226,11 @@ ngx_open_cached_file(ngx_open_file_cache if (file->use_event || (file->event == NULL && (of->uniq == 0 || of->uniq == file->uniq) - && now - file->created < of->valid)) + && now - file->created < of->valid +#if (NGX_HAVE_OPENAT) + && of->disable_symlinks == file->disable_symlinks +#endif + )) { if (file->err == 0) { @@ -239,7 +252,12 @@ ngx_open_cached_file(ngx_open_file_cache } else { of->err = file->err; +#if (NGX_HAVE_OPENAT) + of->failed = file->disable_symlinks ? ngx_openat_file_n + : ngx_open_file_n; +#else of->failed = ngx_open_file_n; +#endif } goto found; @@ -263,7 +281,7 @@ ngx_open_cached_file(ngx_open_file_cache of->fd = file->fd; of->uniq = file->uniq; - rc = ngx_open_and_stat_file(name->data, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -311,8 +329,7 @@ ngx_open_cached_file(ngx_open_file_cache 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_close_file_n " \"%V\" failed", name); } goto add_event; @@ -329,7 +346,7 @@ ngx_open_cached_file(ngx_open_file_cache /* not found */ - rc = ngx_open_and_stat_file(name->data, of, pool->log); + rc = ngx_open_and_stat_file(name, of, pool->log); if (rc != NGX_OK && (of->err == 0 || !of->errors)) { goto failed; @@ -376,6 +393,9 @@ update: file->fd = of->fd; file->err = of->err; +#if (NGX_HAVE_OPENAT) + file->disable_symlinks = of->disable_symlinks; +#endif if (of->err == 0) { file->uniq = of->uniq; @@ -452,7 +472,7 @@ failed: if (of->fd != NGX_INVALID_FILE) { 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); + ngx_close_file_n " \"%V\" failed", name); } } @@ -460,17 +480,297 @@ failed: } +#if (NGX_HAVE_OPENAT) + +static ngx_fd_t +ngx_openat_file_owner(ngx_fd_t at_fd, const u_char *name, + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) +{ + ngx_fd_t fd; + ngx_err_t err; + ngx_file_info_t fi, atfi; + + /* + * To allow symlinks with the same owner, use openat() (followed + * by fstat()) and fstatat(AT_SYMLINK_NOFOLLOW), and then compare + * uids between fstat() and fstatat(). + * + * As there is a race between openat() and fstatat() we don't + * know if openat() in fact opened symlink or not. Therefore, + * we have to compare uids even if fstatat() reports the opened + * component isn't a symlink (as we don't know whether it was + * symlink during openat() or not). + */ + + fd = ngx_openat_file(at_fd, name, mode, create, access); + + if (fd == NGX_FILE_ERROR) { + return NGX_FILE_ERROR; + } + + if (ngx_file_at_info(at_fd, name, &atfi, AT_SYMLINK_NOFOLLOW) + == NGX_FILE_ERROR) + { + err = ngx_errno; + goto failed; + } + + if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { + err = ngx_errno; + goto failed; + } + + if (fi.st_uid != atfi.st_uid) { + err = NGX_ELOOP; + goto failed; + } + + return fd; + +failed: + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%V\" failed", name); + } + + ngx_set_errno(err); + + return NGX_INVALID_FILE; +} + +#endif + + +static ngx_fd_t +ngx_open_file_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, + ngx_int_t mode, ngx_int_t create, ngx_int_t access, ngx_log_t *log) +{ + ngx_fd_t fd; + +#if !(NGX_HAVE_OPENAT) + + fd = ngx_open_file(name->data, mode, create, access); + + if (fd == NGX_INVALID_FILE) { + of->err = ngx_errno; + of->failed = ngx_open_file_n; + return NGX_INVALID_FILE; + } + + return fd; + +#else + + 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); + + if (fd == NGX_INVALID_FILE) { + of->err = ngx_errno; + of->failed = ngx_open_file_n; + return NGX_INVALID_FILE; + } + + return fd; + } + + 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 (at_fd == NGX_FILE_ERROR) { + of->err = ngx_errno; + of->failed = ngx_openat_file_n; + return NGX_FILE_ERROR; + } + + at_name.len = 1; + p++; + } + + for ( ;; ) { + cp = ngx_strlchr(p, end, '/'); + if (cp == NULL) { + break; + } + + if (cp == p) { + p++; + continue; + } + + *cp = '\0'; + + if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { + fd = ngx_openat_file_owner(at_fd, p, + NGX_FILE_RDONLY|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_OPEN, 0); + } + + *cp = '/'; + + if (fd == NGX_INVALID_FILE) { + of->err = ngx_errno; + of->failed = ngx_openat_file_n; + goto failed; + } + + if (at_fd != 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); + } + + p = cp + 1; + at_fd = fd; + at_name.len = cp - at_name.data; + } + + if (p == end && at_fd != AT_FDCWD) { + + /* + * If pathname ends with a trailing slash, check if last path + * component is a directory; 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. + */ + + 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; + } + + if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_NOTOWNER) { + 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); + } + + if (fd == NGX_INVALID_FILE) { + of->err = ngx_errno; + of->failed = ngx_openat_file_n; + } + +failed: + + if (at_fd != 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); + } + + return fd; +#endif +} + + static ngx_int_t -ngx_open_and_stat_file(u_char *name, ngx_open_file_info_t *of, ngx_log_t *log) +ngx_file_info_wrapper(ngx_str_t *name, ngx_open_file_info_t *of, + ngx_file_info_t *fi, ngx_log_t *log) +{ + ngx_int_t rc; + +#if !(NGX_HAVE_OPENAT) + + rc = ngx_file_info(name->data, fi); + + if (rc == NGX_FILE_ERROR) { + of->err = ngx_errno; + of->failed = ngx_file_info_n; + return NGX_FILE_ERROR; + } + + return rc; + +#else + + ngx_fd_t fd; + + if (of->disable_symlinks == NGX_DISABLE_SYMLINKS_OFF) { + + rc = ngx_file_info(name->data, fi); + + if (rc == NGX_FILE_ERROR) { + of->err = ngx_errno; + of->failed = ngx_file_info_n; + return NGX_FILE_ERROR; + } + + return rc; + } + + fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0, log); + + if (fd == NGX_INVALID_FILE) { + return NGX_FILE_ERROR; + } + + rc = ngx_fd_info(fd, fi); + + if (rc == NGX_FILE_ERROR) { + of->err = ngx_errno; + of->failed = ngx_fd_info_n; + } + + if (ngx_close_file(fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_close_file_n " \"%V\" failed", name); + } + + return rc; +#endif +} + + +static ngx_int_t +ngx_open_and_stat_file(ngx_str_t *name, ngx_open_file_info_t *of, + ngx_log_t *log) { ngx_fd_t fd; ngx_file_info_t fi; if (of->fd != NGX_INVALID_FILE) { - if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { - of->failed = ngx_file_info_n; - goto failed; + if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { + of->fd = NGX_INVALID_FILE; + return NGX_ERROR; } if (of->uniq == ngx_file_uniq(&fi)) { @@ -479,9 +779,9 @@ ngx_open_and_stat_file(u_char *name, ngx } else if (of->test_dir) { - if (ngx_file_info(name, &fi) == NGX_FILE_ERROR) { - of->failed = ngx_file_info_n; - goto failed; + if (ngx_file_info_wrapper(name, of, &fi, log) == NGX_FILE_ERROR) { + of->fd = NGX_INVALID_FILE; + return NGX_ERROR; } if (ngx_is_dir(&fi)) { @@ -496,26 +796,27 @@ ngx_open_and_stat_file(u_char *name, ngx * This flag has no effect on a regular files. */ - fd = ngx_open_file(name, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, - NGX_FILE_OPEN, 0); + fd = ngx_open_file_wrapper(name, of, NGX_FILE_RDONLY|NGX_FILE_NONBLOCK, + NGX_FILE_OPEN, 0, log); } else { - fd = ngx_open_file(name, NGX_FILE_APPEND, NGX_FILE_CREATE_OR_OPEN, - NGX_FILE_DEFAULT_ACCESS); + fd = ngx_open_file_wrapper(name, of, NGX_FILE_APPEND, + NGX_FILE_CREATE_OR_OPEN, + NGX_FILE_DEFAULT_ACCESS, log); } if (fd == NGX_INVALID_FILE) { - of->failed = ngx_open_file_n; - goto failed; + of->fd = NGX_INVALID_FILE; + return NGX_ERROR; } if (ngx_fd_info(fd, &fi) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_CRIT, log, ngx_errno, - ngx_fd_info_n " \"%s\" failed", name); + ngx_fd_info_n " \"%V\" failed", name); if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name); + ngx_close_file_n " \"%V\" failed", name); } of->fd = NGX_INVALID_FILE; @@ -526,7 +827,7 @@ ngx_open_and_stat_file(u_char *name, ngx if (ngx_is_dir(&fi)) { if (ngx_close_file(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_close_file_n " \"%s\" failed", name); + ngx_close_file_n " \"%V\" failed", name); } of->fd = NGX_INVALID_FILE; @@ -537,14 +838,14 @@ ngx_open_and_stat_file(u_char *name, ngx if (of->read_ahead && ngx_file_size(&fi) > NGX_MIN_READ_AHEAD) { if (ngx_read_ahead(fd, of->read_ahead) == NGX_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_read_ahead_n " \"%s\" failed", name); + ngx_read_ahead_n " \"%V\" failed", name); } } if (of->directio <= ngx_file_size(&fi)) { if (ngx_directio_on(fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_directio_on_n " \"%s\" failed", name); + ngx_directio_on_n " \"%V\" failed", name); } else { of->is_directio = 1; @@ -564,13 +865,6 @@ done: of->is_exec = ngx_is_exec(&fi); return NGX_OK; - -failed: - - of->fd = NGX_INVALID_FILE; - of->err = ngx_errno; - - return NGX_ERROR; } 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 @@ -32,6 +32,10 @@ typedef struct { ngx_uint_t min_uses; +#if (NGX_HAVE_OPENAT) + unsigned disable_symlinks:2; +#endif + unsigned test_dir:1; unsigned test_only:1; unsigned log:1; @@ -64,6 +68,10 @@ struct ngx_cached_open_file_s { uint32_t uses; +#if (NGX_HAVE_OPENAT) + unsigned disable_symlinks:2; +#endif + unsigned count:24; unsigned close:1; unsigned use_event:1; diff --git a/src/core/ngx_parse.h b/src/core/ngx_parse.h --- a/src/core/ngx_parse.h +++ b/src/core/ngx_parse.h @@ -13,9 +13,6 @@ #include -#define NGX_PARSE_LARGE_TIME -2 - - ssize_t ngx_parse_size(ngx_str_t *line); off_t ngx_parse_offset(ngx_str_t *line); ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t is_sec); 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 @@ -160,7 +160,7 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_ r->valid = ngx_parse_time(&s, 1); - if (r->valid == NGX_ERROR) { + if (r->valid == (time_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter: %V", &names[i]); return NULL; 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,6 +109,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -127,6 +130,10 @@ ngx_http_flv_handler(ngx_http_request_t break; case NGX_EACCES: +#if (NGX_HAVE_OPENAT) + case NGX_EMLINK: + case NGX_ELOOP: +#endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; 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 @@ -759,6 +759,7 @@ static ngx_int_t ngx_http_gzip_filter_deflate(ngx_http_request_t *r, ngx_http_gzip_ctx_t *ctx) { int rc; + ngx_buf_t *b; ngx_chain_t *cl; ngx_http_gzip_conf_t *conf; @@ -770,7 +771,7 @@ ngx_http_gzip_filter_deflate(ngx_http_re rc = deflate(&ctx->zstream, ctx->flush); - if (rc != Z_OK && rc != Z_STREAM_END) { + if (rc != Z_OK && rc != Z_STREAM_END && rc != Z_BUF_ERROR) { ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, "deflate() failed: %d, %d", ctx->flush, rc); return NGX_ERROR; @@ -819,8 +820,6 @@ ngx_http_gzip_filter_deflate(ngx_http_re if (ctx->flush == Z_SYNC_FLUSH) { - ctx->zstream.avail_out = 0; - ctx->out_buf->flush = 1; ctx->flush = Z_NO_FLUSH; cl = ngx_alloc_chain_link(r->pool); @@ -828,7 +827,22 @@ ngx_http_gzip_filter_deflate(ngx_http_re return NGX_ERROR; } - cl->buf = ctx->out_buf; + b = ctx->out_buf; + + if (ngx_buf_size(b) == 0) { + + b = ngx_calloc_buf(ctx->request->pool); + if (b == NULL) { + return NGX_ERROR; + } + + } else { + ctx->zstream.avail_out = 0; + } + + b->flush = 1; + + cl->buf = b; cl->next = NULL; *ctx->last_out = cl; ctx->last_out = &cl->next; 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,6 +129,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -145,6 +148,10 @@ ngx_http_gzip_static_handler(ngx_http_re return NGX_DECLINED; case NGX_EACCES: +#if (NGX_HAVE_OPENAT) + case NGX_EMLINK: + case NGX_ELOOP: +#endif level = NGX_LOG_ERR; break; 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 @@ -530,7 +530,7 @@ ngx_http_headers_expires(ngx_conf_t *cf, hcf->expires_time = ngx_parse_time(&value[n], 1); - if (hcf->expires_time == NGX_ERROR) { + if (hcf->expires_time == (time_t) NGX_ERROR) { return "invalid value"; } @@ -540,10 +540,6 @@ ngx_http_headers_expires(ngx_conf_t *cf, return "daily time value must be less than 24 hours"; } - if (hcf->expires_time == NGX_PARSE_LARGE_TIME) { - return "value must be less than 68 years"; - } - if (minus) { hcf->expires_time = - hcf->expires_time; } 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,6 +209,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -220,6 +223,14 @@ ngx_http_index_handler(ngx_http_request_ return NGX_HTTP_INTERNAL_SERVER_ERROR; } +#if (NGX_HAVE_OPENAT) + if (of.err == NGX_EMLINK + || of.err == NGX_ELOOP) + { + return NGX_HTTP_FORBIDDEN; + } +#endif + if (of.err == NGX_ENOTDIR || of.err == NGX_ENAMETOOLONG || of.err == NGX_EACCES) @@ -296,12 +307,23 @@ 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_open_cached_file(clcf->open_file_cache, &dir, &of, r->pool) != NGX_OK) { if (of.err) { +#if (NGX_HAVE_OPENAT) + if (of.err == NGX_EMLINK + || of.err == NGX_ELOOP) + { + return NGX_HTTP_FORBIDDEN; + } +#endif + if (of.err == NGX_ENOENT) { *last = c; return ngx_http_index_error(r, clcf, dir.data, NGX_ENOENT); 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 @@ -159,8 +159,6 @@ ngx_http_limit_conn_handler(ngx_http_req return NGX_DECLINED; } - r->main->limit_conn_set = 1; - lccf = ngx_http_get_module_loc_conf(r, ngx_http_limit_conn_module); limits = lccf->limits.elts; @@ -187,6 +185,8 @@ ngx_http_limit_conn_handler(ngx_http_req continue; } + r->main->limit_conn_set = 1; + hash = ngx_crc32_short(vv->data, len); shpool = (ngx_slab_pool_t *) limits[i].shm_zone->shm.addr; 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 @@ -373,6 +373,8 @@ ngx_http_log_script_write(ngx_http_reque ngx_http_log_loc_conf_t *llcf; ngx_http_core_loc_conf_t *clcf; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (!r->root_tested) { /* test root directory existance */ @@ -384,8 +386,6 @@ ngx_http_log_script_write(ngx_http_reque path.data[root] = '\0'; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ngx_memzero(&of, sizeof(ngx_open_file_info_t)); of.valid = clcf->open_file_cache_valid; @@ -394,6 +394,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -441,6 +444,9 @@ 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_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) @@ -1249,7 +1255,7 @@ ngx_http_log_open_file_cache(ngx_conf_t s.data = value[i].data + 9; inactive = ngx_parse_time(&s, 1); - if (inactive < 0) { + if (inactive == (time_t) NGX_ERROR) { goto failed; } @@ -1272,7 +1278,7 @@ ngx_http_log_open_file_cache(ngx_conf_t s.data = value[i].data + 6; valid = ngx_parse_time(&s, 1); - if (valid < 0) { + if (valid == (time_t) NGX_ERROR) { goto failed; } 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,6 +440,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -458,6 +461,10 @@ ngx_http_mp4_handler(ngx_http_request_t break; case NGX_EACCES: +#if (NGX_HAVE_OPENAT) + case NGX_EMLINK: + case NGX_ELOOP: +#endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; 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 @@ -10,20 +10,21 @@ #include -typedef struct ngx_http_proxy_redirect_s ngx_http_proxy_redirect_t; - -typedef ngx_int_t (*ngx_http_proxy_redirect_pt)(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); - -struct ngx_http_proxy_redirect_s { - ngx_http_proxy_redirect_pt handler; +typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t; + +typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, + ngx_http_proxy_rewrite_t *pr); + +struct ngx_http_proxy_rewrite_s { + ngx_http_proxy_rewrite_pt handler; union { ngx_http_complex_value_t complex; #if (NGX_PCRE) ngx_http_regex_t *regex; #endif - } redirect; + } pattern; ngx_http_complex_value_t replacement; }; @@ -54,6 +55,8 @@ typedef struct { ngx_array_t *proxy_values; ngx_array_t *redirects; + ngx_array_t *cookie_domains; + ngx_array_t *cookie_paths; ngx_str_t body_source; @@ -123,6 +126,12 @@ static ngx_int_t ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); +static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, + ngx_table_elt_t *h); +static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, + ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites); +static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement); static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); static void *ngx_http_proxy_create_loc_conf(ngx_conf_t *cf); @@ -135,6 +144,10 @@ static char *ngx_http_proxy_pass(ngx_con void *conf); static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); #if (NGX_HTTP_CACHE) @@ -146,6 +159,9 @@ static char *ngx_http_proxy_cache_key(ng static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); +static ngx_int_t ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, + ngx_http_proxy_rewrite_t *pr, ngx_str_t *regex, ngx_uint_t caseless); + #if (NGX_HTTP_SSL) static ngx_int_t ngx_http_proxy_set_ssl(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *plcf); @@ -198,6 +214,20 @@ static ngx_command_t ngx_http_proxy_com 0, NULL }, + { ngx_string("proxy_cookie_domain"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_proxy_cookie_domain, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_cookie_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_proxy_cookie_path, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + { ngx_string("proxy_store"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_http_proxy_store, @@ -649,6 +679,10 @@ ngx_http_proxy_handler(ngx_http_request_ u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; } + if (plcf->cookie_domains || plcf->cookie_paths) { + u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; + } + u->buffering = plcf->upstream.buffering; u->pipe = ngx_pcalloc(r->pool, sizeof(ngx_event_pipe_t)); @@ -2272,10 +2306,11 @@ static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix) { + size_t len; ngx_int_t rc; ngx_uint_t i; + ngx_http_proxy_rewrite_t *pr; ngx_http_proxy_loc_conf_t *plcf; - ngx_http_proxy_redirect_t *pr; plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); @@ -2285,8 +2320,95 @@ ngx_http_proxy_rewrite_redirect(ngx_http return NGX_DECLINED; } + len = h->value.len - prefix; + for (i = 0; i < plcf->redirects->nelts; i++) { - rc = pr[i].handler(r, h, prefix, &pr[i]); + rc = pr[i].handler(r, h, prefix, len, &pr[i]); + + if (rc != NGX_DECLINED) { + return rc; + } + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) +{ + size_t prefix; + u_char *p; + ngx_int_t rc, rv; + ngx_http_proxy_loc_conf_t *plcf; + + p = (u_char *) ngx_strchr(h->value.data, ';'); + if (p == NULL) { + return NGX_DECLINED; + } + + prefix = p + 1 - h->value.data; + + rv = NGX_DECLINED; + + plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); + + if (plcf->cookie_domains) { + p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1); + + if (p) { + rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7, + plcf->cookie_domains); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_DECLINED) { + rv = rc; + } + } + } + + if (plcf->cookie_paths) { + p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1); + + if (p) { + rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5, + plcf->cookie_paths); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc != NGX_DECLINED) { + rv = rc; + } + } + } + + return rv; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h, + u_char *value, ngx_array_t *rewrites) +{ + size_t len, prefix; + u_char *p; + ngx_int_t rc; + ngx_uint_t i; + ngx_http_proxy_rewrite_t *pr; + + prefix = value - h->value.data; + + p = (u_char *) ngx_strchr(value, ';'); + + len = p ? (size_t) (p - value) : (h->value.len - prefix); + + pr = rewrites->elts; + + for (i = 0; i < rewrites->nelts; i++) { + rc = pr[i].handler(r, h, prefix, len, &pr[i]); if (rc != NGX_DECLINED) { return rc; @@ -2298,20 +2420,18 @@ ngx_http_proxy_rewrite_redirect(ngx_http static ngx_int_t -ngx_http_proxy_rewrite_redirect_complex(ngx_http_request_t *r, - ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr) +ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { - size_t len; - u_char *data, *p; - ngx_str_t redirect, replacement; - - if (ngx_http_complex_value(r, &pr->redirect.complex, &redirect) != NGX_OK) { + ngx_str_t pattern, replacement; + + if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { return NGX_ERROR; } - if (redirect.len > h->value.len - prefix - || ngx_rstrncmp(h->value.data + prefix, redirect.data, - redirect.len) != 0) + if (pattern.len > len + || ngx_rstrncmp(h->value.data + prefix, pattern.data, + pattern.len) != 0) { return NGX_DECLINED; } @@ -2320,43 +2440,22 @@ ngx_http_proxy_rewrite_redirect_complex( return NGX_ERROR; } - len = replacement.len + h->value.len - redirect.len; - - data = ngx_pnalloc(r->pool, len); - if (data == NULL) { - return NGX_ERROR; - } - - p = ngx_copy(data, h->value.data, prefix); - - if (replacement.len) { - p = ngx_copy(p, replacement.data, replacement.len); - } - - ngx_memcpy(p, h->value.data + prefix + redirect.len, - h->value.len - redirect.len - prefix); - - h->value.len = len; - h->value.data = data; - - return NGX_OK; + return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement); } #if (NGX_PCRE) static ngx_int_t -ngx_http_proxy_rewrite_redirect_regex(ngx_http_request_t *r, ngx_table_elt_t *h, - size_t prefix, ngx_http_proxy_redirect_t *pr) +ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h, + size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) { - size_t len; - u_char *data; - ngx_str_t redirect, replacement; - - redirect.len = h->value.len - prefix; - redirect.data = h->value.data + prefix; - - if (ngx_http_regex_exec(r, pr->redirect.regex, &redirect) != NGX_OK) { + ngx_str_t pattern, replacement; + + pattern.len = len; + pattern.data = h->value.data + prefix; + + if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) { return NGX_DECLINED; } @@ -2364,29 +2463,85 @@ ngx_http_proxy_rewrite_redirect_regex(ng return NGX_ERROR; } - if (!prefix) { + if (prefix == 0 && h->value.len == len) { h->value = replacement; return NGX_OK; } - len = prefix + replacement.len; - - data = ngx_pnalloc(r->pool, len); - if (data == NULL) { + return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); +} + +#endif + + +static ngx_int_t +ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, + ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr) +{ + u_char *p; + ngx_str_t pattern, replacement; + + if (ngx_http_complex_value(r, &pr->pattern.complex, &pattern) != NGX_OK) { + return NGX_ERROR; + } + + p = h->value.data + prefix; + + if (p[0] == '.') { + p++; + prefix++; + len--; + } + + if (pattern.len != len || ngx_rstrncasecmp(pattern.data, p, len) != 0) { + return NGX_DECLINED; + } + + if (ngx_http_complex_value(r, &pr->replacement, &replacement) != NGX_OK) { return NGX_ERROR; } - ngx_memcpy(data, h->value.data, prefix); - ngx_memcpy(data + prefix, replacement.data, replacement.len); - - h->value.len = len; - h->value.data = data; + return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement); +} + + +static ngx_int_t +ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix, + size_t len, ngx_str_t *replacement) +{ + u_char *p, *data; + size_t new_len; + + new_len = replacement->len + h->value.len - len; + + if (replacement->len > len) { + + data = ngx_pnalloc(r->pool, new_len); + if (data == NULL) { + return NGX_ERROR; + } + + p = ngx_copy(data, h->value.data, prefix); + p = ngx_copy(p, replacement->data, replacement->len); + + ngx_memcpy(p, h->value.data + prefix + len, + h->value.len - len - prefix); + + h->value.data = data; + + } else { + p = ngx_copy(h->value.data + prefix, replacement->data, + replacement->len); + + ngx_memmove(p, h->value.data + prefix + len, + h->value.len - len - prefix); + } + + h->value.len = new_len; return NGX_OK; } -#endif - static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf) @@ -2486,6 +2641,9 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->redirect = NGX_CONF_UNSET; conf->upstream.change_buffering = 1; + conf->cookie_domains = NGX_CONF_UNSET_PTR; + conf->cookie_paths = NGX_CONF_UNSET_PTR; + conf->http_version = NGX_CONF_UNSET_UINT; conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; @@ -2507,7 +2665,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t size_t size; ngx_hash_init_t hash; ngx_http_core_loc_conf_t *clcf; - ngx_http_proxy_redirect_t *pr; + ngx_http_proxy_rewrite_t *pr; ngx_http_script_compile_t sc; if (conf->upstream.store != 0) { @@ -2760,7 +2918,7 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t if (conf->redirects == NULL && conf->url.data) { conf->redirects = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_proxy_redirect_t)); + sizeof(ngx_http_proxy_rewrite_t)); if (conf->redirects == NULL) { return NGX_CONF_ERROR; } @@ -2770,27 +2928,27 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t return NGX_CONF_ERROR; } - ngx_memzero(&pr->redirect.complex, + ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t)); ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); - pr->handler = ngx_http_proxy_rewrite_redirect_complex; + pr->handler = ngx_http_proxy_rewrite_complex_handler; if (conf->vars.uri.len) { - pr->redirect.complex.value = conf->url; + pr->pattern.complex.value = conf->url; pr->replacement.value = conf->location; } else { - pr->redirect.complex.value.len = conf->url.len - + sizeof("/") - 1; - - p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); + pr->pattern.complex.value.len = conf->url.len + + sizeof("/") - 1; + + p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); if (p == NULL) { return NGX_CONF_ERROR; } - pr->redirect.complex.value.data = p; + pr->pattern.complex.value.data = p; p = ngx_cpymem(p, conf->url.data, conf->url.len); *p = '/'; @@ -2800,6 +2958,10 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t } } + ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL); + + ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); + #if (NGX_HTTP_SSL) if (conf->upstream.ssl == NULL) { conf->upstream.ssl = prev->upstream.ssl; @@ -3285,7 +3447,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, u_char *p; ngx_str_t *value; - ngx_http_proxy_redirect_t *pr; + ngx_http_proxy_rewrite_t *pr; ngx_http_compile_complex_value_t ccv; if (plcf->redirect == 0) { @@ -3320,7 +3482,7 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, if (plcf->redirects == NULL) { plcf->redirects = ngx_array_create(cf->pool, 1, - sizeof(ngx_http_proxy_redirect_t)); + sizeof(ngx_http_proxy_rewrite_t)); if (plcf->redirects == NULL) { return NGX_CONF_ERROR; } @@ -3346,25 +3508,25 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, return NGX_CONF_ERROR; } - pr->handler = ngx_http_proxy_rewrite_redirect_complex; - - ngx_memzero(&pr->redirect.complex, sizeof(ngx_http_complex_value_t)); + pr->handler = ngx_http_proxy_rewrite_complex_handler; + + ngx_memzero(&pr->pattern.complex, sizeof(ngx_http_complex_value_t)); ngx_memzero(&pr->replacement, sizeof(ngx_http_complex_value_t)); if (plcf->vars.uri.len) { - pr->redirect.complex.value = plcf->url; + pr->pattern.complex.value = plcf->url; pr->replacement.value = plcf->location; } else { - pr->redirect.complex.value.len = plcf->url.len + sizeof("/") - 1; - - p = ngx_pnalloc(cf->pool, pr->redirect.complex.value.len); + pr->pattern.complex.value.len = plcf->url.len + sizeof("/") - 1; + + p = ngx_pnalloc(cf->pool, pr->pattern.complex.value.len); if (p == NULL) { return NGX_CONF_ERROR; } - pr->redirect.complex.value.data = p; + pr->pattern.complex.value.data = p; p = ngx_cpymem(p, plcf->url.data, plcf->url.len); *p = '/'; @@ -3377,52 +3539,36 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, if (value[1].data[0] == '~') { -#if (NGX_PCRE) - u_char errstr[NGX_MAX_CONF_ERRSTR]; - ngx_regex_compile_t rc; - value[1].len--; value[1].data++; - ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); - if (value[1].data[0] == '*') { value[1].len--; value[1].data++; - rc.options = NGX_REGEX_CASELESS; - } - - rc.pattern = value[1]; - rc.err.len = NGX_MAX_CONF_ERRSTR; - rc.err.data = errstr; - - pr->redirect.regex = ngx_http_regex_compile(cf, &rc); - if (pr->redirect.regex == NULL) { - return NGX_CONF_ERROR; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } } - pr->handler = ngx_http_proxy_rewrite_redirect_regex; - -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "using regex \"%V\" requires PCRE library", - &value[1]); - - return NGX_CONF_ERROR; -#endif } else { ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); ccv.cf = cf; ccv.value = &value[1]; - ccv.complex_value = &pr->redirect.complex; + ccv.complex_value = &pr->pattern.complex; if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { return NGX_CONF_ERROR; } - pr->handler = ngx_http_proxy_rewrite_redirect_complex; + pr->handler = ngx_http_proxy_rewrite_complex_handler; } @@ -3441,6 +3587,217 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, static char * +ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_proxy_rewrite_t *pr; + ngx_http_compile_complex_value_t ccv; + + if (plcf->cookie_domains == NULL) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->cookie_domains = NULL; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (plcf->cookie_domains == NGX_CONF_UNSET_PTR) { + plcf->cookie_domains = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_rewrite_t)); + if (plcf->cookie_domains == NULL) { + return NGX_CONF_ERROR; + } + } + + pr = ngx_array_push(plcf->cookie_domains); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + if (value[1].data[0] == '~') { + value[1].len--; + value[1].data++; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + + if (value[1].data[0] == '.') { + value[1].len--; + value[1].data++; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pr->pattern.complex; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_domain_handler; + + if (value[2].data[0] == '.') { + value[2].len--; + value[2].data++; + } + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &pr->replacement; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_proxy_rewrite_t *pr; + ngx_http_compile_complex_value_t ccv; + + if (plcf->cookie_paths == NULL) { + return NGX_CONF_OK; + } + + value = cf->args->elts; + + if (cf->args->nelts == 2) { + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->cookie_paths = NULL; + return NGX_CONF_OK; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + if (plcf->cookie_paths == NGX_CONF_UNSET_PTR) { + plcf->cookie_paths = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_proxy_rewrite_t)); + if (plcf->cookie_paths == NULL) { + return NGX_CONF_ERROR; + } + } + + pr = ngx_array_push(plcf->cookie_paths); + if (pr == NULL) { + return NGX_CONF_ERROR; + } + + if (value[1].data[0] == '~') { + value[1].len--; + value[1].data++; + + if (value[1].data[0] == '*') { + value[1].len--; + value[1].data++; + + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + } else { + if (ngx_http_proxy_rewrite_regex(cf, pr, &value[1], 0) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + } else { + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &pr->pattern.complex; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_complex_handler; + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &pr->replacement; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, + ngx_str_t *regex, ngx_uint_t caseless) +{ +#if (NGX_PCRE) + u_char errstr[NGX_MAX_CONF_ERRSTR]; + ngx_regex_compile_t rc; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = *regex; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + if (caseless) { + rc.options = NGX_REGEX_CASELESS; + } + + pr->pattern.regex = ngx_http_regex_compile(cf, &rc); + if (pr->pattern.regex == NULL) { + return NGX_ERROR; + } + + pr->handler = ngx_http_proxy_rewrite_regex_handler; + + return NGX_OK; + +#else + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "using regex \"%V\" requires PCRE library", regex); + return NGX_ERROR; + +#endif +} + + +static char * ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_proxy_loc_conf_t *plcf = conf; diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c --- a/src/http/modules/ngx_http_range_filter_module.c +++ b/src/http/modules/ngx_http_range_filter_module.c @@ -595,15 +595,8 @@ ngx_http_range_test_overlapped(ngx_http_ buf = in->buf; if (!buf->last_buf) { - - if (buf->in_file) { - start = buf->file_pos + ctx->offset; - last = buf->file_last + ctx->offset; - - } else { - start = buf->pos - buf->start + ctx->offset; - last = buf->last - buf->start + ctx->offset; - } + start = ctx->offset; + last = ctx->offset + ngx_buf_size(buf); range = ctx->ranges.elts; for (i = 0; i < ctx->ranges.nelts; i++) { @@ -716,7 +709,6 @@ static ngx_int_t ngx_http_range_multipart_body(ngx_http_request_t *r, ngx_http_range_filter_ctx_t *ctx, ngx_chain_t *in) { - off_t body_start; ngx_buf_t *b, *buf; ngx_uint_t i; ngx_chain_t *out, *hcl, *rcl, *dcl, **ll; @@ -726,12 +718,6 @@ ngx_http_range_multipart_body(ngx_http_r buf = in->buf; range = ctx->ranges.elts; -#if (NGX_HTTP_CACHE) - body_start = r->cached ? r->cache->body_start : 0; -#else - body_start = 0; -#endif - for (i = 0; i < ctx->ranges.nelts; i++) { /* @@ -792,13 +778,13 @@ ngx_http_range_multipart_body(ngx_http_r b->file = buf->file; if (buf->in_file) { - b->file_pos = body_start + range[i].start; - b->file_last = body_start + range[i].end; + b->file_pos = buf->file_pos + range[i].start; + b->file_last = buf->file_pos + range[i].end; } if (ngx_buf_in_memory(buf)) { - b->pos = buf->start + (size_t) range[i].start; - b->last = buf->start + (size_t) range[i].end; + b->pos = buf->pos + (size_t) range[i].start; + b->last = buf->pos + (size_t) range[i].end; } dcl = ngx_alloc_chain_link(r->pool); 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,6 +94,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -112,6 +115,10 @@ ngx_http_static_handler(ngx_http_request break; case NGX_EACCES: +#if (NGX_HAVE_OPENAT) + case NGX_EMLINK: + case NGX_ELOOP: +#endif level = NGX_LOG_ERR; rc = NGX_HTTP_FORBIDDEN; 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 @@ -774,14 +774,10 @@ ngx_http_userid_expires(ngx_conf_t *cf, } ucf->expires = ngx_parse_time(&value[1], 1); - if (ucf->expires == NGX_ERROR) { + if (ucf->expires == (time_t) NGX_ERROR) { return "invalid value"; } - if (ucf->expires == NGX_PARSE_LARGE_TIME) { - return "value must be less than 68 years"; - } - return NGX_CONF_OK; } diff --git a/src/http/modules/perl/Makefile.PL b/src/http/modules/perl/Makefile.PL --- a/src/http/modules/perl/Makefile.PL +++ b/src/http/modules/perl/Makefile.PL @@ -25,7 +25,11 @@ WriteMakefile( "-I ../../../../../$ENV{NGX_OBJS} " . ($ENV{NGX_PCRE} =~ /^(YES|NO)/ ? "" : ($ENV{NGX_PCRE} =~ m#^/# ? "-I $ENV{NGX_PCRE} " : - "-I ../../../../../$ENV{NGX_PCRE} ")), + "-I ../../../../../$ENV{NGX_PCRE} ")) . + ($ENV{NGX_OPENSSL} =~ /^(YES|NO)/ ? "" : + ($ENV{NGX_OPENSSL} =~ m#^/# ? + "-I $ENV{NGX_OPENSSL}/.openssl/include " : + "-I ../../../../../$ENV{NGX_OPENSSL}/.openssl/include ")), depend => { 'nginx.c' => 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 @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.1.14'; +our $VERSION = '1.1.15'; 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 @@ -662,6 +662,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) diff --git a/src/http/ngx_http_busy_lock.c b/src/http/ngx_http_busy_lock.c --- a/src/http/ngx_http_busy_lock.c +++ b/src/http/ngx_http_busy_lock.c @@ -274,7 +274,7 @@ char *ngx_http_set_busy_lock_slot(ngx_co line.data = value[i].data + 2; bl->timeout = ngx_parse_time(&line, 1); - if (bl->timeout == NGX_ERROR) { + if (bl->timeout == (time_t) NGX_ERROR) { invalid = 1; break; } 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 @@ -187,6 +187,18 @@ 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"), @@ -764,6 +776,17 @@ static ngx_command_t ngx_http_core_comm #endif +#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_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, disable_symlinks), + &ngx_http_core_disable_symlinks }, + +#endif + ngx_null_command }; @@ -1297,6 +1320,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) @@ -2453,7 +2479,6 @@ ngx_http_subrequest(ngx_http_request_t * sr->start_sec = tp->sec; sr->start_msec = tp->msec; - r->main->subrequests++; r->main->count++; *psr = sr; @@ -2525,6 +2550,16 @@ ngx_http_named_location(ngx_http_request ngx_http_core_main_conf_t *cmcf; r->main->count++; + r->uri_changes--; + + if (r->uri_changes == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "rewrite or internal redirection cycle " + "while redirect to named location \"%V\"", name); + + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return NGX_DONE; + } cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -3335,6 +3370,10 @@ ngx_http_core_create_loc_conf(ngx_conf_t #endif #endif +#if (NGX_HAVE_OPENAT) + clcf->disable_symlinks = NGX_CONF_UNSET_UINT; +#endif + return clcf; } @@ -3614,6 +3653,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t #endif #endif +#if (NGX_HAVE_OPENAT) + ngx_conf_merge_uint_value(conf->disable_symlinks, prev->disable_symlinks, + NGX_DISABLE_SYMLINKS_OFF); +#endif + return NGX_CONF_OK; } @@ -3844,7 +3888,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx s.len = p - s.data; lsopt.tcp_keepidle = ngx_parse_time(&s, 1); - if (lsopt.tcp_keepidle == NGX_ERROR) { + if (lsopt.tcp_keepidle == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } @@ -3860,7 +3904,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx s.len = p - s.data; lsopt.tcp_keepintvl = ngx_parse_time(&s, 1); - if (lsopt.tcp_keepintvl == NGX_ERROR) { + if (lsopt.tcp_keepintvl == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } @@ -4507,7 +4551,7 @@ ngx_http_core_open_file_cache(ngx_conf_t s.data = value[i].data + 9; inactive = ngx_parse_time(&s, 1); - if (inactive < 0) { + if (inactive == (time_t) NGX_ERROR) { goto failed; } @@ -4594,24 +4638,16 @@ ngx_http_core_keepalive(ngx_conf_t *cf, return "invalid value"; } - if (clcf->keepalive_timeout == (ngx_msec_t) NGX_PARSE_LARGE_TIME) { - return "value must be less than 597 hours"; - } - if (cf->args->nelts == 2) { return NGX_CONF_OK; } clcf->keepalive_header = ngx_parse_time(&value[2], 1); - if (clcf->keepalive_header == NGX_ERROR) { + if (clcf->keepalive_header == (time_t) NGX_ERROR) { return "invalid value"; } - if (clcf->keepalive_header == NGX_PARSE_LARGE_TIME) { - return "value must be less than 68 years"; - } - return NGX_CONF_OK; } 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 @@ -404,6 +404,10 @@ struct ngx_http_core_loc_conf_s { #endif #endif +#if (NGX_HAVE_OPENAT) + ngx_uint_t disable_symlinks; /* disable_symlinks */ +#endif + ngx_array_t *error_pages; /* error_page */ ngx_http_try_file_t *try_files; /* try_files */ 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 @@ -1597,7 +1597,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t time_t inactive; ssize_t size; ngx_str_t s, name, *value; - ngx_int_t loader_files, loader_sleep, loader_threshold; + ngx_int_t loader_files; + ngx_msec_t loader_sleep, loader_threshold; ngx_uint_t i, n; ngx_http_file_cache_t *cache; @@ -1704,7 +1705,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t s.data = value[i].data + 9; inactive = ngx_parse_time(&s, 1); - if (inactive < 0) { + if (inactive == (time_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid inactive value \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -1746,7 +1747,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t s.data = value[i].data + 13; loader_sleep = ngx_parse_time(&s, 0); - if (loader_sleep < 0) { + if (loader_sleep == (ngx_msec_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid loader_sleep value \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -1761,7 +1762,7 @@ ngx_http_file_cache_set_slot(ngx_conf_t s.data = value[i].data + 17; loader_threshold = ngx_parse_time(&s, 0); - if (loader_threshold < 0) { + if (loader_threshold == (ngx_msec_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid loader_threshold value \"%V\"", &value[i]); return NGX_CONF_ERROR; @@ -1788,8 +1789,8 @@ ngx_http_file_cache_set_slot(ngx_conf_t cache->path->conf_file = cf->conf_file->file.name.data; cache->path->line = cf->conf_file->line; cache->loader_files = loader_files; - cache->loader_sleep = (ngx_msec_t) loader_sleep; - cache->loader_threshold = (ngx_msec_t) loader_threshold; + cache->loader_sleep = loader_sleep; + cache->loader_threshold = loader_threshold; if (ngx_add_path(cf, &cache->path) != NGX_OK) { return NGX_CONF_ERROR; @@ -1843,7 +1844,7 @@ ngx_http_file_cache_valid_set_slot(ngx_c n = cf->args->nelts - 1; valid = ngx_parse_time(&value[n], 1); - if (valid < 0) { + if (valid == (time_t) NGX_ERROR) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid time value \"%V\"", &value[n]); return NGX_CONF_ERROR; 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 @@ -2010,6 +2010,7 @@ ngx_http_finalize_request(ngx_http_reque if (r == c->data) { r->main->count--; + r->main->subrequests++; if (!r->logged) { @@ -2927,6 +2928,10 @@ ngx_http_post_action(ngx_http_request_t return NGX_DECLINED; } + if (r->post_action && r->uri_changes == 0) { + return NGX_DECLINED; + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "post action: \"%V\"", &clcf->post_action); 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 @@ -478,7 +478,7 @@ struct ngx_http_request_s { /* * instead of using the request context data in - * ngx_http_limit_zone_module and ngx_http_limit_req_module + * ngx_http_limit_conn_module and ngx_http_limit_req_module * we use the single bits in the request structure */ unsigned limit_conn_set: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 @@ -1505,6 +1505,9 @@ 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_open_cached_file(clcf->open_file_cache, &path, &of, r->pool) != NGX_OK) 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 @@ -110,6 +110,8 @@ static ngx_int_t ngx_http_upstream_rewri ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_rewrite_refresh(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -198,7 +200,7 @@ ngx_http_upstream_header_t ngx_http_ups { ngx_string("Set-Cookie"), ngx_http_upstream_process_set_cookie, 0, - ngx_http_upstream_copy_header_line, 0, 1 }, + ngx_http_upstream_rewrite_set_cookie, 0, 1 }, { ngx_string("Content-Disposition"), ngx_http_upstream_ignore_header_line, 0, @@ -1591,7 +1593,7 @@ ngx_http_upstream_process_header(ngx_htt if (rc == NGX_AGAIN) { - if (u->buffer.pos == u->buffer.end) { + if (u->buffer.last == u->buffer.end) { ngx_log_error(NGX_LOG_ERR, c->log, 0, "upstream sent too big header"); @@ -2649,7 +2651,6 @@ ngx_http_upstream_process_upstream(ngx_h static void ngx_http_upstream_process_request(ngx_http_request_t *r) { - ngx_uint_t del; ngx_temp_file_t *tf; ngx_event_pipe_t *p; ngx_http_upstream_t *u; @@ -2661,30 +2662,16 @@ ngx_http_upstream_process_request(ngx_ht if (u->store) { - del = p->upstream_error; - - tf = u->pipe->temp_file; - if (p->upstream_eof || p->upstream_done) { + tf = u->pipe->temp_file; + if (u->headers_in.status_n == NGX_HTTP_OK && (u->headers_in.content_length_n == -1 || (u->headers_in.content_length_n == tf->offset))) { ngx_http_upstream_store(r, u); - - } else { - del = 1; - } - } - - if (del && tf->file.fd != NGX_INVALID_FILE) { - - if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) { - - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_delete_file_n " \"%s\" failed", - u->pipe->temp_file->file.name.data); + u->store = 0; } } } @@ -3047,6 +3034,18 @@ ngx_http_upstream_finalize_request(ngx_h u->pipe->temp_file->file.fd); } + if (u->store && u->pipe && u->pipe->temp_file + && u->pipe->temp_file->file.fd != NGX_INVALID_FILE) + { + if (ngx_delete_file(u->pipe->temp_file->file.name.data) + == NGX_FILE_ERROR) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_delete_file_n " \"%s\" failed", + u->pipe->temp_file->file.name.data); + } + } + #if (NGX_HTTP_CACHE) if (r->cache) { @@ -3673,6 +3672,27 @@ ngx_http_upstream_rewrite_refresh(ngx_ht static ngx_int_t +ngx_http_upstream_rewrite_set_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t *ho; + + ho = ngx_list_push(&r->headers_out.headers); + if (ho == NULL) { + return NGX_ERROR; + } + + *ho = *h; + + if (r->upstream->rewrite_cookie) { + return r->upstream->rewrite_cookie(r, ho); + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_upstream_copy_allow_ranges(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { @@ -4248,7 +4268,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, fail_timeout = ngx_parse_time(&s, 1); - if (fail_timeout == NGX_ERROR) { + if (fail_timeout == (time_t) NGX_ERROR) { goto invalid; } diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -299,6 +299,8 @@ struct ngx_http_upstream_s { ngx_int_t rc); ngx_int_t (*rewrite_redirect)(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix); + ngx_int_t (*rewrite_cookie)(ngx_http_request_t *r, + ngx_table_elt_t *h); ngx_msec_t timeout; diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -432,7 +432,7 @@ ngx_http_get_flushed_variable(ngx_http_r v = &r->variables[index]; - if (v->valid) { + if (v->valid || v->not_found) { if (!v->no_cacheable) { return v; } diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -479,7 +479,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx s.len = p - s.data; ls->tcp_keepidle = ngx_parse_time(&s, 1); - if (ls->tcp_keepidle == NGX_ERROR) { + if (ls->tcp_keepidle == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } @@ -495,7 +495,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx s.len = p - s.data; ls->tcp_keepintvl = ngx_parse_time(&s, 1); - if (ls->tcp_keepintvl == NGX_ERROR) { + if (ls->tcp_keepintvl == (time_t) NGX_ERROR) { goto invalid_so_keepalive; } } diff --git a/src/os/unix/ngx_errno.h b/src/os/unix/ngx_errno.h --- a/src/os/unix/ngx_errno.h +++ b/src/os/unix/ngx_errno.h @@ -48,6 +48,11 @@ typedef int ngx_err_t; #define NGX_EILSEQ EILSEQ #define NGX_ENOMOREFILES 0 +#if (NGX_HAVE_OPENAT) +#define NGX_EMLINK EMLINK +#define NGX_ELOOP ELOOP +#endif + #if (__hpux__) #define NGX_EAGAIN EWOULDBLOCK #else 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 @@ -76,6 +76,10 @@ typedef struct { #define NGX_FILE_APPEND O_WRONLY|O_APPEND #define NGX_FILE_NONBLOCK O_NONBLOCK +#if (NGX_HAVE_OPENAT) +#define NGX_FILE_NOFOLLOW O_NOFOLLOW +#endif + #define NGX_FILE_DEFAULT_ACCESS 0644 #define NGX_FILE_OWNER_ACCESS 0600 @@ -324,6 +328,21 @@ ngx_int_t ngx_directio_off(ngx_fd_t fd); size_t ngx_fs_bsize(u_char *name); +#if (NGX_HAVE_OPENAT) + +#define ngx_openat_file(fd, name, mode, create, access) \ + openat(fd, (const char *) name, mode|create, access) + +#define ngx_openat_file_n "openat()" + +#define ngx_file_at_info(fd, name, sb, flag) \ + fstatat(fd, (const char *) name, sb, flag) + +#define ngx_file_at_info_n "fstatat()" + +#endif + + #define ngx_stderr STDERR_FILENO #define ngx_set_stderr(fd) dup2(fd, STDERR_FILENO) #define ngx_set_stderr_n "dup2(STDERR_FILENO)" diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -47,7 +47,13 @@ ngx_os_init(ngx_log_t *log) for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ } +#if (NGX_HAVE_SC_NPROCESSORS_ONLN) if (ngx_ncpu == 0) { + ngx_ncpu = sysconf(_SC_NPROCESSORS_ONLN); + } +#endif + + if (ngx_ncpu < 1) { ngx_ncpu = 1; }