# HG changeset patch # User Igor Sysoev # Date 1356379200 -14400 # Node ID 88a1b4797f2eedfb0d1a50f30b7925c25ca95626 # Parent cfd4279acc6e9b3d2f5926b7f321365c1d0fb8d0 nginx 1.3.10 *) Change: domain names specified in configuration file are now resolved to IPv6 addresses as well as IPv4 ones. *) Change: now if the "include" directive with mask is used on Unix systems, included files are sorted in alphabetical order. *) Change: the "add_header" directive adds headers to 201 responses. *) Feature: the "geo" directive now supports IPv6 addresses in CIDR notation. *) Feature: the "flush" and "gzip" parameters of the "access_log" directive. *) Feature: variables support in the "auth_basic" directive. *) Bugfix: nginx could not be built with the ngx_http_perl_module in some cases. *) Bugfix: a segmentation fault might occur in a worker process if the ngx_http_xslt_module was used. *) Bugfix: nginx could not be built on MacOSX in some cases. Thanks to Piotr Sikora. *) Bugfix: the "limit_rate" directive with high rates might result in truncated responses on 32-bit platforms. Thanks to Alexey Antropov. *) Bugfix: a segmentation fault might occur in a worker process if the "if" directive was used. Thanks to Piotr Sikora. *) Bugfix: a "100 Continue" response was issued with "413 Request Entity Too Large" responses. *) Bugfix: the "image_filter", "image_filter_jpeg_quality" and "image_filter_sharpen" directives might be inherited incorrectly. Thanks to Ian Babrou. *) Bugfix: "crypt_r() failed" errors might appear if the "auth_basic" directive was used on Linux. *) Bugfix: in backup servers handling. Thanks to Thomas Chen. *) Bugfix: proxied HEAD requests might return incorrect response if the "gzip" directive was used. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,56 @@ +Changes with nginx 1.3.10 25 Dec 2012 + + *) Change: domain names specified in configuration file are now resolved + to IPv6 addresses as well as IPv4 ones. + + *) Change: now if the "include" directive with mask is used on Unix + systems, included files are sorted in alphabetical order. + + *) Change: the "add_header" directive adds headers to 201 responses. + + *) Feature: the "geo" directive now supports IPv6 addresses in CIDR + notation. + + *) Feature: the "flush" and "gzip" parameters of the "access_log" + directive. + + *) Feature: variables support in the "auth_basic" directive. + + *) Bugfix: nginx could not be built with the ngx_http_perl_module in + some cases. + + *) Bugfix: a segmentation fault might occur in a worker process if the + ngx_http_xslt_module was used. + + *) Bugfix: nginx could not be built on MacOSX in some cases. + Thanks to Piotr Sikora. + + *) Bugfix: the "limit_rate" directive with high rates might result in + truncated responses on 32-bit platforms. + Thanks to Alexey Antropov. + + *) Bugfix: a segmentation fault might occur in a worker process if the + "if" directive was used. + Thanks to Piotr Sikora. + + *) Bugfix: a "100 Continue" response was issued with "413 Request Entity + Too Large" responses. + + *) Bugfix: the "image_filter", "image_filter_jpeg_quality" and + "image_filter_sharpen" directives might be inherited incorrectly. + Thanks to Ian Babrou. + + *) Bugfix: "crypt_r() failed" errors might appear if the "auth_basic" + directive was used on Linux. + + *) Bugfix: in backup servers handling. + Thanks to Thomas Chen. + + *) Bugfix: proxied HEAD requests might return incorrect response if the + "gzip" directive was used. + + Changes with nginx 1.3.9 27 Nov 2012 *) Feature: support for chunked transfer encoding while reading client diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,57 @@ +Изменения в nginx 1.3.10 25.12.2012 + + *) Изменение: для указанных в конфигурационном файле доменных имён + теперь используются не только IPv4, но и IPv6 адреса. + + *) Изменение: теперь при использовании директивы include с маской на + Unix-системах включаемые файлы сортируются в алфавитном порядке. + + *) Изменение: директива add_header добавляет строки в ответы с кодом + 201. + + *) Добавление: директива geo теперь поддерживает IPv6 адреса в формате + CIDR. + + *) Добавление: параметры flush и gzip в директиве access_log. + + *) Добавление: директива auth_basic поддерживает переменные. + + *) Исправление: nginx в некоторых случаях не собирался с модулем + ngx_http_perl_module. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовался модуль ngx_http_xslt_module. + + *) Исправление: nginx мог не собираться на MacOSX. + Спасибо Piotr Sikora. + + *) Исправление: при использовании директивы limit_rate с большими + значениями скорости на 32-битных системах ответ мог возвращаться не + целиком. + Спасибо Алексею Антропову. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если использовалась директива if. + Спасибо Piotr Sikora. + + *) Исправление: ответ "100 Continue" выдавался вместе с ответом "413 + Request Entity Too Large". + + *) Исправление: директивы image_filter, image_filter_jpeg_quality и + image_filter_sharpen могли наследоваться некорректно. + Спасибо Ивану Боброву. + + *) Исправление: при использовании директивы auth_basic под Linux могли + возникать ошибки "crypt_r() failed". + + *) Исправление: в обработке backup-серверов. + Спасибо Thomas Chen. + + *) Исправление: при проксировании HEAD-запросов мог возвращаться + некорректный ответ, если использовалась директива gzip. + + Изменения в nginx 1.3.9 27.11.2012 *) Добавление: поддержка chunked transfer encoding при получении тела diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -172,6 +172,7 @@ else ngx_feature="PCRE JIT support" ngx_feature_name="NGX_HAVE_PCRE_JIT" ngx_feature_test="int jit = 0; + pcre_free_study(NULL); pcre_config(PCRE_CONFIG_JIT, &jit); if (jit != 1) return 1;" . auto/feature diff --git a/auto/lib/perl/make b/auto/lib/perl/make --- a/auto/lib/perl/make +++ b/auto/lib/perl/make @@ -26,9 +26,7 @@ cat << END cd $NGX_OBJS/src/http/modules/perl \ && NGX_PM_CFLAGS="\$(NGX_PM_CFLAGS) -g $NGX_CC_OPT" \ - NGX_PCRE=$PCRE \ - NGX_OBJS=$NGX_OBJS \ - NGX_OPENSSL=$OPENSSL \ + NGX_INCS="$CORE_INCS $NGX_OBJS $HTTP_INCS" \ $NGX_PERL Makefile.PL \ LIB=$NGX_PERL_MODULES \ INSTALLSITEMAN3DIR=$NGX_PERL_MODULES_MAN diff --git a/auto/lib/zlib/conf b/auto/lib/zlib/conf --- a/auto/lib/zlib/conf +++ b/auto/lib/zlib/conf @@ -9,11 +9,13 @@ if [ $ZLIB != NONE ]; then case "$NGX_CC_NAME" in msvc* | owc* | bcc) + have=NGX_ZLIB . auto/have LINK_DEPS="$LINK_DEPS $ZLIB/zlib.lib" CORE_LIBS="$CORE_LIBS $ZLIB/zlib.lib" ;; icc*) + have=NGX_ZLIB . auto/have LINK_DEPS="$LINK_DEPS $ZLIB/libz.a" # to allow -ipo optimization we link with the *.o but not library @@ -30,6 +32,7 @@ if [ $ZLIB != NONE ]; then ;; *) + have=NGX_ZLIB . auto/have LINK_DEPS="$LINK_DEPS $ZLIB/libz.a" CORE_LIBS="$CORE_LIBS $ZLIB/libz.a" #CORE_LIBS="$CORE_LIBS -L $ZLIB -lz" @@ -45,7 +48,7 @@ else # FreeBSD, Solaris, Linux ngx_feature="zlib library" - ngx_feature_name= + ngx_feature_name="NGX_ZLIB" ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -778,3 +778,17 @@ ngx_feature_test="struct stat sb; openat(AT_FDCWD, \".\", O_RDONLY|O_NOFOLLOW); fstatat(AT_FDCWD, \".\", &sb, AT_SYMLINK_NOFOLLOW);" . auto/feature + + +ngx_feature="getaddrinfo()" +ngx_feature_name="NGX_HAVE_GETADDRINFO" +ngx_feature_run=no +ngx_feature_incs="#include + #include + #include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test='struct addrinfo *res; + if (getaddrinfo("localhost", NULL, NULL, &res) != 0) return 1; + freeaddrinfo(res)' +. 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 1003009 -#define NGINX_VERSION "1.3.9" +#define nginx_version 1003010 +#define NGINX_VERSION "1.3.10" #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 @@ -945,7 +945,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n file->name = *name; } - file->buffer = NULL; + file->flush = NULL; return file; } @@ -954,7 +954,6 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n static void ngx_conf_flush_files(ngx_cycle_t *cycle) { - ssize_t n, len; ngx_uint_t i; ngx_list_part_t *part; ngx_open_file_t *file; @@ -975,23 +974,8 @@ ngx_conf_flush_files(ngx_cycle_t *cycle) i = 0; } - len = file[i].pos - file[i].buffer; - - if (file[i].buffer == NULL || len == 0) { - continue; - } - - n = ngx_write_fd(file[i].fd, file[i].buffer, len); - - if (n == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - ngx_write_fd_n " to \"%s\" failed", - file[i].name.data); - - } else if (n != len) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", - file[i].name.data, n, len); + if (file[i].flush) { + file[i].flush(&file[i], cycle->log); } } } diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -91,17 +91,8 @@ struct ngx_open_file_s { ngx_fd_t fd; ngx_str_t name; - u_char *buffer; - u_char *pos; - u_char *last; - -#if 0 - /* e.g. append mode, error_log */ - ngx_uint_t flags; - /* e.g. reopen db file */ - ngx_uint_t (*handler)(void *data, ngx_open_file_t *file); + void (*flush)(ngx_open_file_t *file, ngx_log_t *log); void *data; -#endif }; diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -1115,7 +1115,6 @@ ngx_test_lockfile(u_char *file, ngx_log_ void ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user) { - ssize_t n, len; ngx_fd_t fd; ngx_uint_t i; ngx_list_part_t *part; @@ -1139,24 +1138,8 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx continue; } - len = file[i].pos - file[i].buffer; - - if (file[i].buffer && len != 0) { - - n = ngx_write_fd(file[i].fd, file[i].buffer, len); - - if (n == NGX_FILE_ERROR) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, - ngx_write_fd_n " to \"%s\" failed", - file[i].name.data); - - } else if (n != len) { - ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, - ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", - file[i].name.data, n, len); - } - - file[i].pos = file[i].buffer; + if (file[i].flush) { + file[i].flush(&file[i], cycle->log); } fd = ngx_open_file(file[i].name.data, NGX_FILE_APPEND, diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -732,14 +732,14 @@ ngx_copy_file(u_char *from, u_char *to, n = ngx_read_fd(fd, buf, len); - if (n == NGX_FILE_ERROR) { + if (n == -1) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_read_fd_n " \"%s\" failed", from); goto failed; } if ((size_t) n != len) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, ngx_read_fd_n " has read only %z of %uz from %s", n, size, from); goto failed; @@ -747,14 +747,14 @@ ngx_copy_file(u_char *from, u_char *to, n = ngx_write_fd(nfd, buf, len); - if (n == NGX_FILE_ERROR) { + if (n == -1) { ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, ngx_write_fd_n " \"%s\" failed", to); goto failed; } if ((size_t) n != len) { - ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_log_error(NGX_LOG_ALERT, cf->log, 0, ngx_write_fd_n " has written only %z of %uz to %s", n, size, to); goto failed; diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -465,7 +465,7 @@ ngx_parse_addr(ngx_pool_t *pool, ngx_add * prevent MSVC8 warning: * potentially uninitialized local variable 'inaddr6' used */ - ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr)); + ngx_memzero(&inaddr6, sizeof(struct in6_addr)); #endif inaddr = ngx_inet_addr(text, len); @@ -611,11 +611,13 @@ ngx_parse_unix_domain_url(ngx_pool_t *po static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host, *port, *last, *uri, *args; - size_t len; - ngx_int_t n; - struct hostent *h; - struct sockaddr_in *sin; + u_char *p, *host, *port, *last, *uri, *args; + size_t len; + ngx_int_t n; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif u->socklen = sizeof(struct sockaddr_in); sin = (struct sockaddr_in *) &u->sockaddr; @@ -705,6 +707,11 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx } u->no_port = 1; + + if (!u->no_resolve) { + u->port = u->default_port; + sin->sin_port = htons(u->default_port); + } } len = last - host; @@ -714,59 +721,88 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx return NGX_ERROR; } - if (len == 1 && *host == '*') { - len = 0; + u->host.len = len; + u->host.data = host; + + if (u->listen && len == 1 && *host == '*') { + sin->sin_addr.s_addr = INADDR_ANY; + u->wildcard = 1; + return NGX_OK; } - u->host.len = len; - u->host.data = host; + sin->sin_addr.s_addr = ngx_inet_addr(host, len); + + if (sin->sin_addr.s_addr != INADDR_NONE) { + + if (sin->sin_addr.s_addr == INADDR_ANY) { + u->wildcard = 1; + } + + u->naddrs = 1; + + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + sin = ngx_pcalloc(pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(sin, u->sockaddr, sizeof(struct sockaddr_in)); + + u->addrs[0].sockaddr = (struct sockaddr *) sin; + u->addrs[0].socklen = sizeof(struct sockaddr_in); + + p = ngx_pnalloc(pool, u->host.len + sizeof(":65535") - 1); + if (p == NULL) { + return NGX_ERROR; + } + + u->addrs[0].name.len = ngx_sprintf(p, "%V:%d", + &u->host, u->port) - p; + u->addrs[0].name.data = p; + + return NGX_OK; + } if (u->no_resolve) { return NGX_OK; } - if (len) { - sin->sin_addr.s_addr = ngx_inet_addr(host, len); + if (ngx_inet_resolve_host(pool, u) != NGX_OK) { + return NGX_ERROR; + } - if (sin->sin_addr.s_addr == INADDR_NONE) { - p = ngx_alloc(++len, pool->log); - if (p == NULL) { - return NGX_ERROR; - } + u->family = u->addrs[0].sockaddr->sa_family; + u->socklen = u->addrs[0].socklen; + ngx_memcpy(u->sockaddr, u->addrs[0].sockaddr, u->addrs[0].socklen); - (void) ngx_cpystrn(p, host, len); + switch (u->family) { - h = gethostbyname((const char *) p); - - ngx_free(p); +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) &u->sockaddr; - if (h == NULL || h->h_addr_list[0] == NULL) { - u->err = "host not found"; - return NGX_ERROR; - } + if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { + u->wildcard = 1; + } - sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[0]); - } + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) &u->sockaddr; if (sin->sin_addr.s_addr == INADDR_ANY) { u->wildcard = 1; } - } else { - sin->sin_addr.s_addr = INADDR_ANY; - u->wildcard = 1; + break; } - if (u->no_port) { - u->port = u->default_port; - sin->sin_port = htons(u->default_port); - } - - if (u->listen) { - return NGX_OK; - } - - return ngx_inet_resolve_host(pool, u); + return NGX_OK; } @@ -832,6 +868,11 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng } else { u->no_port = 1; + + if (!u->no_resolve) { + u->port = u->default_port; + sin6->sin6_port = htons(u->default_port); + } } } @@ -854,11 +895,6 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng u->wildcard = 1; } - if (u->no_port) { - u->port = u->default_port; - sin6->sin6_port = htons(u->default_port); - } - u->family = AF_INET6; u->naddrs = 1; @@ -898,6 +934,150 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng } +#if (NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6) + +ngx_int_t +ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p, *host; + size_t len; + in_port_t port; + ngx_uint_t i; + struct addrinfo hints, *res, *rp; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + + port = htons(u->port); + + host = ngx_alloc(u->host.len + 1, pool->log); + if (host == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + + ngx_memzero(&hints, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + if (getaddrinfo((char *) host, NULL, &hints, &res) != 0) { + u->err = "host not found"; + ngx_free(host); + return NGX_ERROR; + } + + ngx_free(host); + + for (i = 0, rp = res; rp != NULL; rp = rp->ai_next) { + + switch (rp->ai_family) { + + case AF_INET: + case AF_INET6: + break; + + default: + continue; + } + + i++; + } + + if (i == 0) { + u->err = "host not found"; + goto failed; + } + + /* MP: ngx_shared_palloc() */ + + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); + if (u->addrs == NULL) { + goto failed; + } + + u->naddrs = i; + + i = 0; + + /* AF_INET addresses first */ + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET) { + continue; + } + + sin = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin == NULL) { + goto failed; + } + + ngx_memcpy(sin, rp->ai_addr, rp->ai_addrlen); + + sin->sin_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin, p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + for (rp = res; rp != NULL; rp = rp->ai_next) { + + if (rp->ai_family != AF_INET6) { + continue; + } + + sin6 = ngx_pcalloc(pool, rp->ai_addrlen); + if (sin6 == NULL) { + goto failed; + } + + ngx_memcpy(sin6, rp->ai_addr, rp->ai_addrlen); + + sin6->sin6_port = port; + + u->addrs[i].sockaddr = (struct sockaddr *) sin6; + u->addrs[i].socklen = rp->ai_addrlen; + + len = NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1; + + p = ngx_pnalloc(pool, len); + if (p == NULL) { + goto failed; + } + + len = ngx_sock_ntop((struct sockaddr *) sin6, p, len, 1); + + u->addrs[i].name.len = len; + u->addrs[i].name.data = p; + + i++; + } + + freeaddrinfo(res); + return NGX_OK; + +failed: + + freeaddrinfo(res); + return NGX_ERROR; +} + +#else /* !NGX_HAVE_GETADDRINFO || !NGX_HAVE_INET6 */ + ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u) { @@ -932,12 +1112,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, return NGX_ERROR; } - if (u->one_addr == 0) { - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } - - } else { - i = 1; - } + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } /* MP: ngx_shared_palloc() */ @@ -1010,3 +1185,5 @@ ngx_inet_resolve_host(ngx_pool_t *pool, return NGX_OK; } + +#endif /* NGX_HAVE_GETADDRINFO && NGX_HAVE_INET6 */ diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -30,7 +30,7 @@ #if (NGX_HAVE_UNIX_DOMAIN) #define NGX_SOCKADDR_STRLEN (sizeof("unix:") - 1 + NGX_UNIX_ADDRSTRLEN) #else -#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof(":65535") - 1) +#define NGX_SOCKADDR_STRLEN (NGX_INET6_ADDRSTRLEN + sizeof("[]:65535") - 1) #endif #if (NGX_HAVE_UNIX_DOMAIN) @@ -87,7 +87,7 @@ typedef struct { unsigned listen:1; unsigned uri_part:1; unsigned no_resolve:1; - unsigned one_addr:1; + unsigned one_addr:1; /* compatibility */ unsigned no_port:1; unsigned wildcard:1; diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c --- a/src/core/ngx_radix_tree.c +++ b/src/core/ngx_radix_tree.c @@ -9,7 +9,7 @@ #include -static void *ngx_radix_alloc(ngx_radix_tree_t *tree); +static ngx_radix_node_t *ngx_radix_alloc(ngx_radix_tree_t *tree); ngx_radix_tree_t * @@ -263,13 +263,210 @@ ngx_radix32tree_find(ngx_radix_tree_t *t } -static void * +#if (NGX_HAVE_INET6) + +ngx_int_t +ngx_radix128tree_insert(ngx_radix_tree_t *tree, u_char *key, u_char *mask, + uintptr_t value) +{ + u_char bit; + ngx_uint_t i; + ngx_radix_node_t *node, *next; + + i = 0; + bit = 0x80; + + node = tree->root; + next = tree->root; + + while (bit & mask[i]) { + if (key[i] & bit) { + next = node->right; + + } else { + next = node->left; + } + + if (next == NULL) { + break; + } + + bit >>= 1; + node = next; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + if (next) { + if (node->value != NGX_RADIX_NO_VALUE) { + return NGX_BUSY; + } + + node->value = value; + return NGX_OK; + } + + while (bit & mask[i]) { + next = ngx_radix_alloc(tree); + if (next == NULL) { + return NGX_ERROR; + } + + next->right = NULL; + next->left = NULL; + next->parent = node; + next->value = NGX_RADIX_NO_VALUE; + + if (key[i] & bit) { + node->right = next; + + } else { + node->left = next; + } + + bit >>= 1; + node = next; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + node->value = value; + + return NGX_OK; +} + + +ngx_int_t +ngx_radix128tree_delete(ngx_radix_tree_t *tree, u_char *key, u_char *mask) +{ + u_char bit; + ngx_uint_t i; + ngx_radix_node_t *node; + + i = 0; + bit = 0x80; + node = tree->root; + + while (node && (bit & mask[i])) { + if (key[i] & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + + if (bit == 0) { + if (++i == 16) { + break; + } + + bit = 0x80; + } + } + + if (node == NULL) { + return NGX_ERROR; + } + + if (node->right || node->left) { + if (node->value != NGX_RADIX_NO_VALUE) { + node->value = NGX_RADIX_NO_VALUE; + return NGX_OK; + } + + return NGX_ERROR; + } + + for ( ;; ) { + if (node->parent->right == node) { + node->parent->right = NULL; + + } else { + node->parent->left = NULL; + } + + node->right = tree->free; + tree->free = node; + + node = node->parent; + + if (node->right || node->left) { + break; + } + + if (node->value != NGX_RADIX_NO_VALUE) { + break; + } + + if (node->parent == NULL) { + break; + } + } + + return NGX_OK; +} + + +uintptr_t +ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key) +{ + u_char bit; + uintptr_t value; + ngx_uint_t i; + ngx_radix_node_t *node; + + i = 0; + bit = 0x80; + value = NGX_RADIX_NO_VALUE; + node = tree->root; + + while (node) { + if (node->value != NGX_RADIX_NO_VALUE) { + value = node->value; + } + + if (key[i] & bit) { + node = node->right; + + } else { + node = node->left; + } + + bit >>= 1; + + if (bit == 0) { + i++; + bit = 0x80; + } + } + + return value; +} + +#endif + + +static ngx_radix_node_t * ngx_radix_alloc(ngx_radix_tree_t *tree) { - char *p; + ngx_radix_node_t *p; if (tree->free) { - p = (char *) tree->free; + p = tree->free; tree->free = tree->free->right; return p; } @@ -283,7 +480,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree) tree->size = ngx_pagesize; } - p = tree->start; + p = (ngx_radix_node_t *) tree->start; tree->start += sizeof(ngx_radix_node_t); tree->size -= sizeof(ngx_radix_node_t); diff --git a/src/core/ngx_radix_tree.h b/src/core/ngx_radix_tree.h --- a/src/core/ngx_radix_tree.h +++ b/src/core/ngx_radix_tree.h @@ -36,11 +36,20 @@ typedef struct { ngx_radix_tree_t *ngx_radix_tree_create(ngx_pool_t *pool, ngx_int_t preallocate); + ngx_int_t ngx_radix32tree_insert(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask, uintptr_t value); ngx_int_t ngx_radix32tree_delete(ngx_radix_tree_t *tree, uint32_t key, uint32_t mask); uintptr_t ngx_radix32tree_find(ngx_radix_tree_t *tree, uint32_t key); +#if (NGX_HAVE_INET6) +ngx_int_t ngx_radix128tree_insert(ngx_radix_tree_t *tree, + u_char *key, u_char *mask, uintptr_t value); +ngx_int_t ngx_radix128tree_delete(ngx_radix_tree_t *tree, + u_char *key, u_char *mask); +uintptr_t ngx_radix128tree_find(ngx_radix_tree_t *tree, u_char *key); +#endif + #endif /* _NGX_RADIX_TREE_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -20,8 +20,8 @@ typedef struct { typedef struct { - ngx_str_t realm; - ngx_http_complex_value_t user_file; + ngx_http_complex_value_t *realm; + ngx_http_complex_value_t user_file; } ngx_http_auth_basic_loc_conf_t; @@ -35,22 +35,19 @@ static void *ngx_http_auth_basic_create_ static char *ngx_http_auth_basic_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf); -static char *ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data); static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static ngx_conf_post_handler_pt ngx_http_auth_basic_p = ngx_http_auth_basic; - static ngx_command_t ngx_http_auth_basic_commands[] = { { ngx_string("auth_basic"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF |NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_set_complex_value_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_auth_basic_loc_conf_t, realm), - &ngx_http_auth_basic_p }, + NULL }, { ngx_string("auth_basic_user_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF @@ -103,7 +100,7 @@ ngx_http_auth_basic_handler(ngx_http_req ngx_fd_t fd; ngx_int_t rc; ngx_err_t err; - ngx_str_t pwd, user_file; + ngx_str_t pwd, realm, user_file; ngx_uint_t i, level, login, left, passwd; ngx_file_t file; ngx_http_auth_basic_ctx_t *ctx; @@ -117,7 +114,15 @@ ngx_http_auth_basic_handler(ngx_http_req alcf = ngx_http_get_module_loc_conf(r, ngx_http_auth_basic_module); - if (alcf->realm.len == 0 || alcf->user_file.value.len == 0) { + if (alcf->realm == NULL || alcf->user_file.value.data == NULL) { + return NGX_DECLINED; + } + + if (ngx_http_complex_value(r, alcf->realm, &realm) != NGX_OK) { + return NGX_ERROR; + } + + if (realm.len == 3 && ngx_strncmp(realm.data, "off", 3) == 0) { return NGX_DECLINED; } @@ -125,7 +130,7 @@ ngx_http_auth_basic_handler(ngx_http_req if (ctx) { return ngx_http_auth_basic_crypt_handler(r, ctx, &ctx->passwd, - &alcf->realm); + &realm); } rc = ngx_http_auth_basic_user(r); @@ -135,7 +140,7 @@ ngx_http_auth_basic_handler(ngx_http_req ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no user/password was provided for basic authentication"); - return ngx_http_auth_basic_set_realm(r, &alcf->realm); + return ngx_http_auth_basic_set_realm(r, &realm); } if (rc == NGX_ERROR) { @@ -233,7 +238,7 @@ ngx_http_auth_basic_handler(ngx_http_req pwd.data = &buf[passwd]; return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, - &alcf->realm); + &realm); } break; @@ -271,14 +276,14 @@ ngx_http_auth_basic_handler(ngx_http_req ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1); - return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &alcf->realm); + return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &realm); } ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "user \"%V\" was not found in \"%V\"", &r->headers_in.user, &user_file); - return ngx_http_auth_basic_set_realm(r, &alcf->realm); + return ngx_http_auth_basic_set_realm(r, &realm); } @@ -344,14 +349,29 @@ ngx_http_auth_basic_crypt_handler(ngx_ht static ngx_int_t ngx_http_auth_basic_set_realm(ngx_http_request_t *r, ngx_str_t *realm) { + size_t len; + u_char *basic, *p; + r->headers_out.www_authenticate = ngx_list_push(&r->headers_out.headers); if (r->headers_out.www_authenticate == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } + len = sizeof("Basic realm=\"\"") - 1 + realm->len; + + basic = ngx_pnalloc(r->pool, len); + if (basic == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1); + p = ngx_cpymem(p, realm->data, realm->len); + *p = '"'; + r->headers_out.www_authenticate->hash = 1; ngx_str_set(&r->headers_out.www_authenticate->key, "WWW-Authenticate"); - r->headers_out.www_authenticate->value = *realm; + r->headers_out.www_authenticate->value.data = basic; + r->headers_out.www_authenticate->value.len = len; return NGX_HTTP_UNAUTHORIZED; } @@ -386,11 +406,11 @@ ngx_http_auth_basic_merge_loc_conf(ngx_c ngx_http_auth_basic_loc_conf_t *prev = parent; ngx_http_auth_basic_loc_conf_t *conf = child; - if (conf->realm.data == NULL) { + if (conf->realm == NULL) { conf->realm = prev->realm; } - if (conf->user_file.value.len == 0) { + if (conf->user_file.value.data == NULL) { conf->user_file = prev->user_file; } @@ -418,37 +438,6 @@ ngx_http_auth_basic_init(ngx_conf_t *cf) static char * -ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data) -{ - ngx_str_t *realm = data; - - size_t len; - u_char *basic, *p; - - if (ngx_strcmp(realm->data, "off") == 0) { - ngx_str_set(realm, ""); - return NGX_CONF_OK; - } - - len = sizeof("Basic realm=\"") - 1 + realm->len + 1; - - basic = ngx_pnalloc(cf->pool, len); - if (basic == NULL) { - return NGX_CONF_ERROR; - } - - p = ngx_cpymem(basic, "Basic realm=\"", sizeof("Basic realm=\"") - 1); - p = ngx_cpymem(p, realm->data, realm->len); - *p = '"'; - - realm->len = len; - realm->data = basic; - - return NGX_CONF_OK; -} - - -static char * ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_auth_basic_loc_conf_t *alcf = conf; @@ -456,7 +445,7 @@ ngx_http_auth_basic_user_file(ngx_conf_t ngx_str_t *value; ngx_http_compile_complex_value_t ccv; - if (alcf->user_file.value.len) { + if (alcf->user_file.value.data) { return "is duplicate"; } diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -3014,7 +3014,7 @@ ngx_http_fastcgi_cache_key(ngx_conf_t *c value = cf->args->elts; - if (flcf->cache_key.value.len) { + if (flcf->cache_key.value.data) { return "is duplicate"; } diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -18,6 +18,14 @@ typedef struct { typedef struct { + ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif +} ngx_http_geo_trees_t; + + +typedef struct { ngx_http_geo_range_t **low; ngx_http_variable_value_t *default_value; } ngx_http_geo_high_ranges_t; @@ -35,6 +43,9 @@ typedef struct { ngx_str_t *net; ngx_http_geo_high_ranges_t high; ngx_radix_tree_t *tree; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *tree6; +#endif ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; ngx_array_t *proxies; @@ -57,7 +68,7 @@ typedef struct { typedef struct { union { - ngx_radix_tree_t *tree; + ngx_http_geo_trees_t trees; ngx_http_geo_high_ranges_t high; } u; @@ -68,8 +79,8 @@ typedef struct { } ngx_http_geo_ctx_t; -static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, - ngx_http_geo_ctx_t *ctx); +static ngx_int_t ngx_http_geo_addr(ngx_http_request_t *r, + ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); static ngx_int_t ngx_http_geo_real_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, ngx_addr_t *addr); static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -155,7 +166,7 @@ static ngx_http_geo_header_t ngx_http_g }; -/* AF_INET only */ +/* geo range is AF_INET only */ static ngx_int_t ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, @@ -163,10 +174,56 @@ ngx_http_geo_cidr_variable(ngx_http_requ { ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; + in_addr_t inaddr; + ngx_addr_t addr; + struct sockaddr_in *sin; ngx_http_variable_value_t *vv; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif + + if (ngx_http_geo_addr(r, ctx, &addr) != NGX_OK) { + vv = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, INADDR_NONE); + goto done; + } + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + p = inaddr6->s6_addr; - vv = (ngx_http_variable_value_t *) - ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx)); + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + vv = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + } else { + vv = (ngx_http_variable_value_t *) + ngx_radix128tree_find(ctx->u.trees.tree6, p); + } + + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + + vv = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->u.trees.tree, inaddr); + + break; + } + +done: *v = *vv; @@ -183,25 +240,65 @@ ngx_http_geo_range_variable(ngx_http_req { ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; - in_addr_t addr; + in_addr_t inaddr; + ngx_addr_t addr; ngx_uint_t n; + struct sockaddr_in *sin; ngx_http_geo_range_t *range; +#if (NGX_HAVE_INET6) + u_char *p; + struct in6_addr *inaddr6; +#endif *v = *ctx->u.high.default_value; - addr = ngx_http_geo_addr(r, ctx); + if (ngx_http_geo_addr(r, ctx, &addr) == NGX_OK) { + + switch (addr.sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; + + if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { + p = inaddr6->s6_addr; - range = ctx->u.high.low[addr >> 16]; + inaddr = p[12] << 24; + inaddr += p[13] << 16; + inaddr += p[14] << 8; + inaddr += p[15]; + + } else { + inaddr = INADDR_NONE; + } + + break; +#endif - if (range) { - n = addr & 0xffff; - do { - if (n >= (ngx_uint_t) range->start && n <= (ngx_uint_t) range->end) - { - *v = *range->value; - break; - } - } while ((++range)->value); + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr.sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + break; + } + + } else { + inaddr = INADDR_NONE; + } + + if (ctx->u.high.low) { + range = ctx->u.high.low[inaddr >> 16]; + + if (range) { + n = inaddr & 0xffff; + do { + if (n >= (ngx_uint_t) range->start + && n <= (ngx_uint_t) range->end) + { + *v = *range->value; + break; + } + } while ((++range)->value); + } } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -211,54 +308,25 @@ ngx_http_geo_range_variable(ngx_http_req } -static in_addr_t -ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) +static ngx_int_t +ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx, + ngx_addr_t *addr) { - ngx_addr_t addr; - ngx_table_elt_t *xfwd; - struct sockaddr_in *sin; + ngx_table_elt_t *xfwd; - if (ngx_http_geo_real_addr(r, ctx, &addr) != NGX_OK) { - return INADDR_NONE; + if (ngx_http_geo_real_addr(r, ctx, addr) != NGX_OK) { + return NGX_ERROR; } xfwd = r->headers_in.x_forwarded_for; if (xfwd != NULL && ctx->proxies != NULL) { - (void) ngx_http_get_forwarded_addr(r, &addr, xfwd->value.data, + (void) ngx_http_get_forwarded_addr(r, addr, xfwd->value.data, xfwd->value.len, ctx->proxies, ctx->proxy_recursive); } -#if (NGX_HAVE_INET6) - - if (addr.sockaddr->sa_family == AF_INET6) { - u_char *p; - in_addr_t inaddr; - struct in6_addr *inaddr6; - - inaddr6 = &((struct sockaddr_in6 *) addr.sockaddr)->sin6_addr; - - if (IN6_IS_ADDR_V4MAPPED(inaddr6)) { - p = inaddr6->s6_addr; - - inaddr = p[12] << 24; - inaddr += p[13] << 16; - inaddr += p[14] << 8; - inaddr += p[15]; - - return inaddr; - } - } - -#endif - - if (addr.sockaddr->sa_family != AF_INET) { - return INADDR_NONE; - } - - sin = (struct sockaddr_in *) addr.sockaddr; - return ntohl(sin->sin_addr.s_addr); + return NGX_OK; } @@ -303,7 +371,6 @@ static char * ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - void **p; size_t len; ngx_str_t *value, name; ngx_uint_t i; @@ -313,6 +380,9 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c ngx_http_variable_t *var; ngx_http_geo_ctx_t *geo; ngx_http_geo_conf_ctx_t ctx; +#if (NGX_HAVE_INET6) + static struct in6_addr zero; +#endif value = cf->args->elts; @@ -322,6 +392,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c } name = value[1]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + name.len--; name.data++; @@ -333,6 +410,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c } name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + name.len--; name.data++; @@ -378,9 +462,9 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c geo->proxies = ctx.proxies; geo->proxy_recursive = ctx.proxy_recursive; - if (ctx.high.low) { + if (ctx.ranges) { - if (!ctx.binary_include) { + if (ctx.high.low && !ctx.binary_include) { for (i = 0; i < 0x10000; i++) { a = (ngx_array_t *) ctx.high.low[i]; @@ -395,8 +479,8 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - p = (void **) ngx_cpymem(ctx.high.low[i], a->elts, len); - *p = NULL; + ngx_memcpy(ctx.high.low[i], a->elts, len); + ctx.high.low[i][a->nelts].value = NULL; ctx.data_size += len + sizeof(void *); } @@ -429,7 +513,18 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c } } - geo->u.tree = ctx.tree; + geo->u.trees.tree = ctx.tree; + +#if (NGX_HAVE_INET6) + if (ctx.tree6 == NULL) { + ctx.tree6 = ngx_radix_tree_create(cf->pool, -1); + if (ctx.tree6 == NULL) { + return NGX_CONF_ERROR; + } + } + + geo->u.trees.tree6 = ctx.tree6; +#endif var->get_handler = ngx_http_geo_cidr_variable; var->data = (uintptr_t) geo; @@ -437,16 +532,23 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c ngx_destroy_pool(ctx.temp_pool); ngx_destroy_pool(pool); - if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) { - return rv; - } - if (ngx_radix32tree_insert(ctx.tree, 0, 0, (uintptr_t) &ngx_http_variable_null_value) == NGX_ERROR) { return NGX_CONF_ERROR; } + + /* NGX_BUSY is okay (default was set explicitly) */ + +#if (NGX_HAVE_INET6) + if (ngx_radix128tree_insert(ctx.tree6, zero.s6_addr, zero.s6_addr, + (uintptr_t) &ngx_http_variable_null_value) + == NGX_ERROR) + { + return NGX_CONF_ERROR; + } +#endif } return rv; @@ -469,7 +571,12 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command if (ngx_strcmp(value[0].data, "ranges") == 0) { - if (ctx->tree) { + if (ctx->tree +#if (NGX_HAVE_INET6) + || ctx->tree6 +#endif + ) + { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the \"ranges\" directive must be " "the first directive inside \"geo\" block"); @@ -920,8 +1027,17 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht } } +#if (NGX_HAVE_INET6) + if (ctx->tree6 == NULL) { + ctx->tree6 = ngx_radix_tree_create(ctx->pool, -1); + if (ctx->tree6 == NULL) { + return NGX_CONF_ERROR; + } + } +#endif + if (ngx_strcmp(value[0].data, "default") == 0) { - /* cidr.family = AF_INET; */ + cidr.family = AF_INET; cidr.u.in.addr = 0; cidr.u.in.mask = 0; net = &value[0]; @@ -940,20 +1056,29 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht return NGX_CONF_ERROR; } - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"geo\" supports IPv4 only"); - return NGX_CONF_ERROR; + if (cidr.family == AF_INET) { + cidr.u.in.addr = ntohl(cidr.u.in.addr); + cidr.u.in.mask = ntohl(cidr.u.in.mask); } - cidr.u.in.addr = ntohl(cidr.u.in.addr); - cidr.u.in.mask = ntohl(cidr.u.in.mask); + if (del) { + switch (cidr.family) { - if (del) { - if (ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, - cidr.u.in.mask) - != NGX_OK) - { +#if (NGX_HAVE_INET6) + case AF_INET6: + rc = ngx_radix128tree_delete(ctx->tree6, + cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr); + break; +#endif + + default: /* AF_INET */ + rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, + cidr.u.in.mask); + break; + } + + if (rc != NGX_OK) { ngx_conf_log_error(NGX_LOG_WARN, cf, 0, "no network \"%V\" to delete", net); } @@ -968,32 +1093,78 @@ ngx_http_geo_cidr(ngx_conf_t *cf, ngx_ht return NGX_CONF_ERROR; } - for (i = 2; i; i--) { - rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, cidr.u.in.mask, - (uintptr_t) val); - if (rc == NGX_OK) { - return NGX_CONF_OK; - } + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + for (i = 2; i; i--) { + rc = ngx_radix128tree_insert(ctx->tree6, cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr, + (uintptr_t) val); + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } - if (rc == NGX_ERROR) { - return NGX_CONF_ERROR; + /* rc == NGX_BUSY */ + + old = (ngx_http_variable_value_t *) + ngx_radix128tree_find(ctx->tree6, + cidr.u.in6.addr.s6_addr); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", + net, val, old); + + rc = ngx_radix128tree_delete(ctx->tree6, + cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); + return NGX_CONF_ERROR; + } } - /* rc == NGX_BUSY */ + break; +#endif + + default: /* AF_INET */ + for (i = 2; i; i--) { + rc = ngx_radix32tree_insert(ctx->tree, cidr.u.in.addr, + cidr.u.in.mask, (uintptr_t) val); - old = (ngx_http_variable_value_t *) - ngx_radix32tree_find(ctx->tree, cidr.u.in.addr & cidr.u.in.mask); + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", - net, val, old); + old = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ctx->tree, cidr.u.in.addr); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate network \"%V\", value: \"%v\", old value: \"%v\"", + net, val, old); - rc = ngx_radix32tree_delete(ctx->tree, cidr.u.in.addr, cidr.u.in.mask); + rc = ngx_radix32tree_delete(ctx->tree, + cidr.u.in.addr, cidr.u.in.mask); - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); - return NGX_CONF_ERROR; + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid radix tree"); + return NGX_CONF_ERROR; + } } + + break; } return NGX_CONF_ERROR; 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 @@ -321,7 +321,7 @@ ngx_http_gzip_body_filter(ngx_http_reque ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); - if (ctx == NULL || ctx->done) { + if (ctx == NULL || ctx->done || r->header_only) { return ngx_http_next_body_filter(r, in); } @@ -498,6 +498,10 @@ ngx_http_gzip_filter_memory(ngx_http_req wbits--; memlevel--; } + + if (memlevel < 1) { + memlevel = 1; + } } ctx->wbits = wbits; 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 @@ -74,7 +74,9 @@ static ngx_http_set_header_t ngx_http_s { ngx_string("Cache-Control"), 0, ngx_http_add_cache_control }, - { ngx_string("Last-Modified"), 0, ngx_http_set_last_modified }, + { ngx_string("Last-Modified"), + offsetof(ngx_http_headers_out_t, last_modified), + ngx_http_set_last_modified }, { ngx_string("ETag"), offsetof(ngx_http_headers_out_t, etag), @@ -153,6 +155,7 @@ ngx_http_headers_filter(ngx_http_request if ((conf->expires == NGX_HTTP_EXPIRES_OFF && conf->headers == NULL) || r != r->main || (r->headers_out.status != NGX_HTTP_OK + && r->headers_out.status != NGX_HTTP_CREATED && r->headers_out.status != NGX_HTTP_NO_CONTENT && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY @@ -372,27 +375,12 @@ static ngx_int_t ngx_http_set_last_modified(ngx_http_request_t *r, ngx_http_header_val_t *hv, ngx_str_t *value) { - ngx_table_elt_t *h; - - ngx_http_clear_last_modified(r); - - if (value->len == 0) { - return NGX_OK; - } - - r->headers_out.last_modified_time = ngx_http_parse_time(value->data, - value->len); - - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { + if (ngx_http_set_response_header(r, hv, value) != NGX_OK) { return NGX_ERROR; } - r->headers_out.last_modified = h; - - h->hash = 1; - h->key = hv->key; - h->value = *value; + r->headers_out.last_modified_time = + (value->len) ? ngx_http_parse_time(value->data, value->len) : -1; return NGX_OK; } @@ -406,22 +394,27 @@ ngx_http_set_response_header(ngx_http_re old = (ngx_table_elt_t **) ((char *) &r->headers_out + hv->offset); - if (*old) { - (*old)->hash = 0; - *old = NULL; - } + if (value->len == 0) { + if (*old) { + (*old)->hash = 0; + *old = NULL; + } - if (value->len == 0) { return NGX_OK; } - h = ngx_list_push(&r->headers_out.headers); - if (h == NULL) { - return NGX_ERROR; + if (*old) { + h = *old; + + } else { + h = ngx_list_push(&r->headers_out.headers); + if (h == NULL) { + return NGX_ERROR; + } + + *old = h; } - *old = h; - h->hash = 1; h->key = hv->key; h->value = *value; diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c --- a/src/http/modules/ngx_http_image_filter_module.c +++ b/src/http/modules/ngx_http_image_filter_module.c @@ -1169,10 +1169,22 @@ ngx_http_image_filter_create_conf(ngx_co return NULL; } + /* + * set by ngx_pcalloc(): + * + * conf->width = 0; + * conf->height = 0; + * conf->angle = 0; + * conf->wcv = NULL; + * conf->hcv = NULL; + * conf->acv = NULL; + * conf->jqcv = NULL; + * conf->shcv = NULL; + */ + conf->filter = NGX_CONF_UNSET_UINT; conf->jpeg_quality = NGX_CONF_UNSET_UINT; conf->sharpen = NGX_CONF_UNSET_UINT; - conf->angle = NGX_CONF_UNSET_UINT; conf->transparency = NGX_CONF_UNSET; conf->buffer_size = NGX_CONF_UNSET_SIZE; @@ -1195,27 +1207,29 @@ ngx_http_image_filter_merge_conf(ngx_con conf->filter = prev->filter; conf->width = prev->width; conf->height = prev->height; + conf->angle = prev->angle; conf->wcv = prev->wcv; conf->hcv = prev->hcv; + conf->acv = prev->acv; } } - /* 75 is libjpeg default quality */ - ngx_conf_merge_uint_value(conf->jpeg_quality, prev->jpeg_quality, 75); + if (conf->jpeg_quality == NGX_CONF_UNSET_UINT) { - if (conf->jqcv == NULL) { - conf->jqcv = prev->jqcv; + /* 75 is libjpeg default quality */ + ngx_conf_merge_uint_value(conf->jpeg_quality, prev->jpeg_quality, 75); + + if (conf->jqcv == NULL) { + conf->jqcv = prev->jqcv; + } } - ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0); + if (conf->sharpen == NGX_CONF_UNSET_UINT) { + ngx_conf_merge_uint_value(conf->sharpen, prev->sharpen, 0); - if (conf->shcv == NULL) { - conf->shcv = prev->shcv; - } - - ngx_conf_merge_uint_value(conf->angle, prev->angle, 0); - if (conf->acv == NULL) { - conf->acv = prev->acv; + if (conf->shcv == NULL) { + conf->shcv = prev->shcv; + } } ngx_conf_merge_value(conf->transparency, prev->transparency, 1); 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 @@ -9,6 +9,10 @@ #include #include +#if (NGX_ZLIB) +#include +#endif + typedef struct ngx_http_log_op_s ngx_http_log_op_t; @@ -41,6 +45,17 @@ typedef struct { typedef struct { + u_char *start; + u_char *pos; + u_char *last; + + ngx_event_t *event; + ngx_msec_t flush; + ngx_int_t gzip; +} ngx_http_log_buf_t; + + +typedef struct { ngx_array_t *lengths; ngx_array_t *values; } ngx_http_log_script_t; @@ -78,6 +93,17 @@ static void ngx_http_log_write(ngx_http_ static ssize_t ngx_http_log_script_write(ngx_http_request_t *r, ngx_http_log_script_t *script, u_char **name, u_char *buf, size_t len); +#if (NGX_ZLIB) +static ssize_t ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, + ngx_int_t level, ngx_log_t *log); + +static void *ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size); +static void ngx_http_log_gzip_free(void *opaque, void *address); +#endif + +static void ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log); +static void ngx_http_log_flush_handler(ngx_event_t *ev); + static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, @@ -132,7 +158,7 @@ static ngx_command_t ngx_http_log_comma { ngx_string("access_log"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF - |NGX_HTTP_LMT_CONF|NGX_CONF_TAKE123, + |NGX_HTTP_LMT_CONF|NGX_CONF_1MORE, ngx_http_log_set_log, NGX_HTTP_LOC_CONF_OFFSET, 0, @@ -216,8 +242,8 @@ ngx_http_log_handler(ngx_http_request_t size_t len; ngx_uint_t i, l; ngx_http_log_t *log; - ngx_open_file_t *file; ngx_http_log_op_t *op; + ngx_http_log_buf_t *buffer; ngx_http_log_loc_conf_t *lcf; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -258,21 +284,25 @@ ngx_http_log_handler(ngx_http_request_t len += NGX_LINEFEED_SIZE; - file = log[l].file; + buffer = log[l].file ? log[l].file->data : NULL; - if (file && file->buffer) { + if (buffer) { - if (len > (size_t) (file->last - file->pos)) { + if (len > (size_t) (buffer->last - buffer->pos)) { - ngx_http_log_write(r, &log[l], file->buffer, - file->pos - file->buffer); + ngx_http_log_write(r, &log[l], buffer->start, + buffer->pos - buffer->start); - file->pos = file->buffer; + buffer->pos = buffer->start; } - if (len <= (size_t) (file->last - file->pos)) { + if (len <= (size_t) (buffer->last - buffer->pos)) { + + p = buffer->pos; - p = file->pos; + if (buffer->event && p == buffer->start) { + ngx_add_timer(buffer->event, buffer->flush); + } for (i = 0; i < log[l].format->ops->nelts; i++) { p = op[i].run(r, p, &op[i]); @@ -280,10 +310,14 @@ ngx_http_log_handler(ngx_http_request_t ngx_linefeed(p); - file->pos = p; + buffer->pos = p; continue; } + + if (buffer->event && buffer->event->timer_set) { + ngx_del_timer(buffer->event); + } } line = ngx_pnalloc(r->pool, len); @@ -310,14 +344,29 @@ static void ngx_http_log_write(ngx_http_request_t *r, ngx_http_log_t *log, u_char *buf, size_t len) { - u_char *name; - time_t now; - ssize_t n; - ngx_err_t err; + u_char *name; + time_t now; + ssize_t n; + ngx_err_t err; +#if (NGX_ZLIB) + ngx_http_log_buf_t *buffer; +#endif if (log->script == NULL) { name = log->file->name.data; + +#if (NGX_ZLIB) + buffer = log->file->data; + + if (buffer && buffer->gzip) { + n = ngx_http_log_gzip(log->file->fd, buf, len, buffer->gzip, + r->connection->log); + } else { + n = ngx_write_fd(log->file->fd, buf, len); + } +#else n = ngx_write_fd(log->file->fd, buf, len); +#endif } else { name = NULL; @@ -465,6 +514,194 @@ ngx_http_log_script_write(ngx_http_reque } +#if (NGX_ZLIB) + +static ssize_t +ngx_http_log_gzip(ngx_fd_t fd, u_char *buf, size_t len, ngx_int_t level, + ngx_log_t *log) +{ + int rc, wbits, memlevel; + u_char *out; + size_t size; + ssize_t n; + z_stream zstream; + ngx_err_t err; + ngx_pool_t *pool; + + wbits = MAX_WBITS; + memlevel = MAX_MEM_LEVEL - 1; + + while ((ssize_t) len < ((1 << (wbits - 1)) - 262)) { + wbits--; + memlevel--; + } + + /* + * This is a formula from deflateBound() for conservative upper bound of + * compressed data plus 18 bytes of gzip wrapper. + */ + + size = len + ((len + 7) >> 3) + ((len + 63) >> 6) + 5 + 18; + + ngx_memzero(&zstream, sizeof(z_stream)); + + pool = ngx_create_pool(256, log); + if (pool == NULL) { + /* simulate successful logging */ + return len; + } + + pool->log = log; + + zstream.zalloc = ngx_http_log_gzip_alloc; + zstream.zfree = ngx_http_log_gzip_free; + zstream.opaque = pool; + + out = ngx_pnalloc(pool, size); + if (out == NULL) { + goto done; + } + + zstream.next_in = buf; + zstream.avail_in = len; + zstream.next_out = out; + zstream.avail_out = size; + + rc = deflateInit2(&zstream, (int) level, Z_DEFLATED, wbits + 16, memlevel, + Z_DEFAULT_STRATEGY); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateInit2() failed: %d", rc); + goto done; + } + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, log, 0, + "deflate in: ni:%p no:%p ai:%ud ao:%ud", + zstream.next_in, zstream.next_out, + zstream.avail_in, zstream.avail_out); + + rc = deflate(&zstream, Z_FINISH); + + if (rc != Z_STREAM_END) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "deflate(Z_FINISH) failed: %d", rc); + goto done; + } + + ngx_log_debug5(NGX_LOG_DEBUG_HTTP, log, 0, + "deflate out: ni:%p no:%p ai:%ud ao:%ud rc:%d", + zstream.next_in, zstream.next_out, + zstream.avail_in, zstream.avail_out, + rc); + + size -= zstream.avail_out; + + rc = deflateEnd(&zstream); + + if (rc != Z_OK) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "deflateEnd() failed: %d", rc); + goto done; + } + + n = ngx_write_fd(fd, out, size); + + if (n != (ssize_t) size) { + err = (n == -1) ? ngx_errno : 0; + + ngx_destroy_pool(pool); + + ngx_set_errno(err); + return -1; + } + +done: + + ngx_destroy_pool(pool); + + /* simulate successful logging */ + return len; +} + + +static void * +ngx_http_log_gzip_alloc(void *opaque, u_int items, u_int size) +{ + ngx_pool_t *pool = opaque; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pool->log, 0, + "gzip alloc: n:%ud s:%ud", items, size); + + return ngx_palloc(pool, items * size); +} + + +static void +ngx_http_log_gzip_free(void *opaque, void *address) +{ +#if 0 + ngx_pool_t *pool = opaque; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pool->log, 0, "gzip free: %p", address); +#endif +} + +#endif + + +static void +ngx_http_log_flush(ngx_open_file_t *file, ngx_log_t *log) +{ + size_t len; + ssize_t n; + ngx_http_log_buf_t *buffer; + + buffer = file->data; + + len = buffer->pos - buffer->start; + + if (len == 0) { + return; + } + +#if (NGX_ZLIB) + if (buffer->gzip) { + n = ngx_http_log_gzip(file->fd, buffer->start, len, buffer->gzip, log); + } else { + n = ngx_write_fd(file->fd, buffer->start, len); + } +#else + n = ngx_write_fd(file->fd, buffer->start, len); +#endif + + if (n == -1) { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + ngx_write_fd_n " to \"%s\" failed", + file->name.data); + + } else if ((size_t) n != len) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz", + file->name.data, n, len); + } + + buffer->pos = buffer->start; + + if (buffer->event && buffer->event->timer_set) { + ngx_del_timer(buffer->event); + } +} + + +static void +ngx_http_log_flush_handler(ngx_event_t *ev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, ev->log, 0, + "http log buffer flush handler"); + + ngx_http_log_flush(ev->data, ev->log); +} + + static u_char * ngx_http_log_copy_short(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) @@ -848,10 +1085,13 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx { ngx_http_log_loc_conf_t *llcf = conf; - ssize_t buf; + ssize_t size; + ngx_int_t gzip; ngx_uint_t i, n; - ngx_str_t *value, name; + ngx_msec_t flush; + ngx_str_t *value, name, s; ngx_http_log_t *log; + ngx_http_log_buf_t *buffer; ngx_http_log_fmt_t *fmt; ngx_http_log_main_conf_t *lmcf; ngx_http_script_compile_t sc; @@ -936,54 +1176,152 @@ ngx_http_log_set_log(ngx_conf_t *cf, ngx && ngx_strcasecmp(fmt[i].name.data, name.data) == 0) { log->format = &fmt[i]; - goto buffer; + break; } } - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "unknown log format \"%V\"", &name); - return NGX_CONF_ERROR; + if (log->format == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "unknown log format \"%V\"", &name); + return NGX_CONF_ERROR; + } + + size = 0; + flush = 0; + gzip = 0; + + for (i = 3; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "buffer=", 7) == 0) { + s.len = value[i].len - 7; + s.data = value[i].data + 7; + + size = ngx_parse_size(&s); -buffer: + if (size == NGX_ERROR || size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid buffer size \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "flush=", 6) == 0) { + s.len = value[i].len - 6; + s.data = value[i].data + 6; + + flush = ngx_parse_time(&s, 0); + + if (flush == (ngx_msec_t) NGX_ERROR || flush == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid flush time \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + } - if (cf->args->nelts == 4) { - if (ngx_strncmp(value[3].data, "buffer=", 7) != 0) { + if (ngx_strncmp(value[i].data, "gzip", 4) == 0 + && (value[i].len == 4 || value[i].data[4] == '=')) + { +#if (NGX_ZLIB) + if (size == 0) { + size = 64 * 1024; + } + + if (value[i].len == 4) { + gzip = Z_BEST_SPEED; + continue; + } + + s.len = value[i].len - 5; + s.data = value[i].data + 5; + + gzip = ngx_atoi(s.data, s.len); + + if (gzip < 1 || gzip > 9) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid compression level \"%V\"", &s); + return NGX_CONF_ERROR; + } + + continue; + +#else ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid parameter \"%V\"", &value[3]); + "nginx was built without zlib support"); return NGX_CONF_ERROR; +#endif } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (flush && size == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no buffer is defined for access_log \"%V\"", + &value[1]); + return NGX_CONF_ERROR; + } + + if (size) { + if (log->script) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "buffered logs cannot have variables in name"); return NGX_CONF_ERROR; } - name.len = value[3].len - 7; - name.data = value[3].data + 7; + if (log->file->data) { + buffer = log->file->data; - buf = ngx_parse_size(&name); + if (buffer->last - buffer->start != size + || buffer->flush != flush + || buffer->gzip != gzip) + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "access_log \"%V\" already defined " + "with conflicting parameters", + &value[1]); + return NGX_CONF_ERROR; + } - if (buf == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid buffer value \"%V\"", &name); + return NGX_CONF_OK; + } + + buffer = ngx_pcalloc(cf->pool, sizeof(ngx_http_log_buf_t)); + if (buffer == NULL) { return NGX_CONF_ERROR; } - if (log->file->buffer && log->file->last - log->file->pos != buf) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "access_log \"%V\" already defined " - "with different buffer size", &value[1]); + buffer->start = ngx_pnalloc(cf->pool, size); + if (buffer->start == NULL) { return NGX_CONF_ERROR; } - log->file->buffer = ngx_palloc(cf->pool, buf); - if (log->file->buffer == NULL) { - return NGX_CONF_ERROR; + buffer->pos = buffer->start; + buffer->last = buffer->start + size; + + if (flush) { + buffer->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t)); + if (buffer->event == NULL) { + return NGX_CONF_ERROR; + } + + buffer->event->data = log->file; + buffer->event->handler = ngx_http_log_flush_handler; + buffer->event->log = &cf->cycle->new_log; + + buffer->flush = flush; } - log->file->pos = log->file->buffer; - log->file->last = log->file->buffer + buf; + buffer->gzip = gzip; + + log->file->flush = ngx_http_log_flush; + log->file->data = buffer; } return NGX_CONF_OK; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -209,6 +209,13 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c } name = value[2]; + + if (name.data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &name); + return NGX_CONF_ERROR; + } + name.len--; name.data++; 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 @@ -837,7 +837,7 @@ ngx_http_proxy_create_key(ngx_http_reque return NGX_ERROR; } - if (plcf->cache_key.value.len) { + if (plcf->cache_key.value.data) { if (ngx_http_complex_value(r, &plcf->cache_key, key) != NGX_OK) { return NGX_ERROR; @@ -1614,7 +1614,8 @@ ngx_http_proxy_copy_filter(ngx_event_pip p->upstream_done = 1; ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, - "upstream sent too much data"); + "upstream sent more data than specified in " + "\"Content-Length\" header"); } return NGX_OK; @@ -3651,7 +3652,7 @@ ngx_http_proxy_cache_key(ngx_conf_t *cf, value = cf->args->elts; - if (plcf->cache_key.value.len) { + if (plcf->cache_key.value.data) { return "is duplicate"; } diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- a/src/http/modules/ngx_http_scgi_module.c +++ b/src/http/modules/ngx_http_scgi_module.c @@ -1771,7 +1771,7 @@ ngx_http_scgi_cache_key(ngx_conf_t *cf, value = cf->args->elts; - if (scf->cache_key.value.len) { + if (scf->cache_key.value.data) { return "is duplicate"; } diff --git a/src/http/modules/ngx_http_split_clients_module.c b/src/http/modules/ngx_http_split_clients_module.c --- a/src/http/modules/ngx_http_split_clients_module.c +++ b/src/http/modules/ngx_http_split_clients_module.c @@ -139,7 +139,7 @@ ngx_conf_split_clients_block(ngx_conf_t name = value[2]; - if (name.len < 2 || name.data[0] != '$') { + if (name.data[0] != '$') { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid variable name \"%V\"", &name); return NGX_CONF_ERROR; diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -628,7 +628,7 @@ ngx_http_sub_filter(ngx_conf_t *cf, ngx_ ngx_str_t *value; ngx_http_compile_complex_value_t ccv; - if (slcf->match.len) { + if (slcf->match.data) { return "is duplicate"; } @@ -688,7 +688,7 @@ ngx_http_sub_merge_conf(ngx_conf_t *cf, ngx_conf_merge_value(conf->once, prev->once, 1); ngx_conf_merge_str_value(conf->match, prev->match, ""); - if (conf->value.value.len == 0) { + if (conf->value.value.data == NULL) { conf->value = prev->value; } diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c --- a/src/http/modules/ngx_http_upstream_least_conn_module.c +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c @@ -313,7 +313,9 @@ failed: lcp->rrp.peers = peers->next; pc->tries = lcp->rrp.peers->number; - n = lcp->rrp.peers->number / (8 * sizeof(uintptr_t)) + 1; + n = (lcp->rrp.peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + for (i = 0; i < n; i++) { lcp->rrp.tried[i] = 0; } diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -1807,7 +1807,7 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, value = cf->args->elts; - if (uwcf->cache_key.value.len) { + if (uwcf->cache_key.value.data) { return "is duplicate"; } diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -307,7 +307,7 @@ ngx_http_xslt_send(ngx_http_request_t *r ctx->done = 1; if (b == NULL) { - return ngx_http_filter_finalize_request(r, NULL, + return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module, NGX_HTTP_INTERNAL_SERVER_ERROR); } @@ -315,7 +315,7 @@ ngx_http_xslt_send(ngx_http_request_t *r if (cln == NULL) { ngx_free(b->pos); - return ngx_http_filter_finalize_request(r, NULL, + return ngx_http_filter_finalize_request(r, &ngx_http_xslt_filter_module, NGX_HTTP_INTERNAL_SERVER_ERROR); } 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 @@ -16,20 +16,9 @@ WriteMakefile( CCFLAGS => "$ENV{NGX_PM_CFLAGS}", OPTIMIZE => '-O', - INC => "-I ../../../../../src/core " . - "-I ../../../../../src/event " . - "-I ../../../../../src/os/unix " . - "-I ../../../../../src/http " . - "-I ../../../../../src/http/modules " . - "-I ../../../../../src/http/modules/perl " . - "-I ../../../../../$ENV{NGX_OBJS} " . - ($ENV{NGX_PCRE} =~ /^(YES|NO)/ ? "" : - ($ENV{NGX_PCRE} =~ m#^/# ? "-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 ")), + INC => join(" ", map { + m#^/# ? "-I $_" : "-I ../../../../../$_" + } (split /\s+/, $ENV{NGX_INCS})), 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 @@ -50,7 +50,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.3.9'; +our $VERSION = '1.3.10'; require XSLoader; XSLoader::load('nginx', $VERSION); @@ -123,7 +123,7 @@ This module provides a Perl interface to =head1 SEE ALSO -http://sysoev.ru/nginx/docs/http/ngx_http_perl_module.html +http://nginx.org/en/docs/http/ngx_http_perl_module.html =head1 AUTHOR 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 @@ -1001,6 +1001,7 @@ ngx_http_core_find_config_phase(ngx_http "client intended to send too large body: %O bytes", r->headers_in.content_length_n); + r->expect_tested = 1; (void) ngx_http_discard_request_body(r); ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE); return NGX_OK; @@ -4593,7 +4594,7 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_str_null(&args); - if (cv.lengths == NULL && uri.data[0] == '/') { + if (cv.lengths == NULL && uri.len && uri.data[0] == '/') { p = (u_char *) ngx_strchr(uri.data, '?'); if (p) { 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 @@ -114,11 +114,6 @@ ngx_http_compile_complex_value(ngx_http_ v = ccv->value; - if (v->len == 0) { - ngx_conf_log_error(NGX_LOG_EMERG, ccv->cf, 0, "empty parameter"); - return NGX_ERROR; - } - nv = 0; nc = 0; @@ -133,8 +128,9 @@ ngx_http_compile_complex_value(ngx_http_ } } - if (v->data[0] != '$' && (ccv->conf_prefix || ccv->root_prefix)) { - + if ((v->len == 0 || v->data[0] != '$') + && (ccv->conf_prefix || ccv->root_prefix)) + { if (ngx_conf_full_name(ccv->cf->cycle, v, ccv->conf_prefix) != NGX_OK) { return NGX_ERROR; } 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 @@ -636,6 +636,14 @@ ngx_http_upstream_init_request(ngx_http_ found: + if (uscf == NULL) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "no upstream configuration"); + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + if (uscf->peer.init(r, uscf) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); @@ -3091,6 +3099,7 @@ ngx_http_upstream_finalize_request(ngx_h r->connection->log->action = "sending to client"; if (rc == 0 + && !r->header_only #if (NGX_HTTP_CACHE) && !r->cached #endif diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -474,7 +474,9 @@ failed: rrp->peers = peers->next; pc->tries = rrp->peers->number; - n = rrp->peers->number / (8 * sizeof(uintptr_t)) + 1; + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + for (i = 0; i < n; i++) { rrp->tried[i] = 0; } 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 @@ -330,6 +330,12 @@ ngx_http_add_variable(ngx_conf_t *cf, ng ngx_http_variable_t *v; ngx_http_core_main_conf_t *cmcf; + if (name->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"$\""); + return NULL; + } + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); key = cmcf->variables_keys->keys.elts; @@ -393,6 +399,12 @@ ngx_http_get_variable_index(ngx_conf_t * ngx_http_variable_t *v; ngx_http_core_main_conf_t *cmcf; + if (name->len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"$\""); + return NGX_ERROR; + } + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); v = cmcf->variables.elts; diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -207,7 +207,7 @@ ngx_http_write_filter(ngx_http_request_t } if (r->limit_rate) { - limit = r->limit_rate * (ngx_time() - r->start_sec + 1) + limit = (off_t) r->limit_rate * (ngx_time() - r->start_sec + 1) - (c->sent - clcf->limit_rate_after); if (limit <= 0) { diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c --- a/src/mail/ngx_mail_auth_http_module.c +++ b/src/mail/ngx_mail_auth_http_module.c @@ -1388,7 +1388,6 @@ ngx_mail_auth_http(ngx_conf_t *cf, ngx_c u.url = value[1]; u.default_port = 80; u.uri_part = 1; - u.one_addr = 1; if (ngx_strncmp(u.url.data, "http://", 7) == 0) { u.url.len -= 7; diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -363,7 +363,7 @@ ngx_open_glob(ngx_glob_t *gl) { int n; - n = glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob); + n = glob((char *) gl->pattern, 0, NULL, &gl->pglob); if (n == 0) { return NGX_OK; 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 @@ -28,30 +28,27 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char { char *value; size_t len; - ngx_err_t err; struct crypt_data cd; - ngx_set_errno(0); - cd.initialized = 0; /* work around the glibc bug */ cd.current_salt[0] = ~salt[0]; value = crypt_r((char *) key, (char *) salt, &cd); - err = ngx_errno; - - if (err == 0) { + if (value) { len = ngx_strlen(value) + 1; *encrypted = ngx_pnalloc(pool, len); - if (*encrypted) { - ngx_memcpy(*encrypted, value, len); - return NGX_OK; + if (*encrypted == NULL) { + return NGX_ERROR; } + + ngx_memcpy(*encrypted, value, len); + return NGX_OK; } - ngx_log_error(NGX_LOG_CRIT, pool->log, err, "crypt_r() failed"); + ngx_log_error(NGX_LOG_CRIT, pool->log, ngx_errno, "crypt_r() failed"); return NGX_ERROR; } @@ -75,18 +72,20 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char #endif - ngx_set_errno(0); - value = crypt((char *) key, (char *) salt); if (value) { len = ngx_strlen(value) + 1; *encrypted = ngx_pnalloc(pool, len); - if (*encrypted) { - ngx_memcpy(*encrypted, value, len); + if (*encrypted == NULL) { +#if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) + ngx_mutex_unlock(ngx_crypt_mutex); +#endif + return NGX_ERROR; } + ngx_memcpy(*encrypted, value, len); #if (NGX_THREADS && NGX_NONREENTRANT_CRYPT) ngx_mutex_unlock(ngx_crypt_mutex); #endif