# HG changeset patch # User Igor Sysoev # Date 1257195600 -10800 # Node ID c04fa65fe604240cbf3b29f4dddfc7683514fa5a # Parent c88014f7483250ce1e3e93f0a179a21c719198d2 nginx 0.8.22 *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" directives. *) Feature: the "access" and the "deny" directives support IPv6. *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in request headers. *) Feature: the "unix:" parameter of the "set_real_ip_from" directive. *) Bugfix: nginx did not delete unix domain socket after configuration testing. *) Bugfix: nginx deleted unix domain socket while online upgrade. *) Bugfix: the "!-x" operator did not work. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process, if limit_rate was used in HTTPS server. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process while $limit_rate logging. Thanks to Maxim Dounin. *) Bugfix: a segmentation fault might occur in a worker process, if there was no "listen" directive in "server" block; the bug had appeared in 0.8.21. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,37 @@ +Changes with nginx 0.8.22 03 Nov 2009 + + *) Feature: the "proxy_bind", "fastcgi_bind", and "memcached_bind" + directives. + + *) Feature: the "access" and the "deny" directives support IPv6. + + *) Feature: the "set_real_ip_from" directive supports IPv6 addresses in + request headers. + + *) Feature: the "unix:" parameter of the "set_real_ip_from" directive. + + *) Bugfix: nginx did not delete unix domain socket after configuration + testing. + + *) Bugfix: nginx deleted unix domain socket while online upgrade. + + *) Bugfix: the "!-x" operator did not work. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process, if + limit_rate was used in HTTPS server. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process while + $limit_rate logging. + Thanks to Maxim Dounin. + + *) Bugfix: a segmentation fault might occur in a worker process, if + there was no "listen" directive in "server" block; the bug had + appeared in 0.8.21. + + Changes with nginx 0.8.21 26 Oct 2009 *) Feature: now the "-V" switch shows TLS SNI support. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,37 @@ +Изменения в nginx 0.8.22 03.11.2009 + + *) Добавление: директивы proxy_bind, fastcgi_bind и memcached_bind. + + *) Добавление: директивы access и deny поддерживают IPv6. + + *) Добавление: директива set_real_ip_from поддерживает IPv6 адреса в + заголовках запроса. + + *) Добавление: параметр "unix:" в директиве set_real_ip_from. + + *) Исправление: nginx не удалял unix domain сокет после тестирования + конфигурации. + + *) Исправление: nginx удалял unix domain сокет во время обновления без + перерыва. + + *) Исправление: оператор "!-x" не работал. + Спасибо Максиму Дунину. + + *) Исправление: в рабочем процессе мог произойти segmentation fault при + использовании limit_rate в HTTPS сервере. + Спасибо Максиму Дунину. + + *) Исправление: при записи в лог переменной $limit_rate в рабочем + процессе происходил segmentation fault. + Спасибо Максиму Дунину. + + *) Исправление: в рабочем процессе мог произойти segmentation fault, + если внутри блока server не было директивы listen; ошибка появилась + в 0.8.21. + + Изменения в nginx 0.8.21 26.10.2009 *) Добавление: теперь ключ -V показывает статус поддержки TLS SNI. diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -144,19 +144,4 @@ upgrade: test -f $NGX_PID_PATH.oldbin kill -QUIT \`cat $NGX_PID_PATH.oldbin\` - -upgrade1: - # upgrade 0.1.x to 0.2+ - - $NGX_SBIN_PATH -t - - cp $NGX_PID_PATH $NGX_PID_PATH.oldbin - - kill -USR2 \`cat $NGX_PID_PATH\` - sleep 1 - test -f $NGX_PID_PATH.oldbin - - cp $NGX_PID_PATH $NGX_PID_PATH.newbin - - kill -QUIT \`cat $NGX_PID_PATH.oldbin\` END diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -35,6 +35,12 @@ then fi +# posix_fadvise64() had been implemented in 2.5.60 + +if [ $version -lt 132412 ]; then + have=NGX_HAVE_POSIX_FADVISE . auto/nohave +fi + # epoll, EPOLLET version ngx_feature="epoll" diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 8021 -#define NGINX_VERSION "0.8.21" +#define nginx_version 8022 +#define NGINX_VERSION "0.8.22" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -365,6 +365,18 @@ ngx_open_listening_sockets(ngx_cycle_t * continue; } +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_test_config && ls[i].sockaddr->sa_family == AF_UNIX) { + u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; + + if (ngx_delete_file(name) == -1) { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + ngx_delete_file_n " %s failed", name); + } + } +#endif + if (listen(s, ls[i].backlog) == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, "listen() to %V, backlog %d failed", @@ -615,7 +627,8 @@ ngx_close_listening_sockets(ngx_cycle_t #if (NGX_HAVE_UNIX_DOMAIN) if (ls[i].sockaddr->sa_family == AF_UNIX - && ngx_process != NGX_PROCESS_WORKER) + && ngx_process != NGX_PROCESS_WORKER + && ngx_new_binary == 0) { u_char *name = ls[i].addr_text.data + sizeof("unix:") - 1; @@ -881,7 +894,6 @@ ngx_connection_local_sockaddr(ngx_connec return NGX_ERROR; } - c->local_socklen = len; ngx_memcpy(c->local_sockaddr, &sa, len); } diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -129,7 +129,6 @@ struct ngx_connection_s { #endif struct sockaddr *local_sockaddr; - socklen_t local_socklen; ngx_buf_t *buffer; 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 @@ -8,9 +8,6 @@ #include -#if (NGX_HAVE_INET6) -static size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); -#endif static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u); @@ -59,6 +56,126 @@ ngx_inet_addr(u_char *text, size_t len) } +#if (NGX_HAVE_INET6) + +ngx_int_t +ngx_inet6_addr(u_char *p, size_t len, u_char *addr) +{ + u_char c, *zero, *digit, *s, *d; + size_t len4; + ngx_uint_t n, nibbles, word; + + if (len == 0) { + return NGX_ERROR; + } + + zero = NULL; + digit = NULL; + len4 = 0; + nibbles = 0; + word = 0; + n = 8; + + if (p[0] == ':') { + p++; + len--; + } + + for (/* void */; len; len--) { + c = *p++; + + if (c == ':') { + if (nibbles) { + digit = p; + len4 = len; + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + nibbles = 0; + word = 0; + continue; + } + + } else { + if (zero == NULL) { + digit = p; + len4 = len; + zero = addr; + continue; + } + } + + return NGX_ERROR; + } + + if (c == '.' && nibbles) { + if (n < 2) { + return NGX_ERROR; + } + + word = ngx_inet_addr(digit, len4 - 1); + if (word == INADDR_NONE) { + return NGX_ERROR; + } + + word = ntohl(word); + *addr++ = (u_char) ((word >> 24) & 0xff); + *addr++ = (u_char) ((word >> 16) & 0xff); + n--; + break; + } + + if (++nibbles > 4) { + return NGX_ERROR; + } + + if (c >= '0' && c <= '9') { + word = word * 16 + (c - '0'); + continue; + } + + c |= 0x20; + + if (c >= 'a' && c <= 'f') { + word = word * 16 + (c - 'a') + 10; + continue; + } + + return NGX_ERROR; + } + + if (nibbles == 0 && zero == NULL) { + return NGX_ERROR; + } + + *addr++ = (u_char) (word >> 8); + *addr++ = (u_char) (word & 0xff); + + if (--n) { + if (zero) { + n *= 2; + s = addr - 1; + d = s + n; + while (s >= zero) { + *d-- = *s--; + } + ngx_memzero(zero, n); + return NGX_OK; + } + + } else { + if (zero == NULL) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + +#endif + + size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port) { @@ -101,7 +218,7 @@ ngx_sock_ntop(struct sockaddr *sa, u_cha text[n++] = '['; } - n = ngx_inet6_ntop((u_char *) &sin6->sin6_addr, &text[n], len); + n = ngx_inet6_ntop(sin6->sin6_addr.s6_addr, &text[n], len); if (port) { n = ngx_sprintf(&text[1 + n], "]:%d", @@ -158,7 +275,7 @@ ngx_inet_ntop(int family, void *addr, u_ #if (NGX_HAVE_INET6) -static size_t +size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len) { u_char *dst; @@ -237,31 +354,47 @@ ngx_inet6_ntop(u_char *p, u_char *text, #endif -/* AF_INET only */ - ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr) { - u_char *addr, *mask, *last; - ngx_int_t shift; + u_char *addr, *mask, *last; + size_t len; + ngx_int_t shift; +#if (NGX_HAVE_INET6) + ngx_int_t rc; + ngx_uint_t s, i; +#endif addr = text->data; last = addr + text->len; mask = ngx_strlchr(addr, last, '/'); + len = (mask ? mask : last) - addr; - cidr->u.in.addr = ngx_inet_addr(addr, (mask ? mask : last) - addr); + cidr->u.in.addr = ngx_inet_addr(addr, len); + + if (cidr->u.in.addr != INADDR_NONE) { + cidr->family = AF_INET; + + if (mask == NULL) { + cidr->u.in.mask = 0xffffffff; + return NGX_OK; + } - if (cidr->u.in.addr == INADDR_NONE) { +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(addr, len, cidr->u.in6.addr.s6_addr) == NGX_OK) { + cidr->family = AF_INET6; + + if (mask == NULL) { + ngx_memset(cidr->u.in6.mask.s6_addr, 0xff, 16); + return NGX_OK; + } + +#endif + } else { return NGX_ERROR; } - if (mask == NULL) { - cidr->family = AF_INET; - cidr->u.in.mask = 0xffffffff; - return NGX_OK; - } - mask++; shift = ngx_atoi(mask, last - mask); @@ -269,30 +402,108 @@ ngx_ptocidr(ngx_str_t *text, ngx_cidr_t return NGX_ERROR; } - cidr->family = AF_INET; + switch (cidr->family) { - if (shift == 0) { +#if (NGX_HAVE_INET6) + case AF_INET6: + addr = cidr->u.in6.addr.s6_addr; + mask = cidr->u.in6.mask.s6_addr; + rc = NGX_OK; + + for (i = 0; i < 16; i++) { + + s = (shift > 8) ? 8 : shift; + shift -= s; + + mask[i] = (u_char) (0 - (1 << (8 - s))); - /* the x86 compilers use the shl instruction that shifts by modulo 32 */ + if (addr[i] != (addr[i] & mask[i])) { + rc = NGX_DONE; + addr[i] &= mask[i]; + } + } + + return rc; +#endif - cidr->u.in.mask = 0; + default: /* AF_INET */ + + if (shift) { + cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); - if (cidr->u.in.addr == 0) { + } else { + /* x86 compilers use a shl instruction that shifts by modulo 32 */ + cidr->u.in.mask = 0; + } + + if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { return NGX_OK; } + cidr->u.in.addr &= cidr->u.in.mask; + return NGX_DONE; } +} + + +ngx_int_t +ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, size_t len) +{ + in_addr_t inaddr; + ngx_uint_t family; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct in6_addr inaddr6; + struct sockaddr_in6 *sin6; + + /* + * prevent MSVC8 waring: + * potentially uninitialized local variable 'inaddr6' used + */ + ngx_memzero(inaddr6.s6_addr, sizeof(struct in6_addr)); +#endif + + inaddr = ngx_inet_addr(text, len); + + if (inaddr != INADDR_NONE) { + family = AF_INET; + len = sizeof(struct sockaddr_in); + +#if (NGX_HAVE_INET6) + } else if (ngx_inet6_addr(text, len, inaddr6.s6_addr) == NGX_OK) { + family = AF_INET6; + len = sizeof(struct sockaddr_in6); + +#endif + } else { + return NGX_DECLINED; + } - cidr->u.in.mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); - - if (cidr->u.in.addr == (cidr->u.in.addr & cidr->u.in.mask)) { - return NGX_OK; + addr->sockaddr = ngx_pcalloc(pool, len); + if (addr->sockaddr == NULL) { + return NGX_ERROR; } - cidr->u.in.addr &= cidr->u.in.mask; + addr->sockaddr->sa_family = (u_char) family; + addr->socklen = len; + + switch (family) { - return NGX_DONE; +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) addr->sockaddr; + ngx_memcpy(sin6->sin6_addr.s6_addr, inaddr6.s6_addr, 16); + break; +#endif + + default: /* AF_INET */ + sin = (struct sockaddr_in *) addr->sockaddr; + sin->sin_addr.s_addr = inaddr; + break; + } + + return NGX_OK; } @@ -365,7 +576,7 @@ ngx_parse_unix_domain_url(ngx_pool_t *po saun->sun_family = AF_UNIX; (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); - u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } @@ -523,20 +734,21 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx return NGX_OK; } - if (len++) { - - p = ngx_alloc(len, pool->log); - if (p == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(p, host, len); - - sin->sin_addr.s_addr = inet_addr((const char *) p); + if (len) { + sin->sin_addr.s_addr = ngx_inet_addr(host, len); if (sin->sin_addr.s_addr == INADDR_NONE) { + p = ngx_alloc(++len, pool->log); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, host, len); + h = gethostbyname((const char *) p); + ngx_free(p); + if (h == NULL || h->h_addr_list[0] == NULL) { ngx_free(p); u->err = "host not found"; @@ -550,8 +762,6 @@ ngx_parse_inet_url(ngx_pool_t *pool, ngx u->wildcard = 1; } - ngx_free(p); - } else { sin->sin_addr.s_addr = INADDR_ANY; u->wildcard = 1; @@ -578,7 +788,6 @@ static ngx_int_t ngx_parse_inet6_url(ngx_pool_t *pool, ngx_url_t *u) { #if (NGX_HAVE_INET6) - int rc; u_char *p, *host, *port, *last, *uri; size_t len; ngx_int_t n; @@ -650,35 +859,10 @@ ngx_parse_inet6_url(ngx_pool_t *pool, ng return NGX_ERROR; } - u->host.len = len++; + u->host.len = len; u->host.data = host; - p = ngx_alloc(len, pool->log); - if (p == NULL) { - return NGX_ERROR; - } - - (void) ngx_cpystrn(p, host, len); - -#if (NGX_WIN32) - - rc = WSAStringToAddress((char *) p, AF_INET6, NULL, - (SOCKADDR *) sin6, &u->socklen); - rc = !rc; - - if (u->port) { - sin6->sin6_port = htons(u->port); - } - -#else - - rc = inet_pton(AF_INET6, (const char *) p, &sin6->sin6_addr); - -#endif - - ngx_free(p); - - if (rc == 0) { + if (ngx_inet6_addr(host, len, sin6->sin6_addr.s6_addr) != NGX_OK) { u->err = "invalid IPv6 address"; return NGX_ERROR; } @@ -721,20 +905,20 @@ ngx_inet_resolve_host(ngx_pool_t *pool, struct hostent *h; struct sockaddr_in *sin; - 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); - /* AF_INET only */ port = htons(u->port); - in_addr = inet_addr((char *) host); + in_addr = ngx_inet_addr(u->host.data, u->host.len); if (in_addr == INADDR_NONE) { + 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); + h = gethostbyname((char *) host); ngx_free(host); @@ -753,7 +937,7 @@ ngx_inet_resolve_host(ngx_pool_t *pool, /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, i * sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } @@ -789,11 +973,9 @@ ngx_inet_resolve_host(ngx_pool_t *pool, } else { - ngx_free(host); - /* MP: ngx_shared_palloc() */ - u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); + u->addrs = ngx_pcalloc(pool, sizeof(ngx_addr_t)); if (u->addrs == NULL) { return NGX_ERROR; } 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 @@ -70,7 +70,7 @@ typedef struct { struct sockaddr *sockaddr; socklen_t socklen; ngx_str_t name; -} ngx_peer_addr_t; +} ngx_addr_t; typedef struct { @@ -94,7 +94,7 @@ typedef struct { socklen_t socklen; u_char sockaddr[NGX_SOCKADDRLEN]; - ngx_peer_addr_t *addrs; + ngx_addr_t *addrs; ngx_uint_t naddrs; char *err; @@ -102,13 +102,18 @@ typedef struct { in_addr_t ngx_inet_addr(u_char *text, size_t len); +#if (NGX_HAVE_INET6) +ngx_int_t ngx_inet6_addr(u_char *p, size_t len, u_char *addr); +size_t ngx_inet6_ntop(u_char *p, u_char *text, size_t len); +#endif size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len, ngx_uint_t port); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, ngx_cidr_t *cidr); +ngx_int_t ngx_parse_addr(ngx_pool_t *pool, ngx_addr_t *addr, u_char *text, + size_t len); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); ngx_int_t ngx_inet_resolve_host(ngx_pool_t *pool, ngx_url_t *u); - #endif /* _NGX_INET_H_INCLUDED_ */ 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 @@ -92,7 +92,7 @@ static void *ngx_resolver_dup(ngx_resolv /* STUB: ngx_peer_addr_t * */ ngx_resolver_t * -ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr) +ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr) { ngx_resolver_t *r; ngx_pool_cleanup_t *cln; diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -135,7 +135,7 @@ struct ngx_resolver_ctx_s { }; -ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_peer_addr_t *addr); +ngx_resolver_t *ngx_resolver_create(ngx_conf_t *cf, ngx_addr_t *addr); ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp); ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx); diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -15,10 +15,11 @@ static u_char *ngx_sprintf_num(u_char *b void ngx_strlow(u_char *dst, u_char *src, size_t n) { - while (n--) { + while (n) { *dst = ngx_tolower(*src); dst++; src++; + n--; } } @@ -147,7 +148,7 @@ ngx_vslprintf(u_char *buf, u_char *last, int64_t i64; uint64_t ui64; ngx_msec_t ms; - ngx_uint_t width, sign, hex, max_width, frac_width, i; + ngx_uint_t width, sign, hex, max_width, frac_width, n; ngx_str_t *v; ngx_variable_value_t *vv; @@ -377,7 +378,7 @@ ngx_vslprintf(u_char *buf, u_char *last, scale = 1.0; - for (i = 0; i < frac_width; i++) { + for (n = frac_width; n; n--) { scale *= 10.0; } @@ -1255,7 +1256,7 @@ ngx_utf8_cpystrn(u_char *dst, u_char *sr uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) { - ngx_uint_t i, n; + ngx_uint_t n; uint32_t *escape; static u_char hex[] = "0123456789abcdef"; @@ -1373,17 +1374,18 @@ ngx_escape_uri(u_char *dst, u_char *src, n = 0; - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { n++; } src++; + size--; } return (uintptr_t) n; } - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { *dst++ = '%'; *dst++ = hex[*src >> 4]; @@ -1393,6 +1395,7 @@ ngx_escape_uri(u_char *dst, u_char *src, } else { *dst++ = *src++; } + size--; } return (uintptr_t) dst; @@ -1533,13 +1536,13 @@ uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size) { u_char ch; - ngx_uint_t i, len; + ngx_uint_t len; if (dst == NULL) { len = 0; - for (i = 0; i < size; i++) { + while (size) { switch (*src++) { case '<': @@ -1557,12 +1560,13 @@ ngx_escape_html(u_char *dst, u_char *src default: break; } + size--; } return (uintptr_t) len; } - for (i = 0; i < size; i++) { + while (size) { ch = *src++; switch (ch) { @@ -1584,6 +1588,7 @@ ngx_escape_html(u_char *dst, u_char *src *dst++ = ch; break; } + size--; } return (uintptr_t) dst; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -152,7 +152,6 @@ ngx_event_accept(ngx_event_t *ev) c->socklen = socklen; c->listening = ls; c->local_sockaddr = ls->sockaddr; - c->local_socklen = ls->socklen; c->unexpected_eof = 1; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -54,15 +54,7 @@ ngx_event_connect_peer(ngx_peer_connecti { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, "setsockopt(SO_RCVBUF) failed"); - - ngx_free_connection(c); - - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); - } - - return NGX_ERROR; + goto failed; } } @@ -70,14 +62,16 @@ ngx_event_connect_peer(ngx_peer_connecti ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_nonblocking_n " failed"); - ngx_free_connection(c); + goto failed; + } - if (ngx_close_socket(s) == -1) { - ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, - ngx_close_socket_n " failed"); + if (pc->local) { + if (bind(s, pc->local->sockaddr, pc->local->socklen) == -1) { + ngx_log_error(NGX_LOG_CRIT, pc->log, ngx_socket_errno, + "bind(%V) failed", &pc->local->name); + + goto failed; } - - return NGX_ERROR; } c->recv = ngx_recv; @@ -127,7 +121,7 @@ ngx_event_connect_peer(ngx_peer_connecti if (ngx_add_conn) { if (ngx_add_conn(c) == NGX_ERROR) { - return NGX_ERROR; + goto failed; } } @@ -199,7 +193,7 @@ ngx_event_connect_peer(ngx_peer_connecti if (ngx_blocking(s) == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, ngx_blocking_n " failed"); - return NGX_ERROR; + goto failed; } /* @@ -229,7 +223,7 @@ ngx_event_connect_peer(ngx_peer_connecti } if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } if (rc == -1) { @@ -237,7 +231,7 @@ ngx_event_connect_peer(ngx_peer_connecti /* NGX_EINPROGRESS */ if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) { - return NGX_ERROR; + goto failed; } return NGX_AGAIN; @@ -248,6 +242,17 @@ ngx_event_connect_peer(ngx_peer_connecti wev->ready = 1; return NGX_OK; + +failed: + + ngx_free_connection(c); + + if (ngx_close_socket(s) == -1) { + ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, + ngx_close_socket_n " failed"); + } + + return NGX_ERROR; } diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -55,6 +55,8 @@ struct ngx_peer_connection_s { ngx_atomic_t *lock; #endif + ngx_addr_t *local; + int rcvbuf; ngx_log_t *log; @@ -70,5 +72,4 @@ ngx_int_t ngx_event_connect_peer(ngx_pee ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data); - #endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */ diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -946,7 +946,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, for ( ;; ) { - while (in && buf->last < buf->end) { + while (in && buf->last < buf->end && send < limit) { if (in->buf->last_buf || in->buf->flush) { flush = 1; } @@ -973,8 +973,8 @@ ngx_ssl_send_chain(ngx_connection_t *c, ngx_memcpy(buf->last, in->buf->pos, size); buf->last += size; - in->buf->pos += size; + send += size; if (in->buf->pos == in->buf->last) { in = in->next; @@ -999,7 +999,6 @@ ngx_ssl_send_chain(ngx_connection_t *c, } buf->pos += n; - send += n; c->sent += n; if (n < size) { diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -10,18 +10,37 @@ typedef struct { - in_addr_t mask; - in_addr_t addr; - ngx_uint_t deny; /* unsigned deny:1; */ + in_addr_t mask; + in_addr_t addr; + ngx_uint_t deny; /* unsigned deny:1; */ } ngx_http_access_rule_t; +#if (NGX_HAVE_INET6) typedef struct { - ngx_array_t *rules; /* array of ngx_http_access_rule_t */ + struct in6_addr addr; + struct in6_addr mask; + ngx_uint_t deny; /* unsigned deny:1; */ +} ngx_http_access_rule6_t; + +#endif + +typedef struct { + ngx_array_t *rules; /* array of ngx_http_access_rule_t */ +#if (NGX_HAVE_INET6) + ngx_array_t *rules6; /* array of ngx_http_access_rule6_t */ +#endif } ngx_http_access_loc_conf_t; static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_access_inet(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, in_addr_t addr); +#if (NGX_HAVE_INET6) +static ngx_int_t ngx_http_access_inet6(ngx_http_request_t *r, + ngx_http_access_loc_conf_t *alcf, u_char *p); +#endif +static ngx_int_t ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny); static char *ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void *ngx_http_access_create_loc_conf(ngx_conf_t *cf); @@ -87,46 +106,59 @@ ngx_module_t ngx_http_access_module = { static ngx_int_t ngx_http_access_handler(ngx_http_request_t *r) { - ngx_uint_t i; struct sockaddr_in *sin; - ngx_http_access_rule_t *rule; - ngx_http_core_loc_conf_t *clcf; ngx_http_access_loc_conf_t *alcf; alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); - if (alcf->rules == NULL) { - return NGX_DECLINED; +#if (NGX_HAVE_INET6) + + if (alcf->rules6 && r->connection->sockaddr->sa_family == AF_INET6) { + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; + + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + return ngx_http_access_inet(r, alcf, htonl(addr)); + } + + return ngx_http_access_inet6(r, alcf, p); } - /* AF_INET only */ +#endif - if (r->connection->sockaddr->sa_family != AF_INET) { - return NGX_DECLINED; + if (alcf->rules && r->connection->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr); } - sin = (struct sockaddr_in *) r->connection->sockaddr; + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_access_inet(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + in_addr_t addr) +{ + ngx_uint_t i; + ngx_http_access_rule_t *rule; rule = alcf->rules->elts; for (i = 0; i < alcf->rules->nelts; i++) { ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "access: %08XD %08XD %08XD", - sin->sin_addr.s_addr, rule[i].mask, rule[i].addr); - - if ((sin->sin_addr.s_addr & rule[i].mask) == rule[i].addr) { - if (rule[i].deny) { - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + addr, rule[i].mask, rule[i].addr); - if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "access forbidden by rule"); - } - - return NGX_HTTP_FORBIDDEN; - } - - return NGX_OK; + if ((addr & rule[i].mask) == rule[i].addr) { + return ngx_http_access_found(r, rule[i].deny); } } @@ -134,62 +166,159 @@ ngx_http_access_handler(ngx_http_request } +#if (NGX_HAVE_INET6) + +static ngx_int_t +ngx_http_access_inet6(ngx_http_request_t *r, ngx_http_access_loc_conf_t *alcf, + u_char *p) +{ + ngx_uint_t n; + ngx_uint_t i; + ngx_http_access_rule6_t *rule6; + + rule6 = alcf->rules6->elts; + for (i = 0; i < alcf->rules6->nelts; i++) { + +#if (NGX_DEBUG) + { + size_t cl, ml, al; + u_char ct[NGX_INET6_ADDRSTRLEN]; + u_char mt[NGX_INET6_ADDRSTRLEN]; + u_char at[NGX_INET6_ADDRSTRLEN]; + + cl = ngx_inet6_ntop(p, ct, NGX_INET6_ADDRSTRLEN); + ml = ngx_inet6_ntop(rule6[i].mask.s6_addr, mt, NGX_INET6_ADDRSTRLEN); + al = ngx_inet6_ntop(rule6[i].addr.s6_addr, at, NGX_INET6_ADDRSTRLEN); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "access: %*s %*s %*s", cl, ct, ml, mt, al, at); + } +#endif + + for (n = 0; n < 16; n++) { + if ((p[n] & rule6[i].mask.s6_addr[n]) != rule6[i].addr.s6_addr[n]) { + goto next; + } + } + + return ngx_http_access_found(r, rule6[i].deny); + + next: + continue; + } + + return NGX_DECLINED; +} + +#endif + + +static ngx_int_t +ngx_http_access_found(ngx_http_request_t *r, ngx_uint_t deny) +{ + ngx_http_core_loc_conf_t *clcf; + + if (deny) { + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + + if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "access forbidden by rule"); + } + + return NGX_HTTP_FORBIDDEN; + } + + return NGX_OK; +} + + static char * ngx_http_access_rule(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_access_loc_conf_t *alcf = conf; - ngx_int_t rc; - ngx_str_t *value; - ngx_cidr_t cidr; - ngx_http_access_rule_t *rule; + ngx_int_t rc; + ngx_uint_t all; + ngx_str_t *value; + ngx_cidr_t cidr; + ngx_http_access_rule_t *rule; +#if (NGX_HAVE_INET6) + ngx_http_access_rule6_t *rule6; +#endif - if (alcf->rules == NULL) { - alcf->rules = ngx_array_create(cf->pool, 4, - sizeof(ngx_http_access_rule_t)); - if (alcf->rules == NULL) { - return NGX_CONF_ERROR; - } - } - - rule = ngx_array_push(alcf->rules); - if (rule == NULL) { - return NGX_CONF_ERROR; - } + ngx_memzero(&cidr, sizeof(ngx_cidr_t)); value = cf->args->elts; - rule->deny = (value[0].data[0] == 'd') ? 1 : 0; + all = (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0); + + if (!all) { + + rc = ngx_ptocidr(&value[1], &cidr); - if (value[1].len == 3 && ngx_strcmp(value[1].data, "all") == 0) { - rule->mask = 0; - rule->addr = 0; + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } - return NGX_CONF_OK; + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "low address bits of %V are meaningless", &value[1]); + } } - rc = ngx_ptocidr(&value[1], &cidr); + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + case 0: /* all */ - if (rc == NGX_ERROR) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", - &value[1]); - return NGX_CONF_ERROR; - } + if (alcf->rules6 == NULL) { + alcf->rules6 = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule6_t)); + if (alcf->rules6 == NULL) { + return NGX_CONF_ERROR; + } + } + + rule6 = ngx_array_push(alcf->rules6); + if (rule6 == NULL) { + return NGX_CONF_ERROR; + } + + rule6->mask = cidr.u.in6.mask; + rule6->addr = cidr.u.in6.addr; + rule6->deny = (value[0].data[0] == 'd') ? 1 : 0; - if (cidr.family != AF_INET) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"allow\" supports IPv4 only"); - return NGX_CONF_ERROR; - } + if (!all) { + break; + } + + /* "all" passes through */ +#endif + + default: /* AF_INET */ - if (rc == NGX_DONE) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "low address bits of %V are meaningless", &value[1]); + if (alcf->rules == NULL) { + alcf->rules = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_access_rule_t)); + if (alcf->rules == NULL) { + return NGX_CONF_ERROR; + } + } + + rule = ngx_array_push(alcf->rules); + if (rule == NULL) { + return NGX_CONF_ERROR; + } + + rule->mask = cidr.u.in.mask; + rule->addr = cidr.u.in.addr; + rule->deny = (value[0].data[0] == 'd') ? 1 : 0; } - rule->mask = cidr.u.in.mask; - rule->addr = cidr.u.in.addr; - return NGX_CONF_OK; } @@ -218,6 +347,12 @@ ngx_http_access_merge_loc_conf(ngx_conf_ conf->rules = prev->rules; } +#if (NGX_HAVE_INET6) + if (conf->rules6 == NULL) { + conf->rules6 = prev->rules6; + } +#endif + return NGX_CONF_OK; } 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 @@ -240,6 +240,13 @@ static ngx_command_t ngx_http_fastcgi_c offsetof(ngx_http_fastcgi_loc_conf_t, upstream.ignore_client_abort), NULL }, + { ngx_string("fastcgi_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upsteam_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.local), + NULL }, + { ngx_string("fastcgi_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, 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 @@ -650,7 +650,7 @@ ngx_http_log_variable(ngx_http_request_t static uintptr_t ngx_http_log_escape(u_char *dst, u_char *src, size_t size) { - ngx_uint_t i, n; + ngx_uint_t n; static u_char hex[] = "0123456789ABCDEF"; static uint32_t escape[] = { @@ -678,17 +678,18 @@ ngx_http_log_escape(u_char *dst, u_char n = 0; - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { n++; } src++; + size--; } return (uintptr_t) n; } - for (i = 0; i < size; i++) { + while (size) { if (escape[*src >> 5] & (1 << (*src & 0x1f))) { *dst++ = '\\'; *dst++ = 'x'; @@ -699,6 +700,7 @@ ngx_http_log_escape(u_char *dst, u_char } else { *dst++ = *src++; } + size--; } return (uintptr_t) dst; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -63,6 +63,13 @@ static ngx_command_t ngx_http_memcached 0, NULL }, + { ngx_string("memcached_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upsteam_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_memcached_loc_conf_t, upstream.local), + NULL }, + { ngx_string("memcached_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, 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 @@ -229,6 +229,13 @@ static ngx_command_t ngx_http_proxy_com offsetof(ngx_http_proxy_loc_conf_t, upstream.ignore_client_abort), NULL }, + { ngx_string("proxy_bind"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_upsteam_bind_set_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_loc_conf_t, upstream.local), + NULL }, + { ngx_string("proxy_connect_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -25,17 +25,23 @@ typedef struct { ngx_uint_t type; ngx_uint_t hash; ngx_str_t header; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_uint_t unixsock; /* unsigned unixsock:1; */ +#endif } ngx_http_realip_loc_conf_t; typedef struct { ngx_connection_t *connection; - in_addr_t addr; + struct sockaddr *sockaddr; + socklen_t socklen; ngx_str_t addr_text; } ngx_http_realip_ctx_t; static ngx_int_t ngx_http_realip_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, + size_t len); static void ngx_http_realip_cleanup(void *data); static char *ngx_http_realip_from(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -103,13 +109,11 @@ ngx_http_realip_handler(ngx_http_request { u_char *ip, *p; size_t len; - in_addr_t addr; ngx_uint_t i, hash; ngx_list_part_t *part; ngx_table_elt_t *header; struct sockaddr_in *sin; ngx_connection_t *c; - ngx_pool_cleanup_t *cln; ngx_http_realip_ctx_t *ctx; ngx_http_realip_from_t *from; ngx_http_realip_loc_conf_t *rlcf; @@ -120,11 +124,6 @@ ngx_http_realip_handler(ngx_http_request return NGX_DECLINED; } - cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t)); - if (cln == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } - rlcf = ngx_http_get_module_loc_conf(r, ngx_http_realip_module); if (rlcf->from == NULL) { @@ -207,52 +206,83 @@ found: /* AF_INET only */ - if (r->connection->sockaddr->sa_family != AF_INET) { - return NGX_DECLINED; + if (c->sockaddr->sa_family == AF_INET) { + sin = (struct sockaddr_in *) c->sockaddr; + + from = rlcf->from->elts; + for (i = 0; i < rlcf->from->nelts; i++) { + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, + "realip: %08XD %08XD %08XD", + sin->sin_addr.s_addr, from[i].mask, from[i].addr); + + if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) { + return ngx_http_realip_set_addr(r, ip, len); + } + } + } + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (c->sockaddr->sa_family == AF_UNIX && rlcf->unixsock) { + return ngx_http_realip_set_addr(r, ip, len); } - sin = (struct sockaddr_in *) c->sockaddr; +#endif - from = rlcf->from->elts; - for (i = 0; i < rlcf->from->nelts; i++) { + return NGX_DECLINED; +} - ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0, - "realip: %08XD %08XD %08XD", - sin->sin_addr.s_addr, from[i].mask, from[i].addr); - if ((sin->sin_addr.s_addr & from[i].mask) == from[i].addr) { - - ctx = cln->data; - - ngx_http_set_ctx(r, ctx, ngx_http_realip_module); +static ngx_int_t +ngx_http_realip_set_addr(ngx_http_request_t *r, u_char *ip, size_t len) +{ + u_char *p; + ngx_int_t rc; + ngx_addr_t addr; + ngx_connection_t *c; + ngx_pool_cleanup_t *cln; + ngx_http_realip_ctx_t *ctx; - addr = inet_addr((char *) ip); + cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_realip_ctx_t)); + if (cln == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - if (addr == INADDR_NONE) { - return NGX_DECLINED; - } + ctx = cln->data; + ngx_http_set_ctx(r, ctx, ngx_http_realip_module); + + c = r->connection; + + rc = ngx_parse_addr(c->pool, &addr, ip, len); - p = ngx_pnalloc(c->pool, len); - if (p == NULL) { - return NGX_HTTP_INTERNAL_SERVER_ERROR; - } + switch (rc) { + case NGX_DECLINED: + return NGX_DECLINED; + case NGX_ERROR: + return NGX_HTTP_INTERNAL_SERVER_ERROR; + default: /* NGX_OK */ + break; + } - ngx_memcpy(p, ip, len); - - cln->handler = ngx_http_realip_cleanup; + p = ngx_pnalloc(c->pool, len); + if (p == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } - ctx->connection = c; - ctx->addr = sin->sin_addr.s_addr; - ctx->addr_text = c->addr_text; + ngx_memcpy(p, ip, len); - sin->sin_addr.s_addr = addr; + cln->handler = ngx_http_realip_cleanup; - c->addr_text.len = len; - c->addr_text.data = p; + ctx->connection = c; + ctx->sockaddr = c->sockaddr; + ctx->socklen = c->socklen; + ctx->addr_text = c->addr_text; - return NGX_DECLINED; - } - } + c->sockaddr = addr.sockaddr; + c->socklen = addr.socklen; + c->addr_text.len = len; + c->addr_text.data = p; return NGX_DECLINED; } @@ -263,14 +293,12 @@ ngx_http_realip_cleanup(void *data) { ngx_http_realip_ctx_t *ctx = data; - ngx_connection_t *c; - struct sockaddr_in *sin; + ngx_connection_t *c; c = ctx->connection; - sin = (struct sockaddr_in *) c->sockaddr; - sin->sin_addr.s_addr = ctx->addr; - + c->sockaddr = ctx->sockaddr; + c->socklen = ctx->socklen; c->addr_text = ctx->addr_text; } @@ -285,6 +313,17 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx ngx_cidr_t cidr; ngx_http_realip_from_t *from; + value = cf->args->elts; + +#if (NGX_HAVE_UNIX_DOMAIN) + + if (ngx_strcmp(value[1].data, "unix:") == 0) { + rlcf->unixsock = 1; + return NGX_CONF_OK; + } + +#endif + if (rlcf->from == NULL) { rlcf->from = ngx_array_create(cf->pool, 2, sizeof(ngx_http_realip_from_t)); @@ -298,8 +337,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx return NGX_CONF_ERROR; } - value = cf->args->elts; - rc = ngx_ptocidr(&value[1], &cidr); if (rc == NGX_ERROR) { @@ -310,7 +347,7 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx if (cidr.family != AF_INET) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"realip_from\" supports IPv4 only"); + "\"set_real_ip_from\" supports IPv4 only"); return NGX_CONF_ERROR; } @@ -369,6 +406,7 @@ ngx_http_realip_create_loc_conf(ngx_conf * conf->from = NULL; * conf->hash = 0; * conf->header = { 0, NULL }; + * conf->unixsock = 0; */ conf->type = NGX_CONF_UNSET_UINT; @@ -385,6 +423,9 @@ ngx_http_realip_merge_loc_conf(ngx_conf_ if (conf->from == NULL) { conf->from = prev->from; +#if (NGX_HAVE_UNIX_DOMAIN) + conf->unixsock = prev->unixsock; +#endif } ngx_conf_merge_uint_value(conf->type, prev->type, NGX_HTTP_REALIP_XREALIP); diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.8.21'; +our $VERSION = '0.8.22'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1348,10 +1348,14 @@ static ngx_int_t ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf, ngx_array_t *ports) { - ngx_uint_t p, a; + ngx_uint_t p, a; ngx_http_conf_port_t *port; ngx_http_conf_addr_t *addr; + if (ports == NULL) { + return NGX_OK; + } + port = ports->elts; for (p = 0; p < ports->nelts; p++) { 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 @@ -2838,6 +2838,33 @@ ngx_http_core_merge_srv_conf(ngx_conf_t /* TODO: it does not merge, it inits only */ + ngx_conf_merge_size_value(conf->connection_pool_size, + prev->connection_pool_size, 256); + ngx_conf_merge_size_value(conf->request_pool_size, + prev->request_pool_size, 4096); + ngx_conf_merge_msec_value(conf->client_header_timeout, + prev->client_header_timeout, 60000); + ngx_conf_merge_size_value(conf->client_header_buffer_size, + prev->client_header_buffer_size, 1024); + ngx_conf_merge_bufs_value(conf->large_client_header_buffers, + prev->large_client_header_buffers, + 4, ngx_pagesize); + + if (conf->large_client_header_buffers.size < conf->connection_pool_size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"large_client_header_buffers\" size must be " + "equal to or bigger than \"connection_pool_size\""); + return NGX_CONF_ERROR; + } + + ngx_conf_merge_value(conf->ignore_invalid_headers, + prev->ignore_invalid_headers, 1); + + ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1); + + ngx_conf_merge_value(conf->underscores_in_headers, + prev->underscores_in_headers, 0); + if (!conf->listen) { ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t)); @@ -2882,33 +2909,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t sn->name.data = conf->server_name.data; } - ngx_conf_merge_size_value(conf->connection_pool_size, - prev->connection_pool_size, 256); - ngx_conf_merge_size_value(conf->request_pool_size, - prev->request_pool_size, 4096); - ngx_conf_merge_msec_value(conf->client_header_timeout, - prev->client_header_timeout, 60000); - ngx_conf_merge_size_value(conf->client_header_buffer_size, - prev->client_header_buffer_size, 1024); - ngx_conf_merge_bufs_value(conf->large_client_header_buffers, - prev->large_client_header_buffers, - 4, ngx_pagesize); - - if (conf->large_client_header_buffers.size < conf->connection_pool_size) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the \"large_client_header_buffers\" size must be " - "equal to or bigger than \"connection_pool_size\""); - return NGX_CONF_ERROR; - } - - ngx_conf_merge_value(conf->ignore_invalid_headers, - prev->ignore_invalid_headers, 1); - - ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1); - - ngx_conf_merge_value(conf->underscores_in_headers, - prev->underscores_in_headers, 0); - return NGX_CONF_OK; } 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 @@ -954,9 +954,17 @@ ngx_http_process_request_headers(ngx_eve } if (rv == NGX_DECLINED) { - len = r->header_in->end - r->header_name_start; p = r->header_name_start; + if (p == NULL) { + ngx_log_error(NGX_LOG_INFO, c->log, 0, + "client sent too large request"); + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + return; + } + + len = r->header_in->end - p; + if (len > NGX_MAX_ERROR_STR - 300) { len = NGX_MAX_ERROR_STR - 300; p[len++] = '.'; p[len++] = '.'; p[len++] = '.'; 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 @@ -479,6 +479,8 @@ ngx_http_upstream_init_request(ngx_http_ return; } + u->peer.local = u->conf->local; + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.alignment = clcf->directio_alignment; @@ -4196,6 +4198,41 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng } +char * +ngx_http_upsteam_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + char *p = conf; + + ngx_int_t rc; + ngx_str_t *value; + ngx_addr_t **paddr; + + paddr = (ngx_addr_t **) (p + cmd->offset); + + *paddr = ngx_palloc(cf->pool, sizeof(ngx_addr_t)); + if (*paddr == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + rc = ngx_parse_addr(cf->pool, *paddr, value[1].data, value[1].len); + + switch (rc) { + case NGX_OK: + (*paddr)->name = value[1]; + return NGX_CONF_OK; + + case NGX_DECLINED: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid address \"%V\"", &value[1]); + default: + return NGX_CONF_ERROR; + } +} + + ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, 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 @@ -80,7 +80,7 @@ typedef struct { typedef struct { - ngx_peer_addr_t *addrs; + ngx_addr_t *addrs; ngx_uint_t naddrs; ngx_uint_t weight; ngx_uint_t max_fails; @@ -152,6 +152,8 @@ typedef struct { ngx_array_t *hide_headers; ngx_array_t *pass_headers; + ngx_addr_t *local; + #if (NGX_HTTP_CACHE) ngx_shm_zone_t *cache; @@ -321,6 +323,8 @@ ngx_int_t ngx_http_upstream_create(ngx_h void ngx_http_upstream_init(ngx_http_request_t *r); ngx_http_upstream_srv_conf_t *ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags); +char *ngx_http_upsteam_bind_set_slot(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); ngx_int_t ngx_http_upstream_hide_headers_hash(ngx_conf_t *cf, ngx_http_upstream_conf_t *conf, ngx_http_upstream_conf_t *prev, ngx_str_t *default_hide_headers, ngx_hash_init_t *hash); @@ -334,5 +338,4 @@ extern ngx_module_t ngx_http_upst extern ngx_conf_bitmask_t ngx_http_upstream_cache_method_mask[]; - #endif /* _NGX_HTTP_UPSTREAM_H_INCLUDED_ */ diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -81,5 +81,4 @@ void ngx_http_upstream_save_round_robin_ #endif - #endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */ 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 @@ -14,6 +14,8 @@ static ngx_int_t ngx_http_variable_reque ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_request_get_size(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, @@ -238,7 +240,7 @@ static ngx_http_variable_t ngx_http_cor offsetof(ngx_http_request_t, headers_out.cache_control), 0, 0 }, { ngx_string("limit_rate"), ngx_http_variable_request_set_size, - ngx_http_variable_request, + ngx_http_variable_request_get_size, offsetof(ngx_http_request_t, limit_rate), NGX_HTTP_VAR_CHANGEABLE|NGX_HTTP_VAR_NOCACHEABLE, 0 }, @@ -568,6 +570,28 @@ ngx_http_variable_request_set(ngx_http_r } +static ngx_int_t +ngx_http_variable_request_get_size(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + size_t *sp; + + sp = (size_t *) ((char *) r + data); + + v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -887,7 +911,7 @@ ngx_http_variable_binary_remote_addr(ngx v->valid = 1; v->no_cacheable = 0; v->not_found = 0; - v->data = (u_char *) &sin6->sin6_addr; + v->data = sin6->sin6_addr.s6_addr; break; #endif diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -394,7 +394,7 @@ char *ngx_mail_capabilities(ngx_conf_t * /* STUB */ -void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer); +void ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer); void ngx_mail_auth_http_init(ngx_mail_session_t *s); /**/ 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 @@ -12,7 +12,7 @@ typedef struct { - ngx_peer_addr_t *peer; + ngx_addr_t *peer; ngx_msec_t timeout; @@ -457,7 +457,7 @@ ngx_mail_auth_http_process_headers(ngx_m time_t timer; size_t len, size; ngx_int_t rc, port, n; - ngx_peer_addr_t *peer; + ngx_addr_t *peer; struct sockaddr_in *sin; ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0, @@ -764,7 +764,7 @@ ngx_mail_auth_http_process_headers(ngx_m return; } - peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t)); + peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_addr_t)); if (peer == NULL) { ngx_destroy_pool(ctx->pool); ngx_mail_session_internal_server_error(s); @@ -795,8 +795,7 @@ ngx_mail_auth_http_process_headers(ngx_m sin->sin_port = htons((in_port_t) port); - ctx->addr.data[ctx->addr.len] = '\0'; - sin->sin_addr.s_addr = inet_addr((char *) ctx->addr.data); + sin->sin_addr.s_addr = ngx_inet_addr(ctx->addr.data, ctx->addr.len); if (sin->sin_addr.s_addr == INADDR_NONE) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -108,7 +108,7 @@ static u_char smtp_auth_ok[] = "235 2.0 void -ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_peer_addr_t *peer) +ngx_mail_proxy_init(ngx_mail_session_t *s, ngx_addr_t *peer) { int keepalive; ngx_int_t rc; 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 @@ -141,7 +141,7 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_is_dir(sb) (S_ISDIR((sb)->st_mode)) #define ngx_is_file(sb) (S_ISREG((sb)->st_mode)) #define ngx_is_link(sb) (S_ISLNK((sb)->st_mode)) -#define ngx_is_exec(sb) ((sb)->st_mode & S_IXUSR) +#define ngx_is_exec(sb) (((sb)->st_mode & S_IXUSR) == S_IXUSR) #define ngx_file_access(sb) ((sb)->st_mode & 0777) #define ngx_file_size(sb) (sb)->st_size #define ngx_file_mtime(sb) (sb)->st_mtime diff --git a/src/os/unix/ngx_freebsd_rfork_thread.h b/src/os/unix/ngx_freebsd_rfork_thread.h --- a/src/os/unix/ngx_freebsd_rfork_thread.h +++ b/src/os/unix/ngx_freebsd_rfork_thread.h @@ -118,5 +118,4 @@ void ngx_mutex_unlock(ngx_mutex_t *m); typedef int (*ngx_rfork_thread_func_pt)(void *arg); - #endif /* _NGX_FREEBSD_RFORK_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_setproctitle.h b/src/os/unix/ngx_setproctitle.h --- a/src/os/unix/ngx_setproctitle.h +++ b/src/os/unix/ngx_setproctitle.h @@ -13,7 +13,7 @@ /* FreeBSD, NetBSD, OpenBSD */ #define ngx_init_setproctitle(log) -#define ngx_setproctitle setproctitle +#define ngx_setproctitle(title) setproctitle("%s", title) #else /* !NGX_HAVE_SETPROCTITLE */ diff --git a/src/os/unix/ngx_thread.h b/src/os/unix/ngx_thread.h --- a/src/os/unix/ngx_thread.h +++ b/src/os/unix/ngx_thread.h @@ -124,5 +124,4 @@ ngx_int_t ngx_cond_signal(ngx_cond_t *cv #endif - #endif /* _NGX_THREAD_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_user.h b/src/os/unix/ngx_user.h --- a/src/os/unix/ngx_user.h +++ b/src/os/unix/ngx_user.h @@ -20,5 +20,4 @@ ngx_int_t ngx_crypt(ngx_pool_t *pool, u_ u_char **encrypted); - #endif /* _NGX_USER_H_INCLUDED_ */