# HG changeset patch # User Igor Sysoev # Date 1165179600 -10800 # Node ID 0effe91f60833eacf0ac8e5d7b402dcc34a08e4d # Parent c68f18041059eb75f5c12adaeec52eabfa79c086 nginx 0.5.0 *) Change: the parameters in the "%name" form in the "log_format" directive are not supported anymore. *) Change: the "proxy_upstream_max_fails", "proxy_upstream_fail_timeout", "fastcgi_upstream_max_fails", "fastcgi_upstream_fail_timeout", "memcached_upstream_max_fails", and "memcached_upstream_fail_timeout" directives are not supported anymore. *) Feature: the "server" directive in the "upstream" context supports the "max_fails", "fail_timeout", and "down" parameters. *) Feature: the "ip_hash" directive inside the "upstream" block. *) Feature: the WAIT status in the "Auth-Status" header line of the IMAP/POP3 proxy authentication server response. *) Bugfix: nginx could not be built on 64-bit platforms; bug appeared in 0.4.14. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,21 +1,47 @@ +Changes with nginx 0.5.0 04 Dec 2006 + + *) Change: the parameters in the "%name" form in the "log_format" + directive are not supported anymore. + + *) Change: the "proxy_upstream_max_fails", + "proxy_upstream_fail_timeout", "fastcgi_upstream_max_fails", + "fastcgi_upstream_fail_timeout", "memcached_upstream_max_fails", and + "memcached_upstream_fail_timeout" directives are not supported + anymore. + + *) Feature: the "server" directive in the "upstream" context supports + the "max_fails", "fail_timeout", and "down" parameters. + + *) Feature: the "ip_hash" directive inside the "upstream" block. + + *) Feature: the WAIT status in the "Auth-Status" header line of the + IMAP/POP3 proxy authentication server response. + + *) Bugfix: nginx could not be built on 64-bit platforms; bug appeared + in 0.4.14. + + Changes with nginx 0.4.14 27 Nov 2006 *) Feature: the "proxy_pass_error_message" directive in IMAP/POP3 proxy. - *) Bugfix: ngx_http_perl_module did nto work with perl built with the + *) Feature: now configure detects system PCRE library on FreeBSD, + Linux, and NetBSD. + + *) Bugfix: ngx_http_perl_module did not work with perl built with the threads support; bug appeared in 0.3.38. - *) Bugfix: !!!!!!!!!! segfault perl. - - *) Bugfix: !!!!!!!!!! recursive perl. + *) Bugfix: ngx_http_perl_module did not work if perl was called + recursively. *) Bugfix: nginx ignored a host name in an request line. - *) Bugfix: !!!!!!!!!! endless loop when too many FastCGI sent too many - to stderr - - *) Bugfix: !!!!!!!! negative upstream response time + *) Bugfix: a worker process may got caught in an endless loop, if a + FastCGI server sent too many data to the stderr. + + *) Bugfix: the $upstream_response_time variable may be negative if the + system time was changed backward. *) Bugfix: the "Auth-Login-Attempt" parameter was not sent to IMAP/POP3 proxy authentication server when POP3 was used. @@ -353,7 +379,7 @@ Changes with nginx 0.3.53 *) Change: the "add_header" directive adds the string to 204, 301, and 302 responses. - *) Feature: the "server" directive if the "upstream" context supports + *) Feature: the "server" directive in the "upstream" context supports the "weight" parameter. *) Feature: the "server_name" directive supports the "*" wildcard. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,23 +1,49 @@ +Изменения в nginx 0.5.0 04.12.2006 + + *) Изменение: параметры в виде "%name" в директиве log_format больше не + поддерживаются. + + *) Изменение: директивы proxy_upstream_max_fails, + proxy_upstream_fail_timeout, fastcgi_upstream_max_fails, и + fastcgi_upstream_fail_timeout, memcached_upstream_max_fails и + memcached_upstream_fail_timeout больше не поддерживаются. + + *) Добавление: директива server в блоке upstream поддерживает параметры + max_fails, fail_timeout и down. + + *) Добавление: директива ip_hash в блоке upstream. + + *) Добавление: статус WAIT в строке "Auth-Status" в заголовка ответа + сервера аутентификации IMAP/POP3 прокси. + + *) Исправление: nginx не собирался на 64-битных платформах; ошибка + появилась в 0.4.14. + + Изменения в nginx 0.4.14 27.11.2006 *) Добавление: директива proxy_pass_error_message в IMAP/POP3 прокси. + *) Добавление: теперь configure определяет библиотеку PCRE на FreeBSD, + Linux и NetBSD. + *) Исправление: ngx_http_perl_module не работал с перлом, собранным с поддержкой потоков; ошибка появилась в 0.3.38. - *) Исправление: !!!!!!!!!! - - *) Исправление: !!!!!!!!!! + *) Исправление: ngx_http_perl_module не работал корректно, если перл + вызывался рекурсивно. *) Исправление: nginx игнорировал имя сервера в строке запроса. - *) Исправление: !!!!!!!!!! - - *) Исправление: !!!!!!!! + *) Исправление: если FastCGI сервер передавал много в stderr, то + рабочий процесс мог зациклиться. + + *) Исправление: при изменении системного времени переменная + $upstream_response_time могла быть отрицательной. *) Исправление: при использовании POP3 серверу аутентификации IMAP/POP3 - прокси не передавлся параметр Auth-Login-Attempt. + прокси не передавался параметр Auth-Login-Attempt. *) Исправление: при ошибке соединения с сервером аутентификации IMAP/POP3 прокси мог произойти segmentation fault. diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -255,6 +255,11 @@ if [ $HTTP_FLV = YES ]; then HTTP_SRCS="$HTTP_SRCS $HTTP_FLV_SRCS" fi +if [ $HTTP_UPSTREAM_IP_HASH = YES ]; then + HTTP_MODULES="$HTTP_MODULES $HTTP_UPSTREAM_IP_HASH_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_UPSTREAM_IP_HASH_SRCS" +fi + # STUB #USE_MD5=YES #HTTP_SRCS="$HTTP_SRCS $HTPP_CACHE_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -71,6 +71,7 @@ HTTP_MEMCACHED=YES HTTP_EMPTY_GIF=YES HTTP_BROWSER=YES HTTP_FLV=NO +HTTP_UPSTREAM_IP_HASH=YES # STUB HTTP_STUB_STATUS=NO @@ -170,6 +171,7 @@ do --without-http_memcached_module) HTTP_MEMCACHED=NO ;; --without-http_empty_gif_module) HTTP_EMPTY_GIF=NO ;; --without-http_browser_module) HTTP_BROWSER=NO ;; + --without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;; --with-http_perl_module) HTTP_PERL=YES ;; --with-perl_modules_path=*) NGX_PERL_MODULES="$value" ;; @@ -271,6 +273,8 @@ cat << END --without-http_memcached_module disable ngx_http_memcached_module --without-http_empty_gif_module disable ngx_http_empty_gif_module --without-http_browser_module disable ngx_http_browser_module + --without-http_upstream_ip_hash_module + disable ngx_http_upstream_ip_hash_module --with-http_perl_module enable ngx_http_perl_module --with-perl_modules_path=PATH set path to the perl modules diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -270,8 +270,8 @@ HTTP_DEPS="src/http/ngx_http.h \ src/http/ngx_http_variables.h \ src/http/ngx_http_script.h \ src/http/ngx_http_upstream.h \ - src/http/ngx_http_busy_lock.h \ - src/http/modules/ngx_http_log_module.h" + src/http/ngx_http_upstream_round_robin.h \ + src/http/ngx_http_busy_lock.h" HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_core_module.c \ @@ -286,6 +286,7 @@ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_variables.c \ src/http/ngx_http_script.c \ src/http/ngx_http_upstream.c \ + src/http/ngx_http_upstream_round_robin.c \ src/http/ngx_http_parse_time.c \ src/http/modules/ngx_http_static_module.c \ src/http/modules/ngx_http_index_module.c \ @@ -399,6 +400,10 @@ HTTP_FLV_MODULE=ngx_http_flv_module HTTP_FLV_SRCS=src/http/modules/ngx_http_flv_module.c +HTTP_UPSTREAM_IP_HASH_MODULE=ngx_http_upstream_ip_hash_module +HTTP_UPSTREAM_IP_HASH_SRCS=src/http/modules/ngx_http_upstream_ip_hash_module.c + + IMAP_INCS="src/imap" IMAP_DEPS="src/imap/ngx_imap.h" diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.4.14" +#define NGINX_VERSION "0.5.0" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -19,7 +19,6 @@ typedef struct ngx_open_file_s ngx_ope typedef struct ngx_command_s ngx_command_t; typedef struct ngx_file_s ngx_file_t; typedef struct ngx_event_s ngx_event_t; -typedef struct ngx_peers_s ngx_peers_t; typedef struct ngx_connection_s ngx_connection_t; typedef void (*ngx_event_handler_pt)(ngx_event_t *ev); 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 @@ -6,8 +6,6 @@ #include #include -#include -#include /* @@ -239,8 +237,6 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t #if (NGX_HAVE_UNIX_DOMAIN) - u->type = NGX_PARSE_URL_UNIX; - p += 5; len -= 5; @@ -271,8 +267,8 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t return NGX_ERROR; } - u->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); - if (u->peers == NULL) { + u->addrs = ngx_pcalloc(cf->pool, sizeof(ngx_peer_addr_t)); + if (u->addrs == NULL) { return NGX_ERROR; } @@ -281,16 +277,15 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t return NGX_ERROR; } - u->peers->number = 1; + u->naddrs = 1; saun->sun_family = AF_UNIX; (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1); - u->peers->peer[0].sockaddr = (struct sockaddr *) saun; - u->peers->peer[0].socklen = sizeof(struct sockaddr_un); - u->peers->peer[0].name.len = len + 5; - u->peers->peer[0].name.data = u->url.data; - u->peers->peer[0].uri_separator = ":"; + u->addrs[0].sockaddr = (struct sockaddr *) saun; + u->addrs[0].socklen = sizeof(struct sockaddr_un); + u->addrs[0].name.len = len + 5; + u->addrs[0].name.data = u->url.data; u->host_header.len = sizeof("localhost") - 1; u->host_header.data = (u_char *) "localhost"; @@ -310,8 +305,6 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t return NGX_ERROR; } - u->type = NGX_PARSE_URL_INET; - u->host.data = p; u->host_header.len = len; u->host_header.data = p; @@ -323,7 +316,7 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t u->host.len = i; if (!u->uri_part) { - u->port.len = &p[len] - u->port.data; + u->port.len = len - (i + 1); break; } } @@ -338,8 +331,8 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t } if (u->port.data == NULL) { - u->default_port = 1; - goto port; + u->no_port = 1; + goto no_port; } u->port.len = &p[i] - u->port.data; @@ -375,10 +368,10 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t port = ngx_atoi(p, len); if (port == NGX_ERROR) { - u->default_port = 1; u->host.len = len; + u->no_port = 1; - goto port; + goto no_port; } u->port.len = len; @@ -388,9 +381,10 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t u->portn = (in_port_t) port; -port: +no_port: if (u->listen) { + if (u->portn == 0) { if (u->default_portn == 0) { u->err = "no port"; @@ -435,13 +429,9 @@ port: return NGX_OK; } - if (u->default_port) { + if (u->no_port) { - if (u->upstream) { - return NGX_OK; - } - - if (u->default_portn == 0) { + if (u->default_portn == 0 && !u->upstream) { u->err = "no port"; return NGX_ERROR; } @@ -455,12 +445,8 @@ port: u->port.len = ngx_sprintf(u->port.data, "%d", u->portn) - u->port.data; - } else if (u->portn) { - if (u->portn == u->default_portn) { - u->default_port = 1; - } + } else if (u->portn == 0) { - } else { u->err = "no port"; return NGX_ERROR; } @@ -470,14 +456,11 @@ port: return NGX_ERROR; } - u->peers = ngx_inet_resolve_peer(cf, &u->host, u->portn); - - if (u->peers == NULL) { - return NGX_ERROR; + if (u->no_resolve) { + return NGX_OK; } - if (u->peers == NGX_CONF_ERROR) { - u->err = "host not found"; + if (ngx_inet_resolve_host(cf, u) != NGX_OK) { return NGX_ERROR; } @@ -485,23 +468,22 @@ port: } -ngx_peers_t * -ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, in_port_t port) +ngx_int_t +ngx_inet_resolve_host(ngx_conf_t *cf, ngx_url_t *u) { u_char *host; size_t len; in_addr_t in_addr; ngx_uint_t i; - ngx_peers_t *peers; struct hostent *h; struct sockaddr_in *sin; - host = ngx_palloc(cf->temp_pool, name->len + 1); + host = ngx_palloc(cf->temp_pool, u->host.len + 1); if (host == NULL) { - return NULL; + return NGX_ERROR; } - (void) ngx_cpystrn(host, name->data, name->len + 1); + (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); /* AF_INET only */ @@ -511,92 +493,88 @@ ngx_inet_resolve_peer(ngx_conf_t *cf, ng h = gethostbyname((char *) host); if (h == NULL || h->h_addr_list[0] == NULL) { - return NGX_CONF_ERROR; + u->err = "host not found"; + return NGX_ERROR; } - for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + if (u->one_addr == 0) { + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + + } else { + i = 1; + } /* MP: ngx_shared_palloc() */ - peers = ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); - if (peers == NULL) { - return NULL; + u->addrs = ngx_pcalloc(cf->pool, i * sizeof(ngx_peer_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; } - peers->number = i; + u->naddrs = i; for (i = 0; h->h_addr_list[i] != NULL; i++) { sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); if (sin == NULL) { - return NULL; + return NGX_ERROR; } sin->sin_family = AF_INET; - sin->sin_port = htons(port); + sin->sin_port = htons(u->portn); sin->sin_addr.s_addr = *(in_addr_t *) (h->h_addr_list[i]); - peers->peer[i].sockaddr = (struct sockaddr *) sin; - peers->peer[i].socklen = sizeof(struct sockaddr_in); + u->addrs[i].sockaddr = (struct sockaddr *) sin; + u->addrs[i].socklen = sizeof(struct sockaddr_in); len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; - peers->peer[i].name.data = ngx_palloc(cf->pool, len); - if (peers->peer[i].name.data == NULL) { - return NULL; + u->addrs[i].name.data = ngx_palloc(cf->pool, len); + if (u->addrs[i].name.data == NULL) { + return NGX_ERROR; } len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, - peers->peer[i].name.data, len); + u->addrs[i].name.data, len); - peers->peer[i].name.len = - ngx_sprintf(&peers->peer[i].name.data[len], - ":%d", port) - - peers->peer[i].name.data; - - peers->peer[i].uri_separator = ""; - - peers->peer[i].weight = NGX_CONF_UNSET_UINT; - peers->peer[i].max_fails = NGX_CONF_UNSET_UINT; - peers->peer[i].fail_timeout = NGX_CONF_UNSET; + u->addrs[i].name.len = ngx_sprintf(&u->addrs[i].name.data[len], + ":%d", u->portn) + - u->addrs[i].name.data; } } else { /* MP: ngx_shared_palloc() */ - peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { - return NULL; + u->addrs = ngx_pcalloc(cf->pool, sizeof(ngx_peer_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; } sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); if (sin == NULL) { - return NULL; + return NGX_ERROR; } - peers->number = 1; + u->naddrs = 1; sin->sin_family = AF_INET; - sin->sin_port = htons(port); + sin->sin_port = htons(u->portn); sin->sin_addr.s_addr = in_addr; - peers->peer[0].sockaddr = (struct sockaddr *) sin; - peers->peer[0].socklen = sizeof(struct sockaddr_in); + u->addrs[0].sockaddr = (struct sockaddr *) sin; + u->addrs[0].socklen = sizeof(struct sockaddr_in); - peers->peer[0].name.data = ngx_palloc(cf->pool, - name->len + sizeof(":65536") - 1); - if (peers->peer[0].name.data == NULL) { - return NULL; + u->addrs[0].name.data = ngx_palloc(cf->pool, + u->host.len + sizeof(":65536") - 1); + if (u->addrs[0].name.data == NULL) { + return NGX_ERROR; } - peers->peer[0].name.len = ngx_sprintf(peers->peer[0].name.data, "%V:%d", - name, port) - - peers->peer[0].name.data; - - peers->peer[0].uri_separator = ""; + u->addrs[0].name.len = ngx_sprintf(u->addrs[0].name.data, "%V:%d", + &u->host, u->portn) + - u->addrs[0].name.data; } - return peers; + return NGX_OK; } 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 @@ -12,80 +12,51 @@ #include -#define NGX_PARSE_URL_INET 1 -#define NGX_PARSE_URL_UNIX 2 - - typedef struct { - in_addr_t addr; - in_addr_t mask; + in_addr_t addr; + in_addr_t mask; } ngx_inet_cidr_t; -typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; - - ngx_str_t name; - char *uri_separator; - - ngx_uint_t current_weight; - ngx_uint_t weight; - - ngx_uint_t fails; - time_t accessed; - - ngx_uint_t max_fails; - time_t fail_timeout; - -#if (NGX_SSL) - ngx_ssl_session_t *ssl_session; -#endif -} ngx_peer_t; - - -struct ngx_peers_s { - ngx_uint_t current; - - ngx_uint_t number; - ngx_uint_t last_cached; - - /* ngx_mutex_t *mutex; */ - ngx_connection_t **cached; - - ngx_peer_t peer[1]; -}; - - typedef union { - in_addr_t in_addr; + in_addr_t in_addr; } ngx_url_addr_t; typedef struct { - ngx_int_t type; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; +} ngx_peer_addr_t; - ngx_peers_t *peers; - ngx_str_t url; - ngx_str_t host; - ngx_str_t host_header; - ngx_str_t port; - ngx_str_t uri; +typedef struct { + ngx_int_t type; + + ngx_str_t url; + ngx_str_t host; + ngx_str_t host_header; + ngx_str_t port; + ngx_str_t uri; - in_port_t portn; - in_port_t default_portn; + in_port_t portn; + in_port_t default_portn; - unsigned listen:1; - unsigned uri_part:1; - unsigned upstream:1; + unsigned listen:1; + unsigned uri_part:1; + unsigned upstream:1; + unsigned no_resolve:1; + unsigned one_addr:1; - unsigned default_port:1; - unsigned wildcard:1; + unsigned wildcard:1; + unsigned no_port:1; + + ngx_url_addr_t addr; - ngx_url_addr_t addr; + ngx_peer_addr_t *addrs; + ngx_uint_t naddrs; - char *err; + char *err; } ngx_url_t; @@ -93,8 +64,8 @@ size_t ngx_sock_ntop(int family, struct size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u); -ngx_peers_t *ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, - in_port_t port); +ngx_int_t ngx_inet_resolve_host(ngx_conf_t *cf, ngx_url_t *u); + #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/src/core/ngx_slab.c b/src/core/ngx_slab.c --- a/src/core/ngx_slab.c +++ b/src/core/ngx_slab.c @@ -149,8 +149,8 @@ void * ngx_slab_alloc(ngx_slab_pool_t *pool, size_t size) { size_t s; - uintptr_t p, mask, *bitmap; - ngx_uint_t i, n, m, slot, shift, map; + uintptr_t p, n, m, mask, *bitmap; + ngx_uint_t i, slot, shift, map; ngx_slab_page_t *page, *prev, *slots; ngx_shmtx_lock(&pool->mutex); @@ -287,7 +287,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, si do { if ((page->slab & NGX_SLAB_MAP_MASK) != mask) { - for (m = 1 << NGX_SLAB_MAP_SHIFT, i = 0; + for (m = (uintptr_t) 1 << NGX_SLAB_MAP_SHIFT, i = 0; m & mask; m <<= 1, i++) { @@ -369,7 +369,7 @@ ngx_slab_alloc(ngx_slab_pool_t *pool, si } else { /* size < ngx_pagesize */ - page->slab = (1 << NGX_SLAB_MAP_SHIFT) | shift; + page->slab = ((uintptr_t) 1 << NGX_SLAB_MAP_SHIFT) | shift; page->next = &slots[slot]; page->prev = (uintptr_t) &slots[slot] | NGX_SLAB_BIG; 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 @@ -14,145 +14,21 @@ ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc) { int rc; - ngx_uint_t level, i; u_int event; - time_t now; ngx_err_t err; - ngx_peer_t *peer; + ngx_uint_t level; ngx_socket_t s; ngx_event_t *rev, *wev; ngx_connection_t *c; - now = ngx_time(); - - /* ngx_lock_mutex(pc->peers->mutex); */ - - if (pc->peers->last_cached) { - - /* cached connection */ - - c = pc->peers->cached[pc->peers->last_cached]; - pc->peers->last_cached--; - - /* ngx_unlock_mutex(pc->peers->mutex); */ - -#if (NGX_THREADS) - c->read->lock = c->read->own_lock; - c->write->lock = c->write->own_lock; -#endif - - pc->connection = c; - pc->cached = 1; - - return NGX_OK; + rc = pc->get(pc, pc->data); + if (rc != NGX_OK) { + return rc; } - pc->cached = 0; - pc->connection = NULL; - - if (pc->peers->number == 1) { - peer = &pc->peers->peer[0]; - - } else { - - /* there are several peers */ - - if (pc->tries == pc->peers->number) { - - /* it's a first try - get a current peer */ - - for ( ;; ) { - pc->cur_peer = pc->peers->current; - - peer = &pc->peers->peer[pc->cur_peer]; - - if (peer->max_fails == 0 || peer->fails <= peer->max_fails) { - break; - } - - if (now - peer->accessed > peer->fail_timeout) { - peer->fails = 0; - break; - } - - pc->peers->current++; - - if (pc->peers->current >= pc->peers->number) { - pc->peers->current = 0; - } - - pc->tries--; - - if (pc->tries) { - continue; - } - - goto failed; - } - - peer->current_weight--; - - if (peer->current_weight == 0) { - peer->current_weight = peer->weight; - - pc->peers->current++; + s = ngx_socket(pc->sockaddr->sa_family, SOCK_STREAM, 0); - if (pc->peers->current >= pc->peers->number) { - pc->peers->current = 0; - } - } - - } else { - for ( ;; ) { - peer = &pc->peers->peer[pc->cur_peer]; - - if (peer->max_fails == 0 || peer->fails <= peer->max_fails) { - break; - } - - if (now - peer->accessed > peer->fail_timeout) { - peer->fails = 0; - break; - } - - pc->cur_peer++; - - if (pc->cur_peer >= pc->peers->number) { - pc->cur_peer = 0; - } - - pc->tries--; - - if (pc->tries) { - continue; - } - - goto failed; - } - - peer->current_weight--; - - if (peer->current_weight == 0) { - peer->current_weight = peer->weight; - - if (pc->cur_peer == pc->peers->current) { - pc->peers->current++; - - if (pc->peers->current >= pc->peers->number) { - pc->peers->current = 0; - } - } - } - } - } - - /* ngx_unlock_mutex(pc->peers->mutex); */ - - - s = ngx_socket(peer->sockaddr->sa_family, SOCK_STREAM, 0); - - ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "socket %d", s); + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, 0, "socket %d", s); if (s == -1) { ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno, @@ -211,7 +87,7 @@ ngx_event_connect_peer(ngx_peer_connecti c->log_error = pc->log_error; - if (peer->sockaddr->sa_family != AF_INET) { + if (pc->sockaddr->sa_family != AF_INET) { c->tcp_nopush = NGX_TCP_NOPUSH_DISABLED; c->tcp_nodelay = NGX_TCP_NODELAY_DISABLED; @@ -254,9 +130,9 @@ ngx_event_connect_peer(ngx_peer_connecti } ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0, - "connect to %V, fd:%d #%d", &peer->name, s, c->number); + "connect to %V, fd:%d #%d", pc->name, s, c->number); - rc = connect(s, peer->sockaddr, peer->socklen); + rc = connect(s, pc->sockaddr, pc->socklen); if (rc == -1) { err = ngx_socket_errno; @@ -272,7 +148,7 @@ ngx_event_connect_peer(ngx_peer_connecti } ngx_log_error(level, c->log, err, "connect() to %V failed", - &peer->name); + pc->name); return NGX_DECLINED; } @@ -352,51 +228,11 @@ ngx_event_connect_peer(ngx_peer_connecti wev->ready = 1; return NGX_OK; - -failed: - - /* all peers failed, mark them as live for quick recovery */ - - for (i = 0; i < pc->peers->number; i++) { - pc->peers->peer[i].fails = 0; - } - - /* ngx_unlock_mutex(pc->peers->mutex); */ - - return NGX_BUSY; } -void -ngx_event_connect_peer_failed(ngx_peer_connection_t *pc, ngx_uint_t down) +ngx_int_t +ngx_event_get_peer(ngx_peer_connection_t *pc, void *data) { - time_t now; - ngx_peer_t *peer; - - if (down) { - now = ngx_time(); - - /* ngx_lock_mutex(pc->peers->mutex); */ - - peer = &pc->peers->peer[pc->cur_peer]; - - peer->fails++; - peer->accessed = now; - - if (peer->current_weight > 1) { - peer->current_weight /= 2; - } - - /* ngx_unlock_mutex(pc->peers->mutex); */ - } - - pc->cur_peer++; - - if (pc->cur_peer >= pc->peers->number) { - pc->cur_peer = 0; - } - - if (pc->tries) { - pc->tries--; - } + return NGX_OK; } 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 @@ -13,27 +13,56 @@ #include -typedef struct { - ngx_peers_t *peers; - ngx_uint_t cur_peer; - ngx_uint_t tries; +#define NGX_PEER_KEEPALIVE 1 +#define NGX_PEER_NEXT 2 +#define NGX_PEER_FAILED 4 + + +typedef struct ngx_peer_connection_s ngx_peer_connection_t; + +typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc, + void *data); +#if (NGX_SSL) +typedef void (*ngx_event_save_peer_pt)(ngx_peer_connection_t *pc, void *data); +#endif +typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state); + - ngx_connection_t *connection; -#if (NGX_THREADS) - ngx_atomic_t *lock; +struct ngx_peer_connection_s { + ngx_connection_t *connection; + + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t *name; + + ngx_uint_t tries; + + ngx_event_get_peer_pt get; + ngx_event_free_peer_pt free; + void *data; + +#if (NGX_SSL) + ngx_ssl_session_t *ssl_session; + ngx_event_save_peer_pt save_session; #endif - int rcvbuf; +#if (NGX_THREADS) + ngx_atomic_t *lock; +#endif - ngx_log_t *log; + int rcvbuf; - unsigned cached:1; - unsigned log_error:2; /* ngx_connection_log_error_e */ -} ngx_peer_connection_t; + ngx_log_t *log; + + unsigned cached:1; + unsigned log_error:2; /* ngx_connection_log_error_e */ +}; ngx_int_t ngx_event_connect_peer(ngx_peer_connection_t *pc); -void ngx_event_connect_peer_failed(ngx_peer_connection_t *pc, ngx_uint_t down); +ngx_int_t ngx_event_get_peer(ngx_peer_connection_t *pc, void *data); + #endif /* _NGX_EVENT_CONNECT_H_INCLUDED_ */ 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 @@ -13,9 +13,6 @@ typedef struct { ngx_http_upstream_conf_t upstream; - ngx_http_upstream_srv_conf_t *upstream_peers; - ngx_peers_t *peers0; - ngx_str_t index; ngx_array_t *flushes; @@ -121,6 +118,11 @@ static char *ngx_http_fastcgi_pass(ngx_c static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + static ngx_http_fastcgi_request_start_t ngx_http_fastcgi_request_start = { { 1, /* version */ @@ -310,16 +312,16 @@ static ngx_command_t ngx_http_fastcgi_c { ngx_string("fastcgi_upstream_max_fails"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.max_fails), + ngx_http_fastcgi_upstream_max_fails_unsupported, + 0, + 0, NULL }, { ngx_string("fastcgi_upstream_fail_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.fail_timeout), + ngx_http_fastcgi_upstream_fail_timeout_unsupported, + 0, + 0, NULL }, { ngx_string("fastcgi_param"), @@ -411,8 +413,6 @@ ngx_http_fastcgi_handler(ngx_http_reques u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = flcf->upstream_peers->peers; - u->peer.tries = flcf->upstream_peers->peers->number; #if (NGX_THREADS) u->peer.lock = &r->connection->lock; #endif @@ -1547,9 +1547,6 @@ ngx_http_fastcgi_create_loc_conf(ngx_con conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE; - conf->upstream.max_fails = NGX_CONF_UNSET_UINT; - conf->upstream.fail_timeout = NGX_CONF_UNSET; - conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; @@ -1573,7 +1570,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf uintptr_t *code; ngx_str_t *header; ngx_uint_t i, j; - ngx_peer_t *peer; ngx_array_t hide_headers; ngx_keyval_t *src; ngx_hash_key_t *hk; @@ -1707,25 +1703,6 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf |NGX_HTTP_UPSTREAM_FT_OFF; } - ngx_conf_merge_uint_value(conf->upstream.max_fails, - prev->upstream.max_fails, 1); - - ngx_conf_merge_sec_value(conf->upstream.fail_timeout, - prev->upstream.fail_timeout, 10); - - if (conf->upstream_peers) { - peer = conf->upstream_peers->peers->peer; - for (i = 0; i < conf->upstream_peers->peers->number; i++) { - ngx_conf_init_uint_value(peer[i].weight, 1); - peer[i].current_weight = peer[i].weight; - ngx_conf_init_uint_value(peer[i].max_fails, - conf->upstream.max_fails); - ngx_conf_init_value(peer[i].fail_timeout, - conf->upstream.fail_timeout); - } - - } - ngx_conf_merge_path_value(conf->upstream.temp_path, prev->upstream.temp_path, NGX_HTTP_FASTCGI_TEMP_PATH, 1, 2, 0, @@ -1844,8 +1821,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf peers: - if (conf->upstream_peers == NULL) { - conf->upstream_peers = prev->upstream_peers; + if (conf->upstream.upstream == NULL) { + conf->upstream.upstream = prev->upstream.upstream; conf->upstream.schema = prev->upstream.schema; } @@ -2033,10 +2010,10 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[1]; - u.upstream = 1; - - lcf->upstream_peers = ngx_http_upstream_add(cf, &u); - if (lcf->upstream_peers == NULL) { + u.no_resolve = 1; + + lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); + if (lcf->upstream.upstream == NULL) { return NGX_CONF_ERROR; } @@ -2084,3 +2061,29 @@ ngx_http_fastcgi_lowat_check(ngx_conf_t return NGX_CONF_OK; } + + +static char * +ngx_http_fastcgi_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_upstream_max_fails\" is not supported, " + "use the \"max_fails\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_fastcgi_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"fastcgi_upstream_fail_timeout\" is not supported, " + "use the \"fail_timeout\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + 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 @@ -76,9 +76,6 @@ static void *ngx_http_gzip_filter_alloc( static void ngx_http_gzip_filter_free(void *opaque, void *address); static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx); -static u_char *ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_gzip_ratio_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -230,14 +227,6 @@ ngx_module_t ngx_http_gzip_filter_modul }; -static ngx_http_log_op_name_t ngx_http_gzip_log_fmt_ops[] = { - { ngx_string("gzip_ratio"), NGX_INT32_LEN + 3, - NULL, NULL, ngx_http_gzip_log_ratio }, - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - - static u_char gzheader[10] = { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 }; #if (NGX_HAVE_LITTLE_ENDIAN && NGX_HAVE_NONALIGNED) @@ -907,39 +896,6 @@ ngx_http_gzip_filter_free(void *opaque, } -static u_char * -ngx_http_gzip_log_ratio(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_uint_t zint, zfrac; - ngx_http_gzip_ctx_t *ctx; - - ctx = ngx_http_get_module_ctx(r, ngx_http_gzip_filter_module); - - if (ctx == NULL || ctx->zout == 0) { - *buf = '-'; - return buf + 1; - } - - zint = (ngx_uint_t) (ctx->zin / ctx->zout); - zfrac = (ngx_uint_t) ((ctx->zin * 100 / ctx->zout) % 100); - - if ((ctx->zin * 1000 / ctx->zout) % 10 > 4) { - - /* the rounding, e.g., 2.125 to 2.13 */ - - zfrac++; - - if (zfrac > 99) { - zint++; - zfrac = 0; - } - } - - return ngx_sprintf(buf, "%ui.%02ui", zint, zfrac); -} - - static void ngx_http_gzip_error(ngx_http_gzip_ctx_t *ctx) { @@ -961,8 +917,7 @@ ngx_http_gzip_error(ngx_http_gzip_ctx_t static ngx_int_t ngx_http_gzip_add_variables(ngx_conf_t *cf) { - ngx_http_variable_t *var; - ngx_http_log_op_name_t *op; + ngx_http_variable_t *var; var = ngx_http_add_variable(cf, &ngx_http_gzip_ratio, NGX_HTTP_VAR_NOHASH); if (var == NULL) { @@ -971,17 +926,6 @@ ngx_http_gzip_add_variables(ngx_conf_t * var->get_handler = ngx_http_gzip_ratio_variable; - for (op = ngx_http_gzip_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - for (op = ngx_http_log_fmt_ops; op->run; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->run; - } - } - - op->run = (ngx_http_log_op_run_pt) ngx_http_gzip_log_fmt_ops; - return NGX_OK; } 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 @@ -10,6 +10,22 @@ #include +typedef struct ngx_http_log_op_s ngx_http_log_op_t; + +typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); + +typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, + uintptr_t data); + + +struct ngx_http_log_op_s { + size_t len; + ngx_http_log_op_getlen_pt getlen; + ngx_http_log_op_run_pt run; + uintptr_t data; +}; + typedef struct { ngx_str_t name; @@ -43,8 +59,6 @@ typedef struct { } ngx_http_log_var_t; -static u_char *ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); static u_char *ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_log_pipe(ngx_http_request_t *r, u_char *buf, @@ -64,41 +78,6 @@ static u_char *ngx_http_log_body_bytes_s static u_char *ngx_http_log_request_length(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); -static size_t ngx_http_log_request_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_request(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -static ngx_int_t ngx_http_log_header_in_compile(ngx_conf_t *cf, - ngx_http_log_op_t *op, ngx_str_t *value); -static size_t ngx_http_log_header_in_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static size_t ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_in(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static ngx_int_t ngx_http_log_header_out_compile(ngx_conf_t *cf, - ngx_http_log_op_t *op, ngx_str_t *value); -static size_t ngx_http_log_header_out_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static size_t ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_log_unknown_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static u_char *ngx_http_log_connection_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); -static u_char *ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - -static ngx_table_elt_t *ngx_http_log_unknown_header(ngx_list_t *headers, - ngx_str_t *value); - static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, ngx_str_t *value); static size_t ngx_http_log_variable_getlen(ngx_http_request_t *r, @@ -107,7 +86,6 @@ static u_char *ngx_http_log_variable(ngx ngx_http_log_op_t *op); -static ngx_int_t ngx_http_log_set_formats(ngx_conf_t *cf); static void *ngx_http_log_create_main_conf(ngx_conf_t *cf); static void *ngx_http_log_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_log_merge_loc_conf(ngx_conf_t *cf, void *parent, @@ -143,7 +121,7 @@ static ngx_command_t ngx_http_log_comma static ngx_http_module_t ngx_http_log_module_ctx = { - ngx_http_log_set_formats, /* preconfiguration */ + NULL, /* preconfiguration */ ngx_http_log_init, /* postconfiguration */ ngx_http_log_create_main_conf, /* create main configuration */ @@ -202,39 +180,6 @@ static ngx_http_log_var_t ngx_http_log_ }; -ngx_http_log_op_name_t ngx_http_log_fmt_ops[] = { - { ngx_string("addr"), INET_ADDRSTRLEN - 1, NULL, NULL, ngx_http_log_addr }, - { ngx_string("conn"), NGX_ATOMIC_T_LEN, NULL, NULL, - ngx_http_log_connection }, - { ngx_string("pipe"), 1, NULL, NULL, ngx_http_log_pipe }, - { ngx_string("time"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, - NULL, NULL, ngx_http_log_time }, - { ngx_string("msec"), NGX_TIME_T_LEN + 4, NULL, NULL, ngx_http_log_msec }, - { ngx_string("request_time"), NGX_TIME_T_LEN, NULL, NULL, - ngx_http_log_request_time }, - { ngx_string("status"), 3, NULL, NULL, ngx_http_log_status }, - { ngx_string("length"), NGX_OFF_T_LEN, - NULL, NULL, ngx_http_log_bytes_sent }, - { ngx_string("apache_length"), NGX_OFF_T_LEN, - NULL, NULL, ngx_http_log_body_bytes_sent }, - { ngx_string("request_length"), NGX_SIZE_T_LEN, - NULL, NULL, ngx_http_log_request_length }, - - { ngx_string("request"), 0, NULL, - ngx_http_log_request_getlen, - ngx_http_log_request }, - - { ngx_string("i"), 0, ngx_http_log_header_in_compile, NULL, - ngx_http_log_header_in }, - { ngx_string("o"), 0, ngx_http_log_header_out_compile, NULL, - ngx_http_log_header_out }, - { ngx_string("v"), 0, ngx_http_log_variable_compile, NULL, - ngx_http_log_variable }, - - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - ngx_int_t ngx_http_log_handler(ngx_http_request_t *r) { @@ -367,14 +312,6 @@ ngx_http_log_copy_long(ngx_http_request_ static u_char * -ngx_http_log_addr(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, r->connection->addr_text.data, - r->connection->addr_text.len); -} - - -static u_char * ngx_http_log_connection(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) { @@ -426,20 +363,6 @@ ngx_http_log_request_time(ngx_http_reque } -static size_t -ngx_http_log_request_getlen(ngx_http_request_t *r, uintptr_t data) -{ - return r->request_line.len; -} - - -static u_char * -ngx_http_log_request(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) -{ - return ngx_cpymem(buf, r->request_line.data, r->request_line.len); -} - - static u_char * ngx_http_log_status(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) { @@ -483,363 +406,6 @@ ngx_http_log_request_length(ngx_http_req static ngx_int_t -ngx_http_log_header_in_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, - ngx_str_t *value) -{ - ngx_uint_t i; - - op->len = 0; - - for (i = 0; ngx_http_headers_in[i].name.len != 0; i++) { - - if (ngx_http_headers_in[i].name.len != value->len) { - continue; - } - - /* STUB: "Cookie" speacial handling */ - if (ngx_http_headers_in[i].offset == 0) { - continue; - } - - if (ngx_strncasecmp(ngx_http_headers_in[i].name.data, value->data, - value->len) == 0) - { - op->getlen = ngx_http_log_header_in_getlen; - op->run = ngx_http_log_header_in; - op->data = ngx_http_headers_in[i].offset; - - return NGX_OK; - } - } - - op->getlen = ngx_http_log_unknown_header_in_getlen; - op->run = ngx_http_log_unknown_header_in; - op->data = (uintptr_t) value; - - return NGX_OK; -} - - -static size_t -ngx_http_log_header_in_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_in + op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static size_t -ngx_http_log_unknown_header_in_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_in.headers, (ngx_str_t *) data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_unknown_header_in(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_in.headers, - (ngx_str_t *) op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_int_t -ngx_http_log_header_out_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, - ngx_str_t *value) -{ - ngx_uint_t i; - - op->len = 0; - - for (i = 0; ngx_http_headers_out[i].name.len != 0; i++) { - - if (ngx_http_headers_out[i].name.len != value->len) { - continue; - } - - if (ngx_strncasecmp(ngx_http_headers_out[i].name.data, value->data, - value->len) == 0) - { - op->getlen = ngx_http_log_header_out_getlen; - op->run = ngx_http_log_header_out; - op->data = ngx_http_headers_out[i].offset; - - return NGX_OK; - } - } - - if (value->len == sizeof("Connection") - 1 - && ngx_strncasecmp(value->data, "Connection", value->len) == 0) - { - op->len = sizeof("keep-alive") - 1; - op->getlen = NULL; - op->run = ngx_http_log_connection_header_out; - op->data = 0; - return NGX_OK; - } - - if (value->len == sizeof("Transfer-Encoding") - 1 - && ngx_strncasecmp(value->data, "Transfer-Encoding", value->len) == 0) - { - op->len = sizeof("chunked") - 1; - op->getlen = NULL; - op->run = ngx_http_log_transfer_encoding_header_out; - op->data = 0; - return NGX_OK; - } - - op->getlen = ngx_http_log_unknown_header_out_getlen; - op->run = ngx_http_log_unknown_header_out; - op->data = (uintptr_t) value; - - return NGX_OK; -} - - -static size_t -ngx_http_log_header_out_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + data); - - if (h) { - return h->value.len; - } - - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter, - * but we do not set up their pointers in the filter, - * because they are too seldom needed to be logged. - */ - - if (data == offsetof(ngx_http_headers_out_t, date)) { - return ngx_cached_http_time.len; - } - - if (data == offsetof(ngx_http_headers_out_t, server)) { - return (sizeof(NGINX_VER) - 1); - } - - if (data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - return 1; - } - - return NGX_OFF_T_LEN; - } - - if (data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - return 1; - } - - return sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; - } - - return 1; -} - - -static u_char * -ngx_http_log_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = *(ngx_table_elt_t **) ((char *) &r->headers_out + op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - /* - * No header pointer was found. - * However, some headers: "Date", "Server", "Content-Length", - * and "Last-Modified" have a special handling in the header filter, - * but we do not set up their pointers in the filter, - * because they are too seldom needed to be logged. - */ - - if (op->data == offsetof(ngx_http_headers_out_t, date)) { - return ngx_cpymem(buf, ngx_cached_http_time.data, - ngx_cached_http_time.len); - } - - if (op->data == offsetof(ngx_http_headers_out_t, server)) { - return ngx_cpymem(buf, NGINX_VER, sizeof(NGINX_VER) - 1); - } - - if (op->data == offsetof(ngx_http_headers_out_t, content_length)) { - if (r->headers_out.content_length_n == -1) { - *buf = '-'; - - return buf + 1; - } - - return ngx_sprintf(buf, "%O", r->headers_out.content_length_n); - } - - if (op->data == offsetof(ngx_http_headers_out_t, last_modified)) { - if (r->headers_out.last_modified_time == -1) { - *buf = '-'; - - return buf + 1; - } - - return ngx_http_time(buf, r->headers_out.last_modified_time); - } - - *buf = '-'; - - return buf + 1; -} - - -static size_t -ngx_http_log_unknown_header_out_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_out.headers, - (ngx_str_t *) data); - - if (h) { - return h->value.len; - } - - return 1; -} - - -static u_char * -ngx_http_log_unknown_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_table_elt_t *h; - - h = ngx_http_log_unknown_header(&r->headers_out.headers, - (ngx_str_t *) op->data); - - if (h) { - return ngx_cpymem(buf, h->value.data, h->value.len); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_table_elt_t * -ngx_http_log_unknown_header(ngx_list_t *headers, ngx_str_t *value) -{ - ngx_uint_t i; - ngx_list_part_t *part; - ngx_table_elt_t *h; - - part = &headers->part; - h = part->elts; - - for (i = 0; /* void */; i++) { - - if (i >= part->nelts) { - if (part->next == NULL) { - break; - } - - part = part->next; - h = part->elts; - i = 0; - } - - if (h[i].key.len != value->len) { - continue; - } - - if (ngx_strncasecmp(h[i].key.data, value->data, value->len) == 0) { - return &h[i]; - } - } - - return NULL; -} - - -static u_char * -ngx_http_log_connection_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - if (r->keepalive) { - return ngx_cpymem(buf, "keep-alive", sizeof("keep-alive") - 1); - - } else { - return ngx_cpymem(buf, "close", sizeof("close") - 1); - } -} - - -static u_char * -ngx_http_log_transfer_encoding_header_out(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - if (r->chunked) { - return ngx_cpymem(buf, "chunked", sizeof("chunked") - 1); - } - - *buf = '-'; - - return buf + 1; -} - - -static ngx_int_t ngx_http_log_variable_compile(ngx_conf_t *cf, ngx_http_log_op_t *op, ngx_str_t *value) { @@ -890,18 +456,6 @@ ngx_http_log_variable(ngx_http_request_t } -static ngx_int_t -ngx_http_log_set_formats(ngx_conf_t *cf) -{ - ngx_http_log_op_name_t *op; - - for (op = ngx_http_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - return NGX_OK; -} - - static void * ngx_http_log_create_main_conf(ngx_conf_t *cf) { @@ -1152,20 +706,36 @@ static char * ngx_http_log_compile_format(ngx_conf_t *cf, ngx_array_t *ops, ngx_array_t *args, ngx_uint_t s) { - u_char *data, *p, *fname, *arg_data, ch; - size_t i, len, fname_len, arg_len; - ngx_str_t *value, var, *a; - ngx_uint_t bracket; - ngx_http_log_op_t *op; - ngx_http_log_var_t *v; - ngx_http_log_op_name_t *name; - static ngx_uint_t warn; + u_char *data, *p, ch; + size_t i, len; + ngx_str_t *value, var; + ngx_uint_t bracket; + ngx_http_log_op_t *op; + ngx_http_log_var_t *v; value = args->elts; - arg_data = NULL; for ( /* void */ ; s < args->nelts; s++) { + for (i = 0; i < value[s].len; i++) { + if (value[s].data[i] != '%') { + continue; + } + + ch = value[s].data[i + 1]; + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || ch == '{') + { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the parameters in the \"%%name\" form are not supported, " + "use the \"$variable\" instead"); + + return NGX_CONF_ERROR; + } + } + i = 0; while (i < value[s].len) { @@ -1177,112 +747,7 @@ ngx_http_log_compile_format(ngx_conf_t * data = &value[s].data[i]; - if (value[s].data[i] == '%') { - i++; - - if (i == value[s].len) { - goto invalid; - } - - if (value[s].data[i] == '{') { - i++; - - arg_data = &value[s].data[i]; - - while (i < value[s].len && value[s].data[i] != '}') { - i++; - } - - arg_len = &value[s].data[i] - arg_data; - - if (i == value[s].len || arg_len == 0) { - goto invalid; - } - - i++; - - } else { - arg_len = 0; - } - - if (warn == 0) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "the parameters in the \"%%name\" form are deprecated, " - "use the \"$variable\" instead"); - warn = 1; - } - - fname = &value[s].data[i]; - - while (i < value[s].len - && ((value[s].data[i] >= 'a' && value[s].data[i] <= 'z') - || value[s].data[i] == '_')) - { - i++; - } - - fname_len = &value[s].data[i] - fname; - - if (fname_len == 0) { - goto invalid; - } - - for (name = ngx_http_log_fmt_ops; name->run; name++) { - if (name->name.len == 0) { - name = (ngx_http_log_op_name_t *) name->run; - } - - if (name->name.len == fname_len - && ngx_strncmp(name->name.data, fname, fname_len) == 0) - { - if (name->compile == NULL) { - if (arg_len) { - fname[fname_len] = '\0'; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%s\" must not have argument", - data); - return NGX_CONF_ERROR; - } - - op->len = name->len; - op->getlen = name->getlen; - op->run = name->run; - op->data = 0; - - break; - } - - if (arg_len == 0) { - fname[fname_len] = '\0'; - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"%s\" requires argument", - data); - return NGX_CONF_ERROR; - } - - a = ngx_palloc(cf->pool, sizeof(ngx_str_t)); - if (a == NULL) { - return NGX_CONF_ERROR; - } - - a->len = arg_len; - a->data = arg_data; - - if (name->compile(cf, op, a) == NGX_ERROR) { - return NGX_CONF_ERROR; - } - - break; - } - } - - if (name->name.len == 0) { - goto invalid; - } - - continue; - - } else if (value[s].data[i] == '$') { + if (value[s].data[i] == '$') { if (++i == value[s].len) { goto invalid; @@ -1364,10 +829,7 @@ ngx_http_log_compile_format(ngx_conf_t * i++; - while (i < value[s].len - && value[s].data[i] != '$' - && value[s].data[i] != '%') - { + while (i < value[s].len && value[s].data[i] != '$') { i++; } diff --git a/src/http/modules/ngx_http_log_module.h b/src/http/modules/ngx_http_log_module.h deleted file mode 100644 --- a/src/http/modules/ngx_http_log_module.h +++ /dev/null @@ -1,48 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_HTTP_LOG_MODULE_H_INCLUDED_ -#define _NGX_HTTP_LOG_MODULE_H_INCLUDED_ - - -#include -#include -#include - - -typedef struct ngx_http_log_op_s ngx_http_log_op_t; - -typedef u_char *(*ngx_http_log_op_run_pt) (ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - -typedef size_t (*ngx_http_log_op_getlen_pt) (ngx_http_request_t *r, - uintptr_t data); - -typedef ngx_int_t (*ngx_http_log_op_compile_pt) (ngx_conf_t *cf, - ngx_http_log_op_t *op, ngx_str_t *value); - - -struct ngx_http_log_op_s { - size_t len; - ngx_http_log_op_getlen_pt getlen; - ngx_http_log_op_run_pt run; - uintptr_t data; -}; - - -typedef struct { - ngx_str_t name; - size_t len; - ngx_http_log_op_compile_pt compile; - ngx_http_log_op_getlen_pt getlen; - ngx_http_log_op_run_pt run; -} ngx_http_log_op_name_t; - - -extern ngx_http_log_op_name_t ngx_http_log_fmt_ops[]; - - -#endif /* _NGX_HTTP_LOG_MODULE_H_INCLUDED_ */ 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 @@ -12,7 +12,6 @@ typedef struct { ngx_http_upstream_conf_t upstream; - ngx_peers_t *peers; } ngx_http_memcached_loc_conf_t; @@ -39,6 +38,11 @@ static char *ngx_http_memcached_merge_lo static char *ngx_http_memcached_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + static ngx_conf_bitmask_t ngx_http_memcached_next_upstream_masks[] = { { ngx_string("error"), NGX_HTTP_UPSTREAM_FT_ERROR }, @@ -96,16 +100,16 @@ static ngx_command_t ngx_http_memcached { ngx_string("memcached_upstream_max_fails"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_memcached_loc_conf_t, upstream.max_fails), + ngx_http_memcached_upstream_max_fails_unsupported, + 0, + 0, NULL }, { ngx_string("memcached_upstream_fail_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_memcached_loc_conf_t, upstream.fail_timeout), + ngx_http_memcached_upstream_fail_timeout_unsupported, + 0, + 0, NULL }, ngx_null_command @@ -178,8 +182,6 @@ ngx_http_memcached_handler(ngx_http_requ u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = mlcf->peers; - u->peer.tries = mlcf->peers->number; #if (NGX_THREADS) u->peer.lock = &r->connection->lock; #endif @@ -511,13 +513,8 @@ ngx_http_memcached_create_loc_conf(ngx_c conf->upstream.buffer_size = NGX_CONF_UNSET_SIZE; - conf->upstream.max_fails = NGX_CONF_UNSET_UINT; - conf->upstream.fail_timeout = NGX_CONF_UNSET; - - /* "fastcgi_cyclic_temp_file" is disabled */ + /* the hardcoded values */ conf->upstream.cyclic_temp_file = 0; - - /* the hardcoded values */ conf->upstream.buffering = 0; conf->upstream.ignore_client_abort = 0; conf->upstream.send_lowat = 0; @@ -540,8 +537,6 @@ ngx_http_memcached_merge_loc_conf(ngx_co ngx_http_memcached_loc_conf_t *prev = parent; ngx_http_memcached_loc_conf_t *conf = child; - ngx_uint_t i; - ngx_conf_merge_msec_value(conf->upstream.connect_timeout, prev->upstream.connect_timeout, 60000); @@ -566,20 +561,6 @@ ngx_http_memcached_merge_loc_conf(ngx_co |NGX_HTTP_UPSTREAM_FT_OFF; } - ngx_conf_merge_uint_value(conf->upstream.max_fails, - prev->upstream.max_fails, 1); - - ngx_conf_merge_sec_value(conf->upstream.fail_timeout, - prev->upstream.fail_timeout, 10); - - if (conf->peers && conf->peers->number > 1) { - for (i = 0; i < conf->peers->number; i++) { - conf->peers->peer[i].weight = 1; - conf->peers->peer[i].max_fails = conf->upstream.max_fails; - conf->peers->peer[i].fail_timeout = conf->upstream.fail_timeout; - } - } - return NGX_CONF_OK; } @@ -602,16 +583,14 @@ ngx_http_memcached_pass(ngx_conf_t *cf, ngx_memzero(&u, sizeof(ngx_url_t)); u.url = value[1]; - u.uri_part = 1; + u.no_resolve = 1; + /* u.uri_part = 1; may be used as namespace */ - if (ngx_parse_url(cf, &u) != NGX_OK) { - if (u.err) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "%s in \"%V\"", u.err, &u.url); - } + lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); + if (lcf->upstream.upstream == NULL) { + return NGX_CONF_ERROR; } - lcf->peers = u.peers; lcf->upstream.schema.len = sizeof("memcached://") - 1; lcf->upstream.schema.data = (u_char *) "memcached://"; @@ -627,3 +606,29 @@ ngx_http_memcached_pass(ngx_conf_t *cf, return NGX_CONF_OK; } + + +static char * +ngx_http_memcached_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"memcached_upstream_max_fails\" is not supported, " + "use the \"max_fails\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_memcached_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"memcached_upstream_fail_timeout\" is not supported, " + "use the \"fail_timeout\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + return NGX_CONF_ERROR; +} 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 @@ -35,8 +35,6 @@ struct ngx_http_proxy_redirect_s { typedef struct { ngx_http_upstream_conf_t upstream; - ngx_http_upstream_srv_conf_t *upstream_peers; - ngx_array_t *flushes; ngx_array_t *body_set_len; ngx_array_t *body_set; @@ -107,6 +105,11 @@ static char *ngx_http_proxy_redirect(ngx static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + static ngx_conf_post_t ngx_http_proxy_lowat_post = { ngx_http_proxy_lowat_check }; @@ -297,16 +300,16 @@ static ngx_command_t ngx_http_proxy_com { ngx_string("proxy_upstream_max_fails"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_num_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, upstream.max_fails), + ngx_http_proxy_upstream_max_fails_unsupported, + 0, + 0, NULL }, { ngx_string("proxy_upstream_fail_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, - ngx_conf_set_sec_slot, - NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, upstream.fail_timeout), + ngx_http_proxy_upstream_fail_timeout_unsupported, + 0, + 0, NULL }, { ngx_string("proxy_pass_header"), @@ -419,8 +422,6 @@ ngx_http_proxy_handler(ngx_http_request_ u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = plcf->upstream_peers->peers; - u->peer.tries = plcf->upstream_peers->peers->number; #if (NGX_THREADS) u->peer.lock = &r->connection->lock; #endif @@ -1498,9 +1499,6 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ conf->upstream.max_temp_file_size_conf = NGX_CONF_UNSET_SIZE; conf->upstream.temp_file_write_size_conf = NGX_CONF_UNSET_SIZE; - conf->upstream.max_fails = NGX_CONF_UNSET_UINT; - conf->upstream.fail_timeout = NGX_CONF_UNSET; - conf->upstream.pass_request_headers = NGX_CONF_UNSET; conf->upstream.pass_request_body = NGX_CONF_UNSET; @@ -1527,7 +1525,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t uintptr_t *code; ngx_str_t *header; ngx_uint_t i, j; - ngx_peer_t *peer; ngx_array_t hide_headers; ngx_keyval_t *src, *s, *h; ngx_hash_key_t *hk; @@ -1660,24 +1657,6 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t |NGX_HTTP_UPSTREAM_FT_OFF; } - ngx_conf_merge_uint_value(conf->upstream.max_fails, - prev->upstream.max_fails, 1); - - ngx_conf_merge_sec_value(conf->upstream.fail_timeout, - prev->upstream.fail_timeout, 10); - - if (conf->upstream_peers) { - peer = conf->upstream_peers->peers->peer; - for (i = 0; i < conf->upstream_peers->peers->number; i++) { - ngx_conf_init_uint_value(peer[i].weight, 1); - peer[i].current_weight = peer[i].weight; - ngx_conf_init_uint_value(peer[i].max_fails, - conf->upstream.max_fails); - ngx_conf_init_value(peer[i].fail_timeout, - conf->upstream.fail_timeout); - } - } - ngx_conf_merge_path_value(conf->upstream.temp_path, prev->upstream.temp_path, NGX_HTTP_PROXY_TEMP_PATH, 1, 2, 0, @@ -1834,8 +1813,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t peers: - if (conf->upstream_peers == NULL) { - conf->upstream_peers = prev->upstream_peers; + if (conf->upstream.upstream == NULL) { + conf->upstream.upstream = prev->upstream.upstream; conf->host_header = prev->host_header; conf->port_text = prev->port_text; @@ -2180,11 +2159,11 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ u.url.len = url->len - add; u.url.data = url->data + add; u.default_portn = port; + u.no_resolve = 1; u.uri_part = 1; - u.upstream = 1; - - plcf->upstream_peers = ngx_http_upstream_add(cf, &u); - if (plcf->upstream_peers == NULL) { + + plcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); + if (plcf->upstream.upstream == NULL) { return NGX_CONF_ERROR; } @@ -2345,3 +2324,29 @@ ngx_http_proxy_lowat_check(ngx_conf_t *c return NGX_CONF_OK; } + + +static char * +ngx_http_proxy_upstream_max_fails_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_upstream_max_fails\" is not supported, " + "use the \"max_fails\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_proxy_upstream_fail_timeout_unsupported(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"proxy_upstream_fail_timeout\" is not supported, " + "use the \"fail_timeout\" parameter of the \"server\" directive ", + "inside the \"upstream\" block"); + + return NGX_CONF_ERROR; +} diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -0,0 +1,228 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + /* the round robin data must be first */ + ngx_http_upstream_rr_peer_data_t rrp; + + ngx_uint_t hash; + + /* AF_INET only */ + u_char addr[3]; + + u_char tries; + + ngx_event_get_peer_pt get_rr_peer; +} ngx_http_upstream_ip_hash_peer_data_t; + + +static ngx_int_t ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +static ngx_int_t ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, + void *data); +static char *ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_command_t ngx_http_upstream_ip_hash_commands[] = { + + { ngx_string("ip_hash"), + NGX_HTTP_UPS_CONF|NGX_CONF_NOARGS, + ngx_http_upstream_ip_hash, + 0, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_ip_hash_module_ctx = { + NULL, /* preconfiguration */ + NULL, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + NULL, /* create location configuration */ + NULL /* merge location configuration */ +}; + + +ngx_module_t ngx_http_upstream_ip_hash_module = { + NGX_MODULE_V1, + &ngx_http_upstream_ip_hash_module_ctx, /* module context */ + ngx_http_upstream_ip_hash_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +ngx_int_t +ngx_http_upstream_init_ip_hash(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us) +{ + if (ngx_http_upstream_init_round_robin(cf, us) != NGX_OK) { + return NGX_ERROR; + } + + us->peer.init = ngx_http_upstream_init_ip_hash_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_init_ip_hash_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + struct sockaddr_in *sin; + ngx_http_upstream_ip_hash_peer_data_t *iphp; + + iphp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_ip_hash_peer_data_t)); + if (iphp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = &iphp->rrp; + + if (ngx_http_upstream_init_round_robin_peer(r, us) != NGX_OK) { + return NGX_ERROR; + } + + r->upstream->peer.get = ngx_http_upstream_get_ip_hash_peer; + + /* AF_INET only */ + sin = (struct sockaddr_in *) r->connection->sockaddr; + iphp->addr[0] = (u_char) ((sin->sin_addr.s_addr >> 24) & 0xff); + iphp->addr[1] = (u_char) ((sin->sin_addr.s_addr >> 16) & 0xff); + iphp->addr[2] = (u_char) ((sin->sin_addr.s_addr >> 8) & 0xff); + + iphp->hash = 89; + iphp->tries = 0; + iphp->get_rr_peer = ngx_http_upstream_get_round_robin_peer; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_ip_hash_peer_data_t *iphp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n, p, hash; + ngx_http_upstream_rr_peer_t *peer; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get ip hash peer, try: %ui", pc->tries); + + /* TODO: cached */ + + if (iphp->tries > 20 || iphp->rrp.peers->number == 1) { + return iphp->get_rr_peer(pc, &iphp->rrp); + } + + now = ngx_time(); + + pc->cached = 0; + pc->connection = NULL; + + hash = iphp->hash; + + for ( ;; ) { + + for (i = 0; i < 3; i++) { + hash = (hash * 113 + iphp->addr[i]) % 6271; + } + + p = hash % iphp->rrp.peers->number; + + n = p / (8 * sizeof(uintptr_t)); + m = 1 << p % (8 * sizeof(uintptr_t)); + + if (!(iphp->rrp.tried[n] & m)) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get ip hash peer, hash: %ui %04XA", p, m); + + peer = &iphp->rrp.peers->peer[p]; + + /* ngx_lock_mutex(iphp->rrp.peers->mutex); */ + + if (!peer->down) { + + if (peer->max_fails == 0 || peer->fails < peer->max_fails) { + break; + } + + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + break; + } + + } else { + iphp->rrp.tried[n] |= m; + } + + /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ + + pc->tries--; + } + + if (++iphp->tries >= 20) { + return iphp->get_rr_peer(pc, &iphp->rrp); + } + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; +#if (NGX_SSL) + pc->ssl_session = peer->ssl_session; +#endif + + /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ + + iphp->rrp.tried[n] |= m; + iphp->hash = hash; + + return NGX_OK; +} + + +static char * +ngx_http_upstream_ip_hash(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_srv_conf_t *uscf; + + uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module); + + uscf->peer.init_upstream = ngx_http_upstream_init_ip_hash; + + uscf->flags = NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN; + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -46,15 +46,6 @@ static void ngx_http_userid_get_uid(ngx_ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); -static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); -static size_t ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op); - static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -191,17 +182,6 @@ ngx_module_t ngx_http_userid_filter_mod }; -static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = { - { ngx_string("uid_got"), 0, NULL, - ngx_http_userid_log_uid_got_getlen, - ngx_http_userid_log_uid_got }, - { ngx_string("uid_set"), 0, NULL, - ngx_http_userid_log_uid_set_getlen, - ngx_http_userid_log_uid_set }, - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - static ngx_str_t ngx_http_userid_got = ngx_string("uid_got"); static ngx_str_t ngx_http_userid_set = ngx_string("uid_set"); @@ -462,99 +442,10 @@ ngx_http_userid_set_uid(ngx_http_request } -static size_t -ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_http_userid_ctx_t *ctx; - ngx_http_userid_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); - - if (ctx == NULL || ctx->uid_got[3] == 0) { - return 1; - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - - return conf->name.len + 1 + 32; -} - - -static u_char * -ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_http_userid_ctx_t *ctx; - ngx_http_userid_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); - - if (ctx == NULL || ctx->uid_got[3] == 0) { - *buf = '-'; - return buf + 1; - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - - buf = ngx_copy(buf, conf->name.data, conf->name.len); - - *buf++ = '='; - - return ngx_sprintf(buf, "%08XD%08XD%08XD%08XD", - ctx->uid_got[0], ctx->uid_got[1], - ctx->uid_got[2], ctx->uid_got[3]); -} - - -static size_t -ngx_http_userid_log_uid_set_getlen(ngx_http_request_t *r, uintptr_t data) -{ - ngx_http_userid_ctx_t *ctx; - ngx_http_userid_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); - - if (ctx == NULL || ctx->uid_set[3] == 0) { - return 1; - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - - return conf->name.len + 1 + 32; -} - - -static u_char * -ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_http_userid_ctx_t *ctx; - ngx_http_userid_conf_t *conf; - - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); - - if (ctx == NULL || ctx->uid_set[3] == 0) { - *buf = '-'; - return buf + 1; - } - - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - - buf = ngx_copy(buf, conf->name.data, conf->name.len); - - *buf++ = '='; - - return ngx_sprintf(buf, "%08XD%08XD%08XD%08XD", - ctx->uid_set[0], ctx->uid_set[1], - ctx->uid_set[2], ctx->uid_set[3]); -} - - static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf) { - ngx_http_variable_t *var; - ngx_http_log_op_name_t *op; + ngx_http_variable_t *var; var = ngx_http_add_variable(cf, &ngx_http_userid_got, NGX_HTTP_VAR_NOHASH); if (var == NULL) { @@ -572,18 +463,6 @@ ngx_http_userid_add_variables(ngx_conf_t var->get_handler = ngx_http_userid_variable; var->data = offsetof(ngx_http_userid_ctx_t, uid_set); - - for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - for (op = ngx_http_log_fmt_ops; op->run; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->run; - } - } - - op->run = (ngx_http_log_op_run_pt) ngx_http_userid_log_fmt_ops; - return NGX_OK; } 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 @@ -17,7 +17,7 @@ our @EXPORT = qw( HTTP_SERVER_ERROR ); -our $VERSION = '0.4.14'; +our $VERSION = '0.5.0'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -4,6 +4,8 @@ */ +#define PERL_NO_GET_CONTEXT + #include #include #include diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- a/src/http/ngx_http.h +++ b/src/http/ngx_http.h @@ -32,9 +32,9 @@ typedef u_char *(*ngx_http_log_handler_p #include #include #include +#include #include #include -#include #include #include 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 @@ -2409,9 +2409,9 @@ static u_char * ngx_http_log_error_handler(ngx_http_request_t *r, ngx_http_request_t *sr, u_char *buf, size_t len) { - u_char *p; - ngx_http_upstream_t *u; - ngx_peer_connection_t *peer; + char *uri_separator; + u_char *p; + ngx_http_upstream_t *u; if (r->server_name.data) { p = ngx_snprintf(buf, len, ", server: %V", &r->server_name); @@ -2451,14 +2451,19 @@ ngx_http_log_error_handler(ngx_http_requ u = sr->upstream; - if (u) { - peer = &u->peer; + if (u && u->peer.name) { + + uri_separator = ""; + +#if (NGX_HAVE_UNIX_DOMAIN) + if (u->peer.sockaddr && u->peer.sockaddr->sa_family == AF_UNIX) { + uri_separator = ":"; + } +#endif p = ngx_snprintf(buf, len, ", upstream: \"%V%V%s%V\"", - &u->conf->schema, - &peer->peers->peer[peer->cur_peer].name, - peer->peers->peer[peer->cur_peer].uri_separator, - &u->uri); + &u->conf->schema, u->peer.name, + uri_separator, &u->uri); len -= p - buf; buf = p; } 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 @@ -70,15 +70,6 @@ static ngx_int_t ngx_http_upstream_copy_ ngx_table_elt_t *h, ngx_uint_t offset); #endif -static size_t ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_upstream_log_status(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); -static size_t ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r, - uintptr_t data); -static u_char *ngx_http_upstream_log_response_time(ngx_http_request_t *r, - u_char *buf, ngx_http_log_op_t *op); - static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_upstream_status_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); @@ -96,8 +87,6 @@ static char *ngx_http_upstream_init_main static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, ngx_http_upstream_t *u, ngx_connection_t *c); static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c); -static void ngx_http_upstream_ssl_shutdown(ngx_connection_t *c, - ngx_peer_t *peer); #endif @@ -224,7 +213,7 @@ static ngx_command_t ngx_http_upstream_ NULL }, { ngx_string("server"), - NGX_HTTP_UPS_CONF|NGX_CONF_TAKE12, + NGX_HTTP_UPS_CONF|NGX_CONF_1MORE, ngx_http_upstream_server, NGX_HTTP_SRV_CONF_OFFSET, 0, @@ -265,17 +254,6 @@ ngx_module_t ngx_http_upstream_module = }; -static ngx_http_log_op_name_t ngx_http_upstream_log_fmt_ops[] = { - { ngx_string("upstream_status"), 0, NULL, - ngx_http_upstream_log_status_getlen, - ngx_http_upstream_log_status }, - { ngx_string("upstream_response_time"), 0, NULL, - ngx_http_upstream_log_response_time_getlen, - ngx_http_upstream_log_response_time }, - { ngx_null_string, 0, NULL, NULL, NULL } -}; - - static ngx_http_variable_t ngx_http_upstream_vars[] = { { ngx_string("upstream_status"), NULL, @@ -328,13 +306,16 @@ ngx_http_upstream_init(ngx_http_request_ u->request_bufs = r->request_body->bufs; } + if (u->conf->upstream->peer.init(r, u->conf->upstream) != NGX_OK) { + ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + if (u->create_request(r) != NGX_OK) { ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - u->peer.log = r->connection->log; - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); u->output.sendfile = r->connection->sendfile; @@ -346,7 +327,7 @@ ngx_http_upstream_init(ngx_http_request_ u->writer.pool = r->pool; - if (ngx_array_init(&u->states, r->pool, u->peer.peers->number, + if (ngx_array_init(&u->states, r->pool, 1, sizeof(ngx_http_upstream_state_t)) != NGX_OK) { @@ -548,7 +529,7 @@ ngx_http_upstream_connect(ngx_http_reque return; } - u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name; + u->state->peer = u->peer.name; if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); @@ -637,8 +618,7 @@ static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_connection_t *c) { - ngx_int_t rc; - ngx_peer_t *peer; + ngx_int_t rc; if (ngx_ssl_create_connection(u->conf->ssl, c, NGX_SSL_BUFFER|NGX_SSL_CLIENT) @@ -652,9 +632,7 @@ ngx_http_upstream_ssl_init_connection(ng c->sendfile = 0; u->output.sendfile = 0; - peer = &u->peer.peers->peer[u->peer.cur_peer]; - - if (ngx_ssl_set_session(c, peer->ssl_session) != NGX_OK) { + if (ngx_ssl_set_session(c, u->peer.ssl_session) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; @@ -684,6 +662,8 @@ ngx_http_upstream_ssl_handshake(ngx_conn if (c->ssl->handshaked) { + u->peer.save_session(&u->peer, u->peer.data); + c->write->handler = ngx_http_upstream_send_request_handler; c->read->handler = ngx_http_upstream_process_header; @@ -992,7 +972,7 @@ ngx_http_upstream_process_header(ngx_eve } n = u->peer.connection->recv(u->peer.connection, u->buffer.last, - u->buffer.end - u->buffer.last); + u->buffer.end - u->buffer.last); if (n == NGX_AGAIN) { #if 0 @@ -1605,7 +1585,7 @@ ngx_http_upstream_process_non_buffered_b ngx_buf_t *b; ngx_int_t rc; ngx_uint_t do_write; - ngx_connection_t *c, *client; + ngx_connection_t *c, *downstream, *upstream; ngx_http_request_t *r; ngx_http_upstream_t *u; ngx_http_core_loc_conf_t *clcf; @@ -1638,7 +1618,8 @@ ngx_http_upstream_process_non_buffered_b return; } - client = r->connection; + downstream = r->connection; + upstream = u->peer.connection; b = &u->buffer; @@ -1653,7 +1634,7 @@ ngx_http_upstream_process_non_buffered_b if (u->out_bufs || u->busy_bufs) { rc = ngx_http_output_filter(r, u->out_bufs); - if (client->destroyed) { + if (downstream->destroyed) { return; } @@ -1669,8 +1650,8 @@ ngx_http_upstream_process_non_buffered_b if (u->busy_bufs == NULL) { if (u->length == 0 - || u->peer.connection->read->eof - || u->peer.connection->read->error) + || upstream->read->eof + || upstream->read->error) { ngx_http_upstream_finalize_request(r, u, 0); return; @@ -1687,9 +1668,9 @@ ngx_http_upstream_process_non_buffered_b size = u->length; } - if (size && u->peer.connection->read->ready) { - - n = u->peer.connection->recv(u->peer.connection, b->last, size); + if (size && upstream->read->ready) { + + n = upstream->recv(upstream, b->last, size); if (n == NGX_AGAIN) { break; @@ -1710,8 +1691,8 @@ ngx_http_upstream_process_non_buffered_b break; } - if (client->data == r) { - if (ngx_handle_write_event(client->write, clcf->send_lowat) + if (downstream->data == r) { + if (ngx_handle_write_event(downstream->write, clcf->send_lowat) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, 0); @@ -1719,23 +1700,23 @@ ngx_http_upstream_process_non_buffered_b } } - if (client->write->active) { - ngx_add_timer(client->write, clcf->send_timeout); - - } else if (client->write->timer_set) { - ngx_del_timer(client->write); + if (downstream->write->active) { + ngx_add_timer(downstream->write, clcf->send_timeout); + + } else if (downstream->write->timer_set) { + ngx_del_timer(downstream->write); } - if (ngx_handle_read_event(u->peer.connection->read, 0) == NGX_ERROR) { + if (ngx_handle_read_event(upstream->read, 0) == NGX_ERROR) { ngx_http_upstream_finalize_request(r, u, 0); return; } - if (u->peer.connection->read->active) { - ngx_add_timer(u->peer.connection->read, u->conf->read_timeout); - - } else if (u->peer.connection->read->timer_set) { - ngx_del_timer(u->peer.connection->read); + if (upstream->read->active) { + ngx_add_timer(upstream->read, u->conf->read_timeout); + + } else if (upstream->read->timer_set) { + ngx_del_timer(upstream->read); } } @@ -1942,22 +1923,22 @@ static void ngx_http_upstream_next(ngx_http_request_t *r, ngx_http_upstream_t *u, ngx_uint_t ft_type) { - ngx_uint_t status, down; + ngx_uint_t status, state; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "http next upstream, %xD", ft_type); + "http next upstream, %xi", ft_type); #if 0 ngx_http_busy_unlock(u->conf->busy_lock, &u->busy_lock); #endif if (ft_type == NGX_HTTP_UPSTREAM_FT_HTTP_404) { - down = 0; + state = NGX_PEER_NEXT; } else { - down = 1; + state = NGX_PEER_FAILED; } - ngx_event_connect_peer_failed(&u->peer, down); + u->peer.free(&u->peer, u->peer.data, state); if (ft_type == NGX_HTTP_UPSTREAM_FT_TIMEOUT) { ngx_log_error(NGX_LOG_ERR, r->connection->log, NGX_ETIMEDOUT, @@ -2023,11 +2004,15 @@ ngx_http_upstream_next(ngx_http_request_ "close http upstream connection: %d", u->peer.connection->fd); #if (NGX_HTTP_SSL) + if (u->peer.connection->ssl) { - ngx_http_upstream_ssl_shutdown(u->peer.connection, - &u->peer.peers->peer[u->peer.cur_peer]); + u->peer.connection->ssl->no_wait_shutdown = 1; + u->peer.connection->ssl->no_send_shutdown = 1; + + (void) ngx_ssl_shutdown(u->peer.connection); } #endif + ngx_close_connection(u->peer.connection); } @@ -2074,19 +2059,32 @@ ngx_http_upstream_finalize_request(ngx_h u->finalize_request(r, rc); + u->peer.free(&u->peer, u->peer.data, 0); + if (u->peer.connection) { - ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "close http upstream connection: %d", - u->peer.connection->fd); + #if (NGX_HTTP_SSL) /* TODO: do not shutdown persistent connection */ if (u->peer.connection->ssl) { - ngx_http_upstream_ssl_shutdown(u->peer.connection, - &u->peer.peers->peer[u->peer.cur_peer]); + + /* + * We send the "close notify" shutdown alert to the upstream only + * and do not wait its "close notify" shutdown alert. + * It is acceptable according to the TLS standard. + */ + + u->peer.connection->ssl->no_wait_shutdown = 1; + + (void) ngx_ssl_shutdown(u->peer.connection); } #endif + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "close http upstream connection: %d", + u->peer.connection->fd); + ngx_close_connection(u->peer.connection); } @@ -2125,35 +2123,6 @@ ngx_http_upstream_finalize_request(ngx_h } -#if (NGX_HTTP_SSL) - -static void -ngx_http_upstream_ssl_shutdown(ngx_connection_t *c, ngx_peer_t *peer) -{ - /* lock peer mutex */ - - if (peer->ssl_session) { - ngx_ssl_free_session(peer->ssl_session); - } - - peer->ssl_session = ngx_ssl_get_session(c); - - /* unlock peer mutex */ - - /* - * We send the "close notify" shutdown alert to the upstream only - * and do not wait its "close notify" shutdown alert. - * It is acceptable according to the TLS standard. - */ - - c->ssl->no_wait_shutdown = 1; - - (void) ngx_ssl_shutdown(c); -} - -#endif - - static ngx_int_t ngx_http_upstream_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) @@ -2481,108 +2450,10 @@ ngx_http_upstream_copy_content_encoding( #endif -static size_t -ngx_http_upstream_log_status_getlen(ngx_http_request_t *r, uintptr_t data) -{ - if (r->upstream) { - return r->upstream->states.nelts * (3 + 2); - } - - return 1; -} - - -static u_char * -ngx_http_upstream_log_status(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_uint_t i; - ngx_http_upstream_t *u; - ngx_http_upstream_state_t *state; - - u = r->upstream; - - if (u == NULL || u->states.nelts == 0) { - *buf = '-'; - return buf + 1; - } - - i = 0; - state = u->states.elts; - - for ( ;; ) { - if (state[i].status == 0) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%ui", state[i].status); - } - - if (++i == u->states.nelts) { - return buf; - } - - *buf++ = ','; - *buf++ = ' '; - } -} - - -static size_t -ngx_http_upstream_log_response_time_getlen(ngx_http_request_t *r, - uintptr_t data) -{ - if (r->upstream) { - return r->upstream->states.nelts * (NGX_TIME_T_LEN + 4 + 2); - } - - return 1; -} - - -static u_char * -ngx_http_upstream_log_response_time(ngx_http_request_t *r, u_char *buf, - ngx_http_log_op_t *op) -{ - ngx_uint_t i; - ngx_http_upstream_t *u; - ngx_http_upstream_state_t *state; - - u = r->upstream; - - if (u == NULL || u->states.nelts == 0) { - *buf = '-'; - return buf + 1; - } - - i = 0; - state = u->states.elts; - - for ( ;; ) { - if (state[i].status == 0) { - *buf++ = '-'; - - } else { - buf = ngx_sprintf(buf, "%d.%03d", - state[i].response_time / 1000, - state[i].response_time % 1000); - } - - if (++i == u->states.nelts) { - return buf; - } - - *buf++ = ','; - *buf++ = ' '; - } -} - - static ngx_int_t ngx_http_upstream_add_variables(ngx_conf_t *cf) { - ngx_http_variable_t *var, *v; - ngx_http_log_op_name_t *op; + ngx_http_variable_t *var, *v; for (v = ngx_http_upstream_vars; v->name.len; v++) { var = ngx_http_add_variable(cf, &v->name, v->flags); @@ -2594,17 +2465,6 @@ ngx_http_upstream_add_variables(ngx_conf var->data = v->data; } - for (op = ngx_http_upstream_log_fmt_ops; op->name.len; op++) { /* void */ } - op->run = NULL; - - for (op = ngx_http_log_fmt_ops; op->run; op++) { - if (op->name.len == 0) { - op = (ngx_http_log_op_name_t *) op->run; - } - } - - op->run = (ngx_http_log_op_run_pt) ngx_http_upstream_log_fmt_ops; - return NGX_OK; } @@ -2724,31 +2584,41 @@ ngx_http_upstream_response_time_variable static char * ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { - char *rv; - void *mconf; - ngx_str_t *value; - ngx_url_t u; - ngx_uint_t i, j, m, n; - ngx_conf_t pcf; - ngx_peers_t **peers; - ngx_http_module_t *module; - ngx_http_conf_ctx_t *ctx; - ngx_http_upstream_srv_conf_t *uscf; + char *rv; + void *mconf; + ngx_str_t *value; + ngx_url_t u; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_http_module_t *module; + ngx_http_conf_ctx_t *ctx, *http_ctx; + ngx_http_upstream_srv_conf_t *uscf; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + value = cf->args->elts; + u.host = value[1]; + u.upstream = 1; + u.no_resolve = 1; + + uscf = ngx_http_upstream_add(cf, &u, NGX_HTTP_UPSTREAM_CREATE + |NGX_HTTP_UPSTREAM_WEIGHT + |NGX_HTTP_UPSTREAM_MAX_FAILS + |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT + |NGX_HTTP_UPSTREAM_DOWN + |NGX_HTTP_UPSTREAM_BACKUP); + if (uscf == NULL) { + return NGX_CONF_ERROR; + } + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } - ngx_memzero(&u, sizeof(ngx_url_t)); - - value = cf->args->elts; - u.host = value[1]; - - uscf = ngx_http_upstream_add(cf, &u); - if (uscf == NULL) { - return NGX_CONF_ERROR; - } + http_ctx = cf->ctx; + ctx->main_conf = http_ctx->main_conf; /* the upstream{}'s srv_conf */ @@ -2759,6 +2629,8 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf; + uscf->srv_conf = ctx->srv_conf; + /* the upstream{}'s loc_conf */ @@ -2774,6 +2646,15 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co module = ngx_modules[m]->ctx; + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + } + if (module->create_loc_conf) { mconf = module->create_loc_conf(cf); if (mconf == NULL) { @@ -2805,34 +2686,6 @@ ngx_http_upstream(ngx_conf_t *cf, ngx_co return NGX_CONF_ERROR; } - peers = uscf->servers->elts; - - if (uscf->servers->nelts == 1) { - uscf->peers = peers[0]; - } - - n = 0; - - for (i = 0; i < uscf->servers->nelts; i++) { - n += peers[i]->number; - } - - uscf->peers = ngx_pcalloc(cf->pool, - sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (n - 1)); - if (uscf->peers == NULL) { - return NGX_CONF_ERROR; - } - - uscf->peers->number = n; - - n = 0; - - for (i = 0; i < uscf->servers->nelts; i++) { - for (j = 0; j < peers[i]->number; j++) { - uscf->peers->peer[n++] = peers[i]->peer[j]; - } - } - return rv; } @@ -2842,24 +2695,28 @@ ngx_http_upstream_server(ngx_conf_t *cf, { ngx_http_upstream_srv_conf_t *uscf = conf; - ngx_str_t *value; - ngx_url_t u; - ngx_int_t weight; - ngx_uint_t i; - ngx_peers_t **peers; + time_t fail_timeout; + ngx_str_t *value, s; + ngx_url_t u; + ngx_int_t weight, max_fails; + ngx_uint_t i; + ngx_http_upstream_server_t *us; if (uscf->servers == NULL) { - uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_peers_t *)); + uscf->servers = ngx_array_create(cf->pool, 4, + sizeof(ngx_http_upstream_server_t)); if (uscf->servers == NULL) { return NGX_CONF_ERROR; } } - peers = ngx_array_push(uscf->servers); - if (peers == NULL) { + us = ngx_array_push(uscf->servers); + if (us == NULL) { return NGX_CONF_ERROR; } + ngx_memzero(us, sizeof(ngx_http_upstream_server_t)); + value = cf->args->elts; ngx_memzero(&u, sizeof(ngx_url_t)); @@ -2877,51 +2734,100 @@ ngx_http_upstream_server(ngx_conf_t *cf, } weight = 1; - - if (cf->args->nelts == 3) { - - value = &value[2]; - - if (ngx_strncmp(value->data, "weight=", 7) == 0) { - - weight = ngx_atoi(&value->data[7], value->len - 7); + max_fails = 1; + fail_timeout = 10; + + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strncmp(value[i].data, "weight=", 7) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_WEIGHT)) { + goto invalid; + } + + weight = ngx_atoi(&value[i].data[7], value[i].len - 7); if (weight == NGX_ERROR || weight == 0) { goto invalid; } - } else { - goto invalid; + continue; + } + + if (ngx_strncmp(value[i].data, "max_fails=", 10) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_MAX_FAILS)) { + goto invalid; + } + + max_fails = ngx_atoi(&value[i].data[10], value[i].len - 10); + + if (max_fails == NGX_ERROR) { + goto invalid; + } + + continue; } + + if (ngx_strncmp(value[i].data, "fail_timeout=", 13) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_FAIL_TIMEOUT)) { + goto invalid; + } + + s.len = value[i].len - 13; + s.data = &value[i].data[13]; + + fail_timeout = ngx_parse_time(&s, 1); + + if (fail_timeout < 0) { + goto invalid; + } + + continue; + } + + if (ngx_strncmp(value[i].data, "down", 4) == 0) { + + if (!(uscf->flags & NGX_HTTP_UPSTREAM_DOWN)) { + goto invalid; + } + + us->down = 1; + + continue; + } + + goto invalid; } - for (i = 0; i < u.peers->number; i++) { - u.peers->peer[i].weight = weight; - u.peers->peer[i].current_weight = weight; - u.peers->peer[i].max_fails = NGX_CONF_UNSET_UINT; - u.peers->peer[i].fail_timeout = NGX_CONF_UNSET; - } - - *peers = u.peers; + us->addrs = u.addrs; + us->naddrs = u.naddrs; + us->weight = weight; + us->max_fails = max_fails; + us->fail_timeout = fail_timeout; return NGX_CONF_OK; invalid: - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", value); + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); return NGX_CONF_ERROR; } ngx_http_upstream_srv_conf_t * -ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u) +ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u, ngx_uint_t flags) { ngx_uint_t i; + ngx_http_upstream_server_t *us; ngx_http_upstream_srv_conf_t *uscf, **uscfp; ngx_http_upstream_main_conf_t *umcf; - if (u->upstream) { + if (!(flags & NGX_HTTP_UPSTREAM_CREATE)) { + if (ngx_parse_url(cf, u) != NGX_OK) { if (u->err) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -2930,17 +2836,6 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng return NULL; } - - if (u->peers) { - uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t)); - if (uscf == NULL) { - return NULL; - } - - uscf->peers = u->peers; - - return uscf; - } } umcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_upstream_module); @@ -2948,15 +2843,28 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng uscfp = umcf->upstreams.elts; for (i = 0; i < umcf->upstreams.nelts; i++) { - if (uscfp[i]->host.len != u->host.len) { + if (uscfp[i]->host.len != u->host.len + || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len) + != 0) + { continue; } - if (ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len) - == 0) + if ((flags & NGX_HTTP_UPSTREAM_CREATE) + && (uscfp[i]->flags & NGX_HTTP_UPSTREAM_CREATE)) { - return uscfp[i]; + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate upstream \"%V\"", &u->host); + return NULL; } + + if (uscfp[i]->port == 0 && u->portn && !u->no_port) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "upstream \"%V\" port %d is ignored", + &u->host, u->portn); + } + + return uscfp[i]; } uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t)); @@ -2964,10 +2872,29 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng return NULL; } + uscf->flags = flags; uscf->host = u->host; uscf->file_name = cf->conf_file->file.name; uscf->line = cf->conf_file->line; - uscf->port = u->default_portn; + uscf->port = u->portn; + + if (u->naddrs == 1) { + uscf->servers = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_upstream_server_t)); + if (uscf->servers == NULL) { + return NGX_CONF_ERROR; + } + + us = ngx_array_push(uscf->servers); + if (us == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(us, sizeof(ngx_http_upstream_server_t)); + + us->addrs = u->addrs; + us->naddrs = u->naddrs; + } uscfp = ngx_array_push(&umcf->upstreams); if (uscfp == NULL) { @@ -3010,32 +2937,25 @@ ngx_http_upstream_init_main_conf(ngx_con ngx_array_t headers_in; ngx_hash_key_t *hk; ngx_hash_init_t hash; + ngx_http_upstream_init_pt init; ngx_http_upstream_header_t *header; ngx_http_upstream_srv_conf_t **uscfp; uscfp = umcf->upstreams.elts; for (i = 0; i < umcf->upstreams.nelts; i++) { - if (uscfp[i]->peers) { - continue; - } - - uscfp[i]->peers = ngx_inet_resolve_peer(cf, &uscfp[i]->host, - uscfp[i]->port); - if (uscfp[i]->peers == NULL) { - return NGX_CONF_ERROR; - } - - if (uscfp[i]->peers == NGX_CONF_ERROR) { - ngx_log_error(NGX_LOG_EMERG, cf->log, 0, - "upstream host \"%V\" is not found in %s:%ui", - &uscfp[i]->host, uscfp[i]->file_name.data, - uscfp[i]->line); + + init = uscfp[i]->peer.init_upstream ? uscfp[i]->peer.init_upstream: + ngx_http_upstream_init_round_robin; + + if (init(cf, uscfp[i]) != NGX_OK) { return NGX_CONF_ERROR; } } + /* upstream_headers_in_hash */ + if (ngx_array_init(&headers_in, cf->temp_pool, 32, sizeof(ngx_hash_key_t)) != NGX_OK) { 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 @@ -44,23 +44,61 @@ typedef struct { typedef struct { ngx_hash_t headers_in_hash; ngx_array_t upstreams; - /* ngx_http_upstream_srv_conf_t */ + /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t; +typedef struct ngx_http_upstream_srv_conf_s ngx_http_upstream_srv_conf_t; + +typedef ngx_int_t (*ngx_http_upstream_init_pt)(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +typedef ngx_int_t (*ngx_http_upstream_init_peer_pt)(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); + + +typedef struct { + ngx_http_upstream_init_pt init_upstream; + ngx_http_upstream_init_peer_pt init; + void *data; +} ngx_http_upstream_peer_t; + typedef struct { - ngx_peers_t *peers; + ngx_peer_addr_t *addrs; + ngx_uint_t naddrs; + ngx_uint_t weight; + ngx_uint_t max_fails; + time_t fail_timeout; + + unsigned down:1; + unsigned backup:1; +} ngx_http_upstream_server_t; + - ngx_array_t *servers; +#define NGX_HTTP_UPSTREAM_CREATE 0x0001 +#define NGX_HTTP_UPSTREAM_WEIGHT 0x0002 +#define NGX_HTTP_UPSTREAM_MAX_FAILS 0x0004 +#define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008 +#define NGX_HTTP_UPSTREAM_DOWN 0x0010 +#define NGX_HTTP_UPSTREAM_BACKUP 0x0020 + +struct ngx_http_upstream_srv_conf_s { + ngx_http_upstream_peer_t peer; + void **srv_conf; + + ngx_array_t *servers; /* ngx_http_upstream_server_t */ + + ngx_uint_t flags; ngx_str_t host; ngx_str_t file_name; ngx_uint_t line; in_port_t port; -} ngx_http_upstream_srv_conf_t; +}; typedef struct { + ngx_http_upstream_srv_conf_t *upstream; + ngx_msec_t connect_timeout; ngx_msec_t send_timeout; ngx_msec_t read_timeout; @@ -78,9 +116,6 @@ typedef struct { size_t temp_file_write_size_conf; ngx_uint_t next_upstream; - ngx_uint_t max_fails; - - time_t fail_timeout; ngx_bufs_t bufs; @@ -213,7 +248,11 @@ struct ngx_http_upstream_s { 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_url_t *u, ngx_uint_t flags); + + +#define ngx_http_conf_upstream_srv_conf(uscf, module) \ + uscf->srv_conf[module.ctx_index] extern ngx_module_t ngx_http_upstream_module; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_upstream_round_robin.c @@ -0,0 +1,430 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +ngx_int_t +ngx_http_upstream_init_round_robin(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_url_t u; + ngx_uint_t i, j, n; + ngx_http_upstream_server_t *server; + ngx_http_upstream_rr_peers_t *peers; + + us->peer.init = ngx_http_upstream_init_round_robin_peer; + + if (us->servers) { + n = 0; + server = us->servers->elts; + + for (i = 0; i < us->servers->nelts; i++) { + n += server[i].naddrs; + } + + peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) + + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + if (peers == NULL) { + return NGX_ERROR; + } + + peers->number = n; + peers->name = &us->host; + + n = 0; + + for (i = 0; i < us->servers->nelts; i++) { + for (j = 0; j < server[i].naddrs; j++) { + peers->peer[n].sockaddr = server[i].addrs[j].sockaddr; + peers->peer[n].socklen = server[i].addrs[j].socklen; + peers->peer[n].name = server[i].addrs[j].name; + peers->peer[n].weight = server[i].weight; + peers->peer[n].current_weight = server[i].weight; + peers->peer[n].max_fails = server[i].max_fails; + peers->peer[n].fail_timeout = server[i].fail_timeout; + peers->peer[n].down = server[i].down; + n++; + } + } + + us->peer.data = peers; + + return NGX_OK; + } + + + /* an upstream implicitly defined by proxy_pass, etc. */ + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.host = us->host; + u.portn = us->port; + + if (ngx_inet_resolve_host(cf, &u) != NGX_OK) { + if (u.err) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "%s in upstream host \"%V\" is not found in %s:%ui", + u.err, &us->host, us->file_name.data, us->line); + } + + return NGX_ERROR; + } + + n = u.naddrs; + + peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t) + + sizeof(ngx_http_upstream_rr_peer_t) * (n - 1)); + if (peers == NULL) { + return NGX_ERROR; + } + + peers->number = n; + peers->name = &us->host; + + n = 0; + + for (i = 0; i < u.naddrs; i++) { + peers->peer[n].sockaddr = u.addrs[i].sockaddr; + peers->peer[n].socklen = u.addrs[i].socklen; + peers->peer[n].name = u.addrs[i].name; + peers->peer[n].weight = 1; + peers->peer[n].current_weight = 1; + peers->peer[n].max_fails = 1; + peers->peer[n].fail_timeout = 10; + n++; + } + + us->peer.data = peers; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us) +{ + ngx_uint_t n; + ngx_http_upstream_rr_peer_data_t *rrp; + + rrp = r->upstream->peer.data; + + if (rrp == NULL) { + rrp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_rr_peer_data_t)); + if (rrp == NULL) { + return NGX_ERROR; + } + + r->upstream->peer.data = rrp; + } + + rrp->peers = us->peer.data; + rrp->current = 0; + + if (rrp->peers->number <= 8 * sizeof(uintptr_t)) { + rrp->tried = &rrp->data; + rrp->data = 0; + + } else { + n = (rrp->peers->number + (8 * sizeof(uintptr_t) - 1)) + / (8 * sizeof(uintptr_t)); + + rrp->tried = ngx_pcalloc(r->pool, n * sizeof(uintptr_t)); + if (rrp->tried == NULL) { + return NGX_ERROR; + } + } + + r->upstream->peer.get = ngx_http_upstream_get_round_robin_peer; + r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; + r->upstream->peer.tries = rrp->peers->number; +#if (NGX_HTTP_SSL) + r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer; +#endif + + return NGX_OK; +} + + +ngx_int_t +ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_rr_peer_data_t *rrp = data; + + time_t now; + uintptr_t m; + ngx_uint_t i, n; + ngx_connection_t *c; + ngx_http_upstream_rr_peer_t *peer; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "get rr peer, try: %ui", pc->tries); + + now = ngx_time(); + + /* ngx_lock_mutex(rrp->peers->mutex); */ + + if (rrp->peers->last_cached) { + + /* cached connection */ + + c = rrp->peers->cached[rrp->peers->last_cached]; + rrp->peers->last_cached--; + + /* ngx_unlock_mutex(ppr->peers->mutex); */ + +#if (NGX_THREADS) + c->read->lock = c->read->own_lock; + c->write->lock = c->write->own_lock; +#endif + + pc->connection = c; + pc->cached = 1; + + return NGX_OK; + } + + pc->cached = 0; + pc->connection = NULL; + + if (rrp->peers->number == 1) { + peer = &rrp->peers->peer[0]; + + } else { + + /* there are several peers */ + + if (pc->tries == rrp->peers->number) { + + /* it's a first try - get a current peer */ + + for ( ;; ) { + rrp->current = rrp->peers->current; + + n = rrp->current / (8 * sizeof(uintptr_t)); + m = 1 << rrp->current % (8 * sizeof(uintptr_t)); + + if (!(rrp->tried[n] & m)) { + peer = &rrp->peers->peer[rrp->current]; + + if (!peer->down) { + + if (peer->max_fails == 0 + || peer->fails < peer->max_fails) + { + break; + } + + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + break; + } + + } else { + rrp->tried[n] |= m; + } + + pc->tries--; + } + + rrp->peers->current++; + + if (rrp->peers->current >= rrp->peers->number) { + rrp->peers->current = 0; + } + + if (pc->tries) { + continue; + } + + goto failed; + } + + peer->current_weight--; + + if (peer->current_weight == 0) { + peer->current_weight = peer->weight; + + rrp->peers->current++; + + if (rrp->peers->current >= rrp->peers->number) { + rrp->peers->current = 0; + } + } + + } else { + for ( ;; ) { + n = rrp->current / (8 * sizeof(uintptr_t)); + m = 1 << rrp->current % (8 * sizeof(uintptr_t)); + + if (!(rrp->tried[n] & m)) { + + peer = &rrp->peers->peer[rrp->current]; + + if (!peer->down) { + + if (peer->max_fails == 0 + || peer->fails < peer->max_fails) + { + break; + } + + if (now - peer->accessed > peer->fail_timeout) { + peer->fails = 0; + break; + } + + } else { + rrp->tried[n] |= m; + } + + pc->tries--; + } + + rrp->current++; + + if (rrp->current >= rrp->peers->number) { + rrp->current = 0; + } + + if (pc->tries) { + continue; + } + + goto failed; + } + + peer->current_weight--; + + if (peer->current_weight == 0) { + peer->current_weight = peer->weight; + + if (rrp->current == rrp->peers->current) { + rrp->peers->current++; + + if (rrp->peers->current >= rrp->peers->number) { + rrp->peers->current = 0; + } + } + } + } + + rrp->tried[n] |= m; + } + + pc->sockaddr = peer->sockaddr; + pc->socklen = peer->socklen; + pc->name = &peer->name; +#if (NGX_SSL) + pc->ssl_session = peer->ssl_session; +#endif + + /* ngx_unlock_mutex(rrp->peers->mutex); */ + + return NGX_OK; + +failed: + + /* all peers failed, mark them as live for quick recovery */ + + for (i = 0; i < rrp->peers->number; i++) { + rrp->peers->peer[i].fails = 0; + } + + /* ngx_unlock_mutex(rrp->peers->mutex); */ + + pc->name = rrp->peers->name; + + return NGX_BUSY; +} + + +void +ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data, + ngx_uint_t state) +{ + ngx_http_upstream_rr_peer_data_t *rrp = data; + + time_t now; + ngx_http_upstream_rr_peer_t *peer; + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "free rr peer %ui %ui", pc->tries, state); + + if (state == 0 && pc->tries == 0) { + return; + } + + /* TODO: NGX_PEER_KEEPALIVE */ + + if (rrp->peers->number == 1) { + pc->tries = 0; + return; + } + + if (state & NGX_PEER_FAILED) { + now = ngx_time(); + + peer = &rrp->peers->peer[rrp->current]; + + /* ngx_lock_mutex(rrp->peers->mutex); */ + + peer->fails++; + peer->accessed = now; + + if (peer->current_weight > 1) { + peer->current_weight /= 2; + } + + /* ngx_unlock_mutex(rrp->peers->mutex); */ + } + + rrp->current++; + + if (rrp->current >= rrp->peers->number) { + rrp->current = 0; + } + + if (pc->tries) { + pc->tries--; + } + + /* ngx_unlock_mutex(rrp->peers->mutex); */ +} + + +#if (NGX_HTTP_SSL) + +void +ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, void *data) +{ + ngx_http_upstream_rr_peer_data_t *rrp = data; + + ngx_ssl_session_t *ssl_session; + ngx_http_upstream_rr_peer_t *peer; + + ssl_session = ngx_ssl_get_session(pc->connection); + + if (ssl_session == NULL) { + return; + } + + peer = &rrp->peers->peer[rrp->current]; + + /* ngx_lock_mutex(rrp->peers->mutex); */ + peer->ssl_session = ssl_session; + /* ngx_unlock_mutex(rrp->peers->mutex); */ + + if (pc->ssl_session) { + /* TODO: may block */ + ngx_ssl_free_session(pc->ssl_session); + } +} + +#endif diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_upstream_round_robin.h @@ -0,0 +1,77 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ +#define _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t name; + + ngx_uint_t current_weight; + ngx_uint_t weight; + + ngx_uint_t fails; + time_t accessed; + + ngx_uint_t max_fails; + time_t fail_timeout; + + ngx_uint_t down; /* unsigned down:1; */ + +#if (NGX_SSL) + ngx_ssl_session_t *ssl_session; +#endif +} ngx_http_upstream_rr_peer_t; + + +typedef struct { + ngx_uint_t current; + + ngx_uint_t number; + ngx_uint_t last_cached; + + /* ngx_mutex_t *mutex; */ + ngx_connection_t **cached; + + ngx_str_t *name; + + ngx_http_upstream_rr_peer_t peer[1]; +} ngx_http_upstream_rr_peers_t; + + +typedef struct { + ngx_http_upstream_rr_peers_t *peers; + ngx_uint_t current; + uintptr_t *tried; + uintptr_t data; +} ngx_http_upstream_rr_peer_data_t; + + +ngx_int_t ngx_http_upstream_init_round_robin(ngx_conf_t *cf, + ngx_http_upstream_srv_conf_t *us); +ngx_int_t ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r, + ngx_http_upstream_srv_conf_t *us); +ngx_int_t ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, + void *data); +void ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, + void *data, ngx_uint_t state); + +#if (NGX_HTTP_SSL) +void ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, + void *data); +#endif + + + +#endif /* _NGX_HTTP_UPSTREAM_ROUND_ROBIN_H_INCLUDED_ */ diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -160,6 +160,7 @@ typedef struct { unsigned no_sync_literal:1; unsigned starttls:1; unsigned auth_method:2; + unsigned auth_wait:1; ngx_str_t login; ngx_str_t passwd; @@ -265,7 +266,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima /* STUB */ -void ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers); +void ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peer_addr_t *peer); void ngx_imap_auth_http_init(ngx_imap_session_t *s); /**/ diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -12,7 +12,7 @@ typedef struct { - ngx_peers_t *peers; + ngx_peer_addr_t *peer; ngx_msec_t timeout; @@ -175,7 +175,10 @@ ngx_imap_auth_http_init(ngx_imap_session ngx_imap_set_ctx(s, ctx, ngx_imap_auth_http_module); - ctx->peer.peers = ahcf->peers; + ctx->peer.sockaddr = ahcf->peer->sockaddr; + ctx->peer.socklen = ahcf->peer->socklen; + ctx->peer.name = &ahcf->peer->name; + ctx->peer.get = ngx_event_get_peer; ctx->peer.log = s->connection->log; ctx->peer.log_error = NGX_ERROR_ERR; @@ -229,8 +232,7 @@ ngx_imap_auth_http_write_handler(ngx_eve if (wev->timedout) { ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, - "auth http server %V timed out", - &ctx->peer.peers->peer[0].name); + "auth http server %V timed out", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); @@ -293,8 +295,7 @@ ngx_imap_auth_http_read_handler(ngx_even if (rev->timedout) { ngx_log_error(NGX_LOG_ERR, rev->log, NGX_ETIMEDOUT, - "auth http server %V timed out", - &ctx->peer.peers->peer[0].name); + "auth http server %V timed out", ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); @@ -413,7 +414,7 @@ ngx_imap_auth_http_ignore_status_line(ng ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server &V sent invalid response", - &ctx->peer.peers->peer[0].name); + ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); @@ -447,7 +448,7 @@ ngx_imap_auth_http_process_headers(ngx_i time_t timer; size_t len, size; ngx_int_t rc, port, n; - ngx_peers_t *peers; + ngx_peer_addr_t *peer; struct sockaddr_in *sin; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0, @@ -488,6 +489,16 @@ ngx_imap_auth_http_process_headers(ngx_i continue; } + if (len == 4 + && ctx->header_start[0] == 'W' + && ctx->header_start[1] == 'A' + && ctx->header_start[2] == 'I' + && ctx->header_start[3] == 'T') + { + s->auth_wait = 1; + continue; + } + ctx->errmsg.len = len; ctx->errmsg.data = ctx->header_start; @@ -632,10 +643,27 @@ ngx_imap_auth_http_process_headers(ngx_i return; } + if (s->auth_wait) { + timer = ctx->sleep; + + ngx_destroy_pool(ctx->pool); + + if (timer == 0) { + ngx_imap_auth_http_init(s); + return; + } + + ngx_add_timer(s->connection->read, timer * 1000); + + s->connection->read->handler = ngx_imap_auth_sleep_handler; + + return; + } + if (ctx->addr.len == 0 || ctx->port.len == 0) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send server or port", - &ctx->peer.peers->peer[0].name); + ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; @@ -644,14 +672,14 @@ ngx_imap_auth_http_process_headers(ngx_i if (s->passwd.data == NULL) { ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V did not send password", - &ctx->peer.peers->peer[0].name); + ctx->peer.name); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; } - peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { + peer = ngx_pcalloc(s->connection->pool, sizeof(ngx_peer_addr_t)); + if (peer == NULL) { ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; @@ -671,7 +699,7 @@ ngx_imap_auth_http_process_headers(ngx_i ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "port:\"%V\"", - &ctx->peer.peers->peer[0].name, &ctx->port); + ctx->peer.name, &ctx->port); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; @@ -685,23 +713,21 @@ ngx_imap_auth_http_process_headers(ngx_i ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid server " "address:\"%V\"", - &ctx->peer.peers->peer[0].name, &ctx->addr); + ctx->peer.name, &ctx->addr); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; } - peers->number = 1; - - peers->peer[0].sockaddr = (struct sockaddr *) sin; - peers->peer[0].socklen = sizeof(struct sockaddr_in); + peer->sockaddr = (struct sockaddr *) sin; + peer->socklen = sizeof(struct sockaddr_in); len = ctx->addr.len + 1 + ctx->port.len; - peers->peer[0].name.len = len; + peer->name.len = len; - peers->peer[0].name.data = ngx_palloc(s->connection->pool, len); - if (peers->peer[0].name.data == NULL) { + peer->name.data = ngx_palloc(s->connection->pool, len); + if (peer->name.data == NULL) { ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); return; @@ -709,17 +735,14 @@ ngx_imap_auth_http_process_headers(ngx_i len = ctx->addr.len; - ngx_memcpy(peers->peer[0].name.data, ctx->addr.data, len); - - peers->peer[0].name.data[len++] = ':'; + ngx_memcpy(peer->name.data, ctx->addr.data, len); - ngx_memcpy(peers->peer[0].name.data + len, - ctx->port.data, ctx->port.len); + peer->name.data[len++] = ':'; - peers->peer[0].uri_separator = ""; + ngx_memcpy(peer->name.data + len, ctx->port.data, ctx->port.len); ngx_destroy_pool(ctx->pool); - ngx_imap_proxy_init(s, peers); + ngx_imap_proxy_init(s, peer); return; } @@ -732,7 +755,7 @@ ngx_imap_auth_http_process_headers(ngx_i ngx_log_error(NGX_LOG_ERR, s->connection->log, 0, "auth http server %V sent invalid header in response", - &ctx->peer.peers->peer[0].name); + ctx->peer.name); ngx_close_connection(ctx->peer.connection); ngx_destroy_pool(ctx->pool); ngx_imap_session_internal_server_error(s); @@ -758,6 +781,12 @@ ngx_imap_auth_sleep_handler(ngx_event_t rev->timedout = 0; + if (s->auth_wait) { + s->auth_wait = 0; + ngx_imap_auth_http_init(s); + return; + } + if (s->protocol == NGX_IMAP_POP3_PROTOCOL) { s->imap_state = ngx_pop3_start; s->connection->read->handler = ngx_pop3_auth_state; @@ -1209,8 +1238,8 @@ ngx_imap_auth_http_merge_conf(ngx_conf_t ngx_uint_t i; ngx_table_elt_t *header; - if (conf->peers == NULL) { - conf->peers = prev->peers; + if (conf->peer == NULL) { + conf->peer = prev->peer; conf->host_header = prev->host_header; conf->uri = prev->uri; } @@ -1264,6 +1293,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c u.url = value[1]; u.default_portn = 80; u.uri_part = 1; + u.one_addr = 1; if (ngx_parse_url(cf, &u) != NGX_OK) { if (u.err) { @@ -1272,8 +1302,7 @@ ngx_imap_auth_http(ngx_conf_t *cf, ngx_c } } - ahcf->peers = u.peers; - ahcf->peers->number = 1; + ahcf->peer = u.addrs; ahcf->host_header = u.host_header; ahcf->uri = u.uri; diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -1279,8 +1279,7 @@ ngx_imap_log_error(ngx_log_t *log, u_cha return p; } - p = ngx_snprintf(buf, len, ", upstream: %V", - &s->proxy->upstream.peers->peer[0].name); + p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name); return p; } diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c --- a/src/imap/ngx_imap_proxy_module.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -94,7 +94,7 @@ ngx_module_t ngx_imap_proxy_module = { void -ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers) +ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peer_addr_t *peer) { int keepalive; ngx_int_t rc; @@ -125,7 +125,10 @@ ngx_imap_proxy_init(ngx_imap_session_t * s->proxy = p; - p->upstream.peers = peers; + p->upstream.sockaddr = peer->sockaddr; + p->upstream.socklen = peer->socklen; + p->upstream.name = &peer->name; + p->upstream.get = ngx_event_get_peer; p->upstream.log = s->connection->log; p->upstream.log_error = NGX_ERROR_ERR;