# HG changeset patch # User Igor Sysoev # Date 1148328000 -14400 # Node ID d2ae1c9f1fd3a9ecf4829f21979274cdb873a7a2 # Parent 869664706c099de75c8b73d970c341d953b84077 nginx 0.3.47 *) Feature: the "upstream" directive. *) Change: now the "\" escape symbol in the "\"" and "\'" pairs in the SSI command is always removed. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,12 @@ +Changes with nginx 0.3.47 23 May 2006 + + *) Feature: the "upstream" directive. + + *) Change: now the "\" escape symbol in the "\"" and "\'" pairs in the + SSI command is always removed. + + Changes with nginx 0.3.46 11 May 2006 *) Feature: the "proxy_hide_header", "proxy_pass_header", diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,10 +1,18 @@ +Изменения в nginx 0.3.47 23.05.2006 + + *) Добавление: директива upstream. + + *) Изменение: символ "\" в парах "\"" и "\'" в SSI командах теперь + всегда убирается. + + Изменения в nginx 0.3.46 11.05.2006 *) Добавление: директивы proxy_hide_header, proxy_pass_header, fastcgi_hide_header и fastcgi_pass_header. - *) Изменение: директивы proxy_x_powered_by, fastcgi_x_powered_by и + *) Изменение: директивы proxy_pass_x_powered_by, fastcgi_x_powered_by и proxy_pass_server упразднены. *) Добавление: в режиме прокси поддерживается строка заголовка 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_VER "nginx/0.3.46" +#define NGINX_VER "nginx/0.3.47" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -61,7 +61,7 @@ #define NGX_CONF_OK NULL -#define NGX_CONF_ERROR (char *) -1 +#define NGX_CONF_ERROR (void *) -1 #define NGX_CONF_BLOCK_START 1 #define NGX_CONF_BLOCK_DONE 2 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 @@ -63,6 +63,9 @@ typedef void (*ngx_connection_handler_pt #include #include #include +#if (NGX_OPENSSL) +#include +#endif #include #if (NGX_HAVE_UNIX_DOMAIN) #include @@ -71,9 +74,6 @@ typedef void (*ngx_connection_handler_pt #include #include #include -#if (NGX_OPENSSL) -#include -#endif #include diff --git a/src/core/ngx_cpuinfo.c b/src/core/ngx_cpuinfo.c --- a/src/core/ngx_cpuinfo.c +++ b/src/core/ngx_cpuinfo.c @@ -31,16 +31,14 @@ ngx_cpuid(uint32_t i, uint32_t *buf) " mov %%ebx, %%esi; " " cpuid; " - " mov %%eax, %0; " - " mov %%ebx, %1; " - " mov %%edx, %2; " - " mov %%ecx, %3; " + " mov %%eax, (%1); " + " mov %%ebx, 4(%1); " + " mov %%edx, 8(%1); " + " mov %%ecx, 12(%1); " " mov %%esi, %%ebx; " - : "=m" (buf[0]), "=m" (buf[1]), "=m" (buf[2]), "=m" (buf[3]) - : "a" (i) - : "ecx", "edx", "esi" ); + : : "a" (i), "D" (buf) : "ecx", "edx", "esi", "memory" ); } 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 @@ -220,6 +220,339 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) } +ngx_int_t +ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u) +{ + u_char *p; + size_t len; + ngx_int_t port; + ngx_uint_t i; +#if (NGX_HAVE_UNIX_DOMAIN) + struct sockaddr_un *saun; +#endif + + len = u->url.len; + p = u->url.data; + + if (ngx_strncasecmp(p, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + u->type = NGX_PARSE_URL_UNIX; + + p += 5; + len -= 5; + + if (u->uri_part) { + for (i = 0; i < len; i++) { + + if (p[i] == ':') { + len = i; + + u->uri.len -= len + 1; + u->uri.data += len + 1; + + break; + } + } + } + + if (len == 0) { + u->err = "no path in the unix domain socket"; + return NGX_ERROR; + } + + if (len + 1 > sizeof(saun->sun_path)) { + u->err = "too long path in the unix domain socket"; + return NGX_ERROR; + } + + u->peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); + if (u->peers == NULL) { + return NGX_ERROR; + } + + saun = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_un)); + if (saun == NULL) { + return NGX_ERROR; + } + + u->peers->number = 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 = u->url; + u->peers->peer[0].uri_separator = ":"; + + u->host_header.len = sizeof("localhost") - 1; + u->host_header.data = (u_char *) "localhost"; + + return NGX_OK; + +#else + u->err = "the unix domain sockets are not supported on this platform"; + + return NGX_ERROR; + +#endif + } + + if ((p[0] == ':' || p[0] == '/') && !u->listen) { + u->err = "invalid host"; + return NGX_ERROR; + } + + u->type = NGX_PARSE_URL_INET; + + u->host.data = p; + u->host_header.len = len; + u->host_header.data = p; + + for (i = 0; i < len; i++) { + + if (p[i] == ':') { + u->port.data = &p[i + 1]; + u->host.len = i; + + if (!u->uri_part) { + u->port.len = &p[len] - u->port.data; + break; + } + } + + if (p[i] == '/') { + u->uri.len = len - i; + u->uri.data = &p[i]; + u->host_header.len = i; + + if (u->host.len == 0) { + u->host.len = i; + } + + if (u->port.data == NULL) { + u->default_port = 1; + goto port; + } + + u->port.len = &p[i] - u->port.data; + + if (u->port.len == 0) { + u->err = "invalid port"; + return NGX_ERROR; + } + + break; + } + } + + if (u->port.data) { + + if (u->port.len == 0) { + u->port.len = &p[i] - u->port.data; + + if (u->port.len == 0) { + u->err = "invalid port"; + return NGX_ERROR; + } + } + + port = ngx_atoi(u->port.data, u->port.len); + + if (port == NGX_ERROR || port < 1 || port > 65536) { + u->err = "invalid port"; + return NGX_ERROR; + } + + } else { + port = ngx_atoi(p, len); + + if (port == NGX_ERROR) { + u->default_port = 1; + u->host.len = len; + + goto port; + } + + u->port.len = len; + u->port.data = p; + u->wildcard = 1; + } + + u->portn = (in_port_t) port; + +port: + + if (u->listen) { + return NGX_OK; + } + + if (u->default_port) { + + if (u->upstream) { + return NGX_OK; + } + + if (u->default_portn == 0) { + u->err = "no port"; + return NGX_ERROR; + } + + u->portn = u->default_portn; + + u->port.data = ngx_palloc(cf->pool, sizeof("65536") - 1); + if (u->port.data == NULL) { + return NGX_ERROR; + } + + 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 { + u->err = "no port"; + return NGX_ERROR; + } + + if (u->host.len == 0) { + u->err = "no host"; + return NGX_ERROR; + } + + u->peers = ngx_inet_resolve_peer(cf, &u->host, u->portn); + + if (u->peers == NULL) { + return NGX_ERROR; + } + + if (u->peers == NGX_CONF_ERROR) { + u->err = "host not found"; + return NGX_ERROR; + } + + return NGX_OK; +} + + +ngx_peers_t * +ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, in_port_t port) +{ + 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); + if (host == NULL) { + return NULL; + } + + (void) ngx_cpystrn(host, name->data, name->len + 1); + + /* AF_INET only */ + + in_addr = inet_addr((char *) host); + + if (in_addr == INADDR_NONE) { + h = gethostbyname((char *) host); + + if (h == NULL || h->h_addr_list[0] == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; h->h_addr_list[i] != NULL; i++) { /* void */ } + + /* MP: ngx_shared_palloc() */ + + peers = ngx_pcalloc(cf->pool, + sizeof(ngx_peers_t) + sizeof(ngx_peer_t) * (i - 1)); + if (peers == NULL) { + return NULL; + } + + peers->number = i; + peers->weight = 1; + + for (i = 0; h->h_addr_list[i] != NULL; i++) { + + sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NULL; + } + + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + 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); + + 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; + } + + len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, + peers->peer[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 = ""; + } + + } else { + + /* MP: ngx_shared_palloc() */ + + peers = ngx_pcalloc(cf->pool, sizeof(ngx_peers_t)); + if (peers == NULL) { + return NULL; + } + + sin = ngx_pcalloc(cf->pool, sizeof(struct sockaddr_in)); + if (sin == NULL) { + return NULL; + } + + peers->number = 1; + + sin->sin_family = AF_INET; + sin->sin_port = htons(port); + sin->sin_addr.s_addr = in_addr; + + peers->peer[0].sockaddr = (struct sockaddr *) sin; + peers->peer[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; + } + + 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 = ""; + } + + return peers; +} + + ngx_peers_t * ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u) { @@ -241,6 +574,7 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, } if (u->default_port) { + if (u->default_port_value == 0) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no port in upstream \"%V\"", &u->name); @@ -277,7 +611,7 @@ ngx_inet_upstream_parse(ngx_conf_t *cf, u->port = htons(u->port); - host = ngx_palloc(cf->pool, u->host.len + 1); + host = ngx_palloc(cf->temp_pool, u->host.len + 1); if (host == NULL) { return NULL; } 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,6 +12,10 @@ #include +#define NGX_PARSE_URL_INET 1 +#define NGX_PARSE_URL_UNIX 2 + + typedef struct { in_addr_t addr; in_addr_t mask; @@ -19,6 +23,66 @@ typedef struct { typedef struct { + struct sockaddr *sockaddr; + socklen_t socklen; + + ngx_str_t name; + char *uri_separator; + + 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 weight; + + ngx_uint_t number; + ngx_uint_t last_cached; + + /* ngx_mutex_t *mutex; */ + ngx_connection_t **cached; + + ngx_peer_t peer[1]; +}; + + +typedef struct { + ngx_int_t type; + + 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; + + in_port_t portn; + in_port_t default_portn; + + unsigned listen:1; + unsigned uri_part:1; + unsigned upstream:1; + + unsigned default_port:1; + unsigned wildcard:1; + + char *err; +} ngx_url_t; + + +typedef struct { ngx_str_t name; /* "schema:host:port/uri" */ ngx_str_t url; /* "host:port/uri" */ ngx_str_t host; @@ -35,6 +99,7 @@ typedef struct { unsigned uri_part:1; unsigned port_only:1; + unsigned virtual:1; } ngx_inet_upstream_t; @@ -45,7 +110,10 @@ size_t ngx_inet_ntop(int family, void *a ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); ngx_peers_t *ngx_inet_upstream_parse(ngx_conf_t *cf, ngx_inet_upstream_t *u); +ngx_peers_t *ngx_inet_resolve_peer(ngx_conf_t *cf, ngx_str_t *name, + in_port_t port); char *ngx_inet_parse_host_port(ngx_inet_upstream_t *u); +ngx_int_t ngx_parse_url(ngx_conf_t *cf, ngx_url_t *u); #endif /* _NGX_INET_H_INCLUDED_ */ diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c --- a/src/core/ngx_parse.c +++ b/src/core/ngx_parse.c @@ -50,10 +50,10 @@ ngx_parse_size(ngx_str_t *line) ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec) { - size_t len; - u_char *start, last; - ngx_int_t value, total, scale; - ngx_uint_t max, i; + size_t len; + u_char *start, last; + ngx_int_t value, total, scale; + ngx_uint_t max, i; enum { st_start = 0, st_year, 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 @@ -14,41 +14,6 @@ typedef struct { - struct sockaddr *sockaddr; - socklen_t socklen; - - ngx_str_t name; - char *uri_separator; - - 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 weight; - - ngx_uint_t number; - ngx_uint_t last_cached; - - /* ngx_mutex_t *mutex; */ - ngx_connection_t **cached; - - ngx_peer_t peer[1]; -}; - - -typedef struct { ngx_peers_t *peers; ngx_uint_t cur_peer; ngx_uint_t tries; diff --git a/src/http/modules/ngx_http_empty_gif_module.c b/src/http/modules/ngx_http_empty_gif_module.c --- a/src/http/modules/ngx_http_empty_gif_module.c +++ b/src/http/modules/ngx_http_empty_gif_module.c @@ -135,7 +135,7 @@ ngx_http_empty_gif_handler(ngx_http_requ } } - b = ngx_create_temp_buf(r->pool, sizeof(ngx_empty_gif)); + b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t)); if (b == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } @@ -145,6 +145,7 @@ ngx_http_empty_gif_handler(ngx_http_requ b->pos = ngx_empty_gif; b->last = ngx_empty_gif + sizeof(ngx_empty_gif); + b->memory = 1; b->last_buf = 1; r->headers_out.status = NGX_HTTP_OK; diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -11,16 +11,17 @@ typedef struct { - ngx_http_upstream_conf_t upstream; - - ngx_peers_t *peers; - - ngx_str_t index; - - ngx_array_t *flushes; - ngx_array_t *params_len; - ngx_array_t *params; - ngx_array_t *params_source; + 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; + ngx_array_t *params_len; + ngx_array_t *params; + ngx_array_t *params_source; } ngx_http_fastcgi_loc_conf_t; @@ -39,14 +40,14 @@ typedef enum { typedef struct { - ngx_http_fastcgi_state_e state; - u_char *pos; - u_char *last; - ngx_uint_t type; - size_t length; - size_t padding; - - ngx_uint_t fastcgi_stdout; + ngx_http_fastcgi_state_e state; + u_char *pos; + u_char *last; + ngx_uint_t type; + size_t length; + size_t padding; + + ngx_uint_t fastcgi_stdout; } ngx_http_fastcgi_ctx_t; @@ -391,8 +392,8 @@ ngx_http_fastcgi_handler(ngx_http_reques u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = flcf->peers; - u->peer.tries = flcf->peers->number; + 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 @@ -1687,11 +1688,13 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf 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; + if (conf->upstream_peers && !conf->upstream_peers->balanced) { + for (i = 0; i < conf->upstream_peers->peers->number; i++) { + conf->upstream_peers->peers->peer[i].weight = 1; + conf->upstream_peers->peers->peer[i].max_fails = + conf->upstream.max_fails; + conf->upstream_peers->peers->peer[i].fail_timeout = + conf->upstream.fail_timeout; } } @@ -1813,8 +1816,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf peers: - if (conf->peers == NULL) { - conf->peers = prev->peers; + if (conf->upstream_peers == NULL) { + conf->upstream_peers = prev->upstream_peers; conf->upstream.schema = prev->upstream.schema; } @@ -1989,12 +1992,9 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng { ngx_http_fastcgi_loc_conf_t *lcf = conf; + ngx_url_t u; ngx_str_t *value; - ngx_inet_upstream_t inet_upstream; ngx_http_core_loc_conf_t *clcf; -#if (NGX_HAVE_UNIX_DOMAIN) - ngx_unix_domain_upstream_t unix_upstream; -#endif if (lcf->upstream.schema.len) { return "is duplicate"; @@ -2002,40 +2002,14 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng value = cf->args->elts; - if (ngx_strncasecmp(value[1].data, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - - unix_upstream.name = value[1]; - unix_upstream.url = value[1]; - - lcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - lcf->peers->peer[0].uri_separator = ""; - -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain sockets are not supported " - "on this platform"); + 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) { return NGX_CONF_ERROR; - -#endif - - } else { - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.name = value[1]; - inet_upstream.url = value[1]; - - lcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (lcf->peers == NULL) { - return NGX_CONF_ERROR; - } } lcf->upstream.schema.len = sizeof("fastcgi://") - 1; 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 @@ -16,56 +16,56 @@ typedef ngx_int_t (*ngx_http_proxy_redir ngx_table_elt_t *h, size_t prefix, ngx_http_proxy_redirect_t *pr); struct ngx_http_proxy_redirect_s { - ngx_http_proxy_redirect_pt handler; - ngx_str_t redirect; + ngx_http_proxy_redirect_pt handler; + ngx_str_t redirect; union { - ngx_str_t text; + ngx_str_t text; struct { - void *lengths; - void *values; + void *lengths; + void *values; } vars; - void *regex; + void *regex; } replacement; }; typedef struct { - ngx_http_upstream_conf_t upstream; - - ngx_peers_t *peers; - - ngx_array_t *flushes; - ngx_array_t *body_set_len; - ngx_array_t *body_set; - ngx_array_t *headers_set_len; - ngx_array_t *headers_set; - ngx_hash_t headers_set_hash; - - ngx_array_t *headers_source; - ngx_array_t *headers_names; - - ngx_array_t *redirects; - - ngx_str_t body_source; - - ngx_str_t method; - ngx_str_t host_header; - ngx_str_t port_text; - - ngx_flag_t redirect; + 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; + ngx_array_t *headers_set_len; + ngx_array_t *headers_set; + ngx_hash_t headers_set_hash; + + ngx_array_t *headers_source; + ngx_array_t *headers_names; + + ngx_array_t *redirects; + + ngx_str_t body_source; + + ngx_str_t method; + ngx_str_t host_header; + ngx_str_t port_text; + + ngx_flag_t redirect; } ngx_http_proxy_loc_conf_t; typedef struct { - ngx_uint_t status; - ngx_uint_t status_count; - u_char *status_start; - u_char *status_end; - - size_t internal_body_length; + ngx_uint_t status; + ngx_uint_t status_count; + u_char *status_start; + u_char *status_end; + + size_t internal_body_length; } ngx_http_proxy_ctx_t; @@ -407,8 +407,8 @@ ngx_http_proxy_handler(ngx_http_request_ u->peer.log = r->connection->log; u->peer.log_error = NGX_ERROR_ERR; - u->peer.peers = plcf->peers; - u->peer.tries = plcf->peers->number; + 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 @@ -1640,11 +1640,13 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t 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; + if (conf->upstream_peers && !conf->upstream_peers->balanced) { + for (i = 0; i < conf->upstream_peers->peers->number; i++) { + conf->upstream_peers->peers->peer[i].weight = 1; + conf->upstream_peers->peers->peer[i].max_fails = + conf->upstream.max_fails; + conf->upstream_peers->peers->peer[i].fail_timeout = + conf->upstream.fail_timeout; } } @@ -1797,8 +1799,8 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t peers: - if (conf->peers == NULL) { - conf->peers = prev->peers; + if (conf->upstream_peers == NULL) { + conf->upstream_peers = prev->upstream_peers; conf->host_header = prev->host_header; conf->port_text = prev->port_text; @@ -2106,14 +2108,11 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ size_t add; u_short port; ngx_str_t *value, *url; - ngx_inet_upstream_t inet_upstream; + ngx_url_t u; ngx_http_core_loc_conf_t *clcf; #if (NGX_HTTP_SSL) ngx_pool_cleanup_t *cln; #endif -#if (NGX_HAVE_UNIX_DOMAIN) - ngx_unix_domain_upstream_t unix_upstream; -#endif if (plcf->upstream.schema.len) { return "is duplicate"; @@ -2167,53 +2166,23 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } - if (ngx_strncasecmp(url->data + add, "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); - - unix_upstream.name = *url; - unix_upstream.url.len = url->len - add; - unix_upstream.url.data = url->data + add; - unix_upstream.uri_part = 1; - - plcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); - if (plcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - plcf->host_header.len = sizeof("localhost") - 1; - plcf->host_header.data = (u_char *) "localhost"; - plcf->upstream.uri = unix_upstream.uri; - -#else - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the unix domain sockets are not supported " - "on this platform"); + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url.len = url->len - add; + u.url.data = url->data + add; + u.default_portn = port; + u.uri_part = 1; + u.upstream = 1; + + plcf->upstream_peers = ngx_http_upstream_add(cf, &u); + if (plcf->upstream_peers == NULL) { return NGX_CONF_ERROR; - -#endif - - } else { - ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); - - inet_upstream.name = *url; - inet_upstream.url.len = url->len - add; - inet_upstream.url.data = url->data + add; - inet_upstream.default_port_value = port; - inet_upstream.uri_part = 1; - - plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); - if (plcf->peers == NULL) { - return NGX_CONF_ERROR; - } - - plcf->host_header = inet_upstream.host_header; - plcf->port_text = inet_upstream.port_text; - plcf->upstream.uri = inet_upstream.uri; } + plcf->host_header = u.host_header; + plcf->port_text = u.port; + plcf->upstream.uri = u.uri; + plcf->upstream.schema.len = add; plcf->upstream.schema.data = url->data; diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -1224,38 +1224,14 @@ ngx_http_ssi_parse(ngx_http_request_t *r case ssi_quoted_symbol_state: state = ctx->saved_state; - if (ch == '\\') { - break; - } - - if (ch == '"' && state == ssi_double_quoted_value_state) { - ctx->param->value.data[ctx->param->value.len - 1] = ch; - break; - } - - if (ch == '\'' && state == ssi_quoted_value_state) { - ctx->param->value.data[ctx->param->value.len - 1] = ch; - break; - } - - if (ctx->param->value.len == ctx->value_len) { - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "too long \"%V%c...\" value of \"%V\" " - "parameter in \"%V\" SSI command", - &ctx->param->value, ch, &ctx->param->key, - &ctx->command); - state = ssi_error_state; - break; - } - ctx->param->value.data[ctx->param->value.len++] = ch; break; case ssi_postparam_state: - if (ctx->param->value.len < ctx->value_len / 2) { - value = ngx_palloc(r->pool, ctx->param->value.len); + if (ctx->param->value.len + 1 < ctx->value_len / 2) { + value = ngx_palloc(r->pool, ctx->param->value.len + 1); if (value == NULL) { return NGX_ERROR; } @@ -1433,7 +1409,7 @@ ngx_http_ssi_evaluate_string(ngx_http_re size_t *size, len, prefix, part_len; ngx_str_t var, *val; ngx_int_t key; - ngx_uint_t i, j, n, bracket; + ngx_uint_t i, j, n, bracket, quoted; ngx_array_t lengths, values; ngx_http_variable_value_t *vv; @@ -1567,18 +1543,28 @@ ngx_http_ssi_evaluate_string(ngx_http_re } else { part_data = &text->data[i]; + quoted = 0; for (p = part_data; i < text->len; i++) { ch = text->data[i]; - if (ch == '$') { - if (text->data[i - 1] != '\\') { + if (!quoted) { + + if (ch == '\\') { + quoted = 1; + continue; + } + + if (ch == '$') { break; } - *(p - 1) = ch; - - continue; + } else { + quoted = 0; + + if (ch != '\\' && ch != '\'' && ch != '"' && ch != '$') { + *p++ = '\\'; + } } *p++ = ch; @@ -2016,7 +2002,7 @@ ngx_http_ssi_if(ngx_http_request_t *r, n flags = 0; if (p < last - 1 && p[0] == '\\' && p[1] == '/') { - p++; + p++; } } diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- a/src/http/modules/perl/ngx_http_perl_module.c +++ b/src/http/modules/perl/ngx_http_perl_module.c @@ -399,6 +399,24 @@ ngx_http_perl_ssi(ngx_http_request_t *r, dTHXa(ctx->perl); +#if 0 + + /* the code is disabled to force the precompiled perl code using only */ + + ngx_http_perl_eval_anon_sub(aTHX_ handler, &sv); + + if (sv == &PL_sv_undef) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "eval_pv(\"%V\") failed", handler); + return NGX_ERROR; + } + + if (sv == NULL) { + sv = newSVpvn((char *) handler->data, handler->len); + } + +#endif + sv = newSVpvn((char *) handler->data, handler->len); rc = ngx_http_perl_call_handler(aTHX_ r, sv, ¶ms[NGX_HTTP_PERL_SSI_ARG], diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -106,7 +106,7 @@ static ngx_command_t ngx_http_core_comm NULL }, { ngx_string("server"), - NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_MULTI|NGX_CONF_NOARGS, ngx_http_core_server, 0, 0, @@ -506,7 +506,6 @@ ngx_http_handler(ngx_http_request_t *r) r->valid_unparsed_uri = 1; r->valid_location = 1; r->uri_changed = 1; - r->uri_changes = NGX_HTTP_MAX_REWRITE_CYCLES + 1; r->phase = (r == r->main) ? NGX_HTTP_POST_READ_PHASE: NGX_HTTP_SERVER_REWRITE_PHASE; @@ -547,7 +546,7 @@ ngx_http_core_run_phases(ngx_http_reques if (r->uri_changes == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "rewrite cycle"); + "rewrite or internal redirection cycle"); ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } @@ -1263,6 +1262,8 @@ ngx_http_subrequest(ngx_http_request_t * sr->discard_body = r->discard_body; sr->main_filter_need_in_memory = r->main_filter_need_in_memory; + sr->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; + ngx_http_handler(sr); if (!c->destroyed) { @@ -1331,6 +1332,8 @@ ngx_http_internal_redirect(ngx_http_requ r->internal = 1; r->method = NGX_HTTP_GET; + r->uri_changes--; + ngx_http_handler(r); return NGX_DONE; @@ -1794,7 +1797,7 @@ ngx_http_core_create_main_conf(ngx_conf_ if (ngx_array_init(&cmcf->servers, cf->pool, 4, sizeof(ngx_http_core_srv_conf_t *)) - == NGX_ERROR) + != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -666,6 +666,8 @@ ngx_http_process_request_line(ngx_event_ c->write->handler = ngx_http_request_handler; r->read_event_handler = ngx_http_block_read; + r->uri_changes = NGX_HTTP_MAX_URI_CHANGES + 1; + ngx_http_handler(r); return; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -8,7 +8,7 @@ #define _NGX_HTTP_REQUEST_H_INCLUDED_ -#define NGX_HTTP_MAX_REWRITE_CYCLES 10 +#define NGX_HTTP_MAX_URI_CHANGES 10 /* must be 2^n */ #define NGX_HTTP_LC_HEADER_LEN 32 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 @@ -85,8 +85,12 @@ static ngx_int_t ngx_http_upstream_statu static ngx_int_t ngx_http_upstream_response_time_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static char *ngx_http_upstream(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); +static char *ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static void *ngx_http_upstream_create_main_conf(ngx_conf_t *cf); -static char *ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf); +static char *ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf); #if (NGX_HTTP_SSL) static void ngx_http_upstream_ssl_init_connection(ngx_http_request_t *, @@ -206,12 +210,32 @@ ngx_http_upstream_header_t ngx_http_ups }; -ngx_http_module_t ngx_http_upstream_module_ctx = { +static ngx_command_t ngx_http_upstream_commands[] = { + + { ngx_string("upstream"), + NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, + ngx_http_upstream, + 0, + 0, + NULL }, + + { ngx_string("server"), + NGX_HTTP_UPS_CONF|NGX_CONF_TAKE1, + ngx_http_upstream_server, + NGX_HTTP_SRV_CONF_OFFSET, + 0, + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_upstream_module_ctx = { ngx_http_upstream_add_variables, /* preconfiguration */ NULL, /* postconfiguration */ ngx_http_upstream_create_main_conf, /* create main configuration */ - ngx_http_core_init_main_conf, /* init main configuration */ + ngx_http_upstream_init_main_conf, /* init main configuration */ NULL, /* create server configuration */ NULL, /* merge server configuration */ @@ -224,7 +248,7 @@ ngx_http_module_t ngx_http_upstream_mod ngx_module_t ngx_http_upstream_module = { NGX_MODULE_V1, &ngx_http_upstream_module_ctx, /* module context */ - NULL, /* module directives */ + ngx_http_upstream_commands, /* module directives */ NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ @@ -868,6 +892,14 @@ ngx_http_upstream_send_request_handler(n #endif + if (u->header_sent) { + wev->handler = ngx_http_upstream_dummy_handler; + + (void) ngx_handle_write_event(wev, 0); + + return; + } + ngx_http_upstream_send_request(r, u); } @@ -2547,6 +2579,232 @@ 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; + + 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; + } + + /* the upstream{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_http_upstream_module.ctx_index] = uscf; + + + /* the upstream{}'s loc_conf */ + + ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); + if (ctx->loc_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_HTTP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->create_loc_conf) { + mconf = module->create_loc_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->loc_conf[ngx_modules[m]->ctx_index] = mconf; + } + } + + + /* parse inside upstream{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_HTTP_UPS_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (uscf->servers == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "no servers are inside upstream"); + 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; + uscf->peers->weight = 1; + + 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; +} + + +static char * +ngx_http_upstream_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_upstream_srv_conf_t *uscf = conf; + + ngx_str_t *value; + ngx_url_t u; + ngx_peers_t **peers; + + if (uscf->servers == NULL) { + uscf->servers = ngx_array_create(cf->pool, 4, sizeof(ngx_peers_t *)); + if (uscf->servers == NULL) { + return NGX_CONF_ERROR; + } + } + + peers = ngx_array_push(uscf->servers); + if (peers == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + + ngx_memzero(&u, sizeof(ngx_url_t)); + + u.url = value[1]; + u.default_portn = 80; + + if (ngx_parse_url(cf, &u) != NGX_OK) { + if (u.err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u.err, &u.url); + } + + return NGX_CONF_ERROR; + } + + *peers = u.peers; + + return NGX_CONF_OK; +} + + +ngx_http_upstream_srv_conf_t * +ngx_http_upstream_add(ngx_conf_t *cf, ngx_url_t *u) +{ + ngx_uint_t i; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + if (u->upstream) { + if (ngx_parse_url(cf, u) != NGX_OK) { + if (u->err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in upstream \"%V\"", u->err, &u->url); + } + + 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); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + if (uscfp[i]->host.len != u->host.len) { + continue; + } + + if (ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len) + == 0) + { + return uscfp[i]; + } + } + + uscf = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_srv_conf_t)); + if (uscf == NULL) { + return NULL; + } + + uscf->host = u->host; + uscf->file_name = cf->conf_file->file.name; + uscf->line = cf->conf_file->line; + uscf->port = u->default_portn; + + uscfp = ngx_array_push(&umcf->upstreams); + if (uscfp == NULL) { + return NULL; + } + + *uscfp = uscf; + + return uscf; +} + + static void * ngx_http_upstream_create_main_conf(ngx_conf_t *cf) { @@ -2557,19 +2815,51 @@ ngx_http_upstream_create_main_conf(ngx_c return NULL; } + if (ngx_array_init(&umcf->upstreams, cf->pool, 4, + sizeof(ngx_http_upstream_srv_conf_t *)) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + return umcf; } static char * -ngx_http_core_init_main_conf(ngx_conf_t *cf, void *conf) +ngx_http_upstream_init_main_conf(ngx_conf_t *cf, void *conf) { ngx_http_upstream_main_conf_t *umcf = conf; - ngx_array_t headers_in; - ngx_hash_key_t *hk; - ngx_hash_init_t hash; - ngx_http_upstream_header_t *header; + ngx_uint_t i; + ngx_array_t headers_in; + ngx_hash_key_t *hk; + ngx_hash_init_t hash; + 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); + return NGX_CONF_ERROR; + } + } 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 @@ -42,10 +42,26 @@ typedef struct { typedef struct { ngx_hash_t headers_in_hash; + ngx_array_t upstreams; + /* ngx_http_upstream_srv_conf_t */ } ngx_http_upstream_main_conf_t; typedef struct { + ngx_peers_t *peers; + + ngx_array_t *servers; + + ngx_str_t host; + ngx_str_t file_name; + ngx_uint_t line; + in_port_t port; + + ngx_uint_t balanced; /* unsigned balanced:1; */ +} ngx_http_upstream_srv_conf_t; + + +typedef struct { ngx_msec_t connect_timeout; ngx_msec_t send_timeout; ngx_msec_t read_timeout; @@ -199,6 +215,8 @@ 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); extern ngx_module_t ngx_http_upstream_module;