# HG changeset patch # User Igor Sysoev # Date 1134853200 -10800 # Node ID 55a211e5eeb7a4096049b2d280b9d838b2a3c80b # Parent 9cee8bc94578e0cebfda68fcbe3804273656a031 nginx 0.3.17 *) Change: now on Linux configure checks the presence of epoll and sendfile64() in kernel. *) Feature: the "map" directive supports domain names in the ".domain.tld" form. *) Bugfix: the timeouts were not used in SSL handshake; bug appeared in 0.2.4. *) Bugfix: in the HTTPS protocol in the "proxy_pass" directive. *) Bugfix: when the HTTPS protocol was used in the "proxy_pass" directive the port 80 was used by default. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,19 @@ + +Changes with nginx 0.3.17 18 Dec 2005 + + *) Change: now on Linux configure checks the presence of epoll and + sendfile64() in kernel. + + *) Feature: the "map" directive supports domain names in the + ".domain.tld" form. + + *) Bugfix: the timeouts were not used in SSL handshake. + + *) Bugfix: in the HTTP protocol in the "proxy_pass" directive. + + *) Bugfix: when the HTTP protocol was used in the "proxy_pass" + directive the port 80 was used by default. + Changes with nginx 0.3.16 16 Dec 2005 @@ -113,7 +129,7 @@ Changes with nginx 0.3.10 *) Feature: the "if" directive supports the "=" and "!=" operations. - *) Feature: the "proxy_set_body" directive supports the HTTPS protocol. + *) Feature: the "proxy_pass" directive supports the HTTPS protocol. *) Feature: the "proxy_set_body" directive. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,19 @@ + +Изменения в nginx 0.3.17 18.12.2005 + + *) Изменение: на Linux configure теперь проверяет наличие epoll и + sendfile64() в ядре. + + *) Добавление: директива map поддерживает доменные имена в формате + ".domain.tld". + + *) Исправление: во время SSL handshake не иcпользовались таймауты. + + *) Исправление: в использовании протокола HTTPS в директиве proxy_pass. + + *) Исправление: при использовании протокола HTTPS в директиве + proxy_pass по умолчанию использовался порт 80. + Изменения в nginx 0.3.16 16.12.2005 diff --git a/auto/os/linux b/auto/os/linux --- a/auto/os/linux +++ b/auto/os/linux @@ -38,7 +38,7 @@ fi ngx_feature="epoll" ngx_feature_name="NGX_HAVE_EPOLL" -ngx_feature_run=no +ngx_feature_run=yes ngx_feature_incs="#include " ngx_feature_libs= ngx_feature_test="int efd = 0, fd = 1, n; @@ -62,12 +62,14 @@ fi CC_AUX_FLAGS="-D_GNU_SOURCE" ngx_feature="sendfile()" ngx_feature_name="NGX_HAVE_SENDFILE" -ngx_feature_run=no -ngx_feature_incs="#include " +ngx_feature_run=yes +ngx_feature_incs="#include +#include " ngx_feature_libs= ngx_feature_test="int s = 0, fd = 1; ssize_t n; off_t off = 0; - n = sendfile(s, fd, &off, 1)" + n = sendfile(s, fd, &off, 1); + if (n == -1 && errno == ENOSYS) return 1" . auto/feature if [ $ngx_found = yes ]; then @@ -80,12 +82,14 @@ fi CC_AUX_FLAGS="-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64" ngx_feature="sendfile64()" ngx_feature_name="NGX_HAVE_SENDFILE64" -ngx_feature_run=no -ngx_feature_incs="#include " +ngx_feature_run=yes +ngx_feature_incs="#include +#include " ngx_feature_libs= ngx_feature_test="int s = 0, fd = 1; ssize_t n; off_t off = 0; - n = sendfile(s, fd, &off, 1)" + n = sendfile(s, fd, &off, 1); + if (n == -1 && errno == ENOSYS) return 1" . auto/feature diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -266,6 +266,7 @@ HTTP_DEPS="src/http/ngx_http.h \ HTTP_SRCS="src/http/ngx_http.c \ src/http/ngx_http_core_module.c \ + src/http/ngx_http_config.c \ src/http/ngx_http_special_response.c \ src/http/ngx_http_request.c \ src/http/ngx_http_parse.c \ 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.16" +#define NGINX_VER "nginx/0.3.17" #define NGINX_VAR "NGINX" #define NGX_OLDPID_EXT ".oldbin" diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -76,10 +76,6 @@ ngx_hash_find_wildcard(ngx_hash_wildcard n--; } - if (n == 0) { - return NULL; - } - key = 0; for (i = n; i < len; i++) { @@ -93,8 +89,28 @@ ngx_hash_find_wildcard(ngx_hash_wildcard value = ngx_hash_find(&hwc->hash, key, &name[n], len - n); if (value) { + + /* + * the 2 low bits of value have the special meaning: + * 00 - value is data pointer, + * 01 - value is pointer to wildcard hash allowing + * "*.example.com" only, + * 11 - value is pointer to wildcard hash allowing + * both "example.com" and "*.example.com". + */ + if ((uintptr_t) value & 1) { - hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~1); + + hwc = (ngx_hash_wildcard_t *) ((uintptr_t) value & (uintptr_t) ~3); + + if (n == 0) { + if ((uintptr_t) value & 2) { + return hwc->value; + + } else { + return NULL; + } + } value = ngx_hash_find_wildcard(hwc, name, n - 1); @@ -332,7 +348,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * ngx_uint_t nelts) { size_t len; - ngx_uint_t i, n; + ngx_uint_t i, n, dot; ngx_array_t curr_names, next_names; ngx_hash_key_t *name, *next_name; ngx_hash_init_t h; @@ -359,9 +375,11 @@ ngx_hash_wildcard_init(ngx_hash_init_t * "wc0: \"%V\"", &names[n].key); #endif + dot = 0; + for (len = 0; len < names[n].key.len; len++) { if (names[n].key.data[len] == '.') { - len++; + dot = 1; break; } } @@ -371,7 +389,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * return NGX_ERROR; } - name->key.len = len - 1; + name->key.len = len; name->key.data = names[n].key.data; name->key_hash = hinit->key(name->key.data, name->key.len); name->value = names[n].value; @@ -381,6 +399,10 @@ ngx_hash_wildcard_init(ngx_hash_init_t * "wc1: \"%V\"", &name->key); #endif + if (dot) { + len++; + } + next_names.nelts = 0; if (names[n].key.len != len) { @@ -417,7 +439,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * #if 0 ngx_log_error(NGX_LOG_ALERT, hinit->pool->log, 0, - "wc2: \"%V\"", &next_name->key); + "wc3: \"%V\"", &next_name->key); #endif } @@ -442,7 +464,7 @@ ngx_hash_wildcard_init(ngx_hash_init_t * #endif } - name->value = (void *) ((uintptr_t) wdc | 1); + name->value = (void *) ((uintptr_t) wdc | (dot ? 1 : 3)); } } diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -334,6 +334,7 @@ ngx_ssl_handshake(ngx_connection_t *c) if (sslerr == SSL_ERROR_WANT_READ) { c->read->ready = 0; c->read->handler = ngx_ssl_handshake_handler; + c->write->handler = ngx_ssl_handshake_handler; if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { return NGX_ERROR; @@ -344,6 +345,7 @@ ngx_ssl_handshake(ngx_connection_t *c) if (sslerr == SSL_ERROR_WANT_WRITE) { c->write->ready = 0; + c->read->handler = ngx_ssl_handshake_handler; c->write->handler = ngx_ssl_handshake_handler; if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { @@ -357,6 +359,7 @@ ngx_ssl_handshake(ngx_connection_t *c) c->ssl->no_wait_shutdown = 1; c->ssl->no_send_shutdown = 1; + c->read->eof = 1; if (sslerr == SSL_ERROR_ZERO_RETURN || ERR_peek_error() == 0) { ngx_log_error(NGX_LOG_INFO, c->log, err, @@ -365,6 +368,8 @@ ngx_ssl_handshake(ngx_connection_t *c) return NGX_ERROR; } + c->read->error = 1; + ngx_ssl_connection_error(c, sslerr, err, "SSL_do_handshake() failed"); return NGX_ERROR; @@ -381,6 +386,11 @@ ngx_ssl_handshake_handler(ngx_event_t *e ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL handshake handler: %d", ev->write); + if (ev->timedout) { + c->ssl->handler(c); + return; + } + if (ngx_ssl_handshake(c) == NGX_AGAIN) { return; } @@ -548,6 +558,7 @@ ngx_ssl_handle_recv(ngx_connection_t *c, return NGX_DONE; } + c->read->error = 1; ngx_ssl_connection_error(c, sslerr, err, "SSL_read() failed"); return NGX_ERROR; @@ -773,6 +784,7 @@ ngx_ssl_write(ngx_connection_t *c, u_cha c->ssl->no_wait_shutdown = 1; c->ssl->no_send_shutdown = 1; + c->write->error = 1; ngx_ssl_connection_error(c, sslerr, err, "SSL_write() failed"); @@ -795,6 +807,7 @@ ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c) { int n, sslerr, mode; + ngx_err_t err; ngx_uint_t again; if (c->timedout) { @@ -866,7 +879,9 @@ ngx_ssl_shutdown(ngx_connection_t *c) return NGX_AGAIN; } - ngx_ssl_error(NGX_LOG_ALERT, c->log, 0, "SSL_shutdown() failed"); + err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0; + + ngx_ssl_connection_error(c, sslerr, err, "SSL_shutdown() failed"); SSL_free(c->ssl->connection); c->ssl = NULL; diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -9,8 +9,6 @@ #include -#define NGX_HTTP_MAP_HASH 10007 - typedef struct { ngx_uint_t hash_max_size; ngx_uint_t hash_bucket_size; @@ -18,13 +16,7 @@ typedef struct { typedef struct { - ngx_pool_t *pool; - - ngx_array_t keys; - ngx_array_t *keys_hash; - - ngx_array_t dns_wildcards; - ngx_array_t *dns_hash; + ngx_http_hash_conf_t hash; ngx_array_t *values_hash; @@ -253,40 +245,44 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - if (ngx_array_init(&ctx.keys, pool, 16384, sizeof(ngx_hash_key_t)) + if (ngx_array_init(&ctx.hash.keys, pool, 16384, sizeof(ngx_hash_key_t)) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - if (ngx_array_init(&ctx.dns_wildcards, pool, 16384, sizeof(ngx_hash_key_t)) + if (ngx_array_init(&ctx.hash.dns_wildcards, pool, 16384, + sizeof(ngx_hash_key_t)) != NGX_OK) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - ctx.keys_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * NGX_HTTP_MAP_HASH); - if (ctx.keys_hash == NULL) { + ctx.hash.keys_hash = ngx_pcalloc(pool, + sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); + if (ctx.hash.keys_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - ctx.dns_hash = ngx_pcalloc(pool, sizeof(ngx_array_t) * NGX_HTTP_MAP_HASH); - if (ctx.dns_hash == NULL) { + ctx.hash.dns_hash = ngx_pcalloc(pool, + sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); + if (ctx.hash.dns_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } ctx.values_hash = ngx_pcalloc(pool, - sizeof(ngx_array_t) * NGX_HTTP_MAP_HASH); + sizeof(ngx_array_t) * NGX_HTTP_CONFIG_HASH); if (ctx.values_hash == NULL) { ngx_destroy_pool(pool); return NGX_CONF_ERROR; } - ctx.pool = cf->pool; + ctx.hash.pool = cf->pool; + ctx.hash.temp_pool = pool; ctx.default_value = NULL; ctx.hostnames = 0; @@ -312,11 +308,13 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c hash.name = "map_hash"; hash.pool = cf->pool; - if (ctx.keys.nelts) { + if (ctx.hash.keys.nelts) { hash.hash = &map->hash; hash.temp_pool = NULL; - if (ngx_hash_init(&hash, ctx.keys.elts, ctx.keys.nelts) != NGX_OK) { + if (ngx_hash_init(&hash, ctx.hash.keys.elts, ctx.hash.keys.nelts) + != NGX_OK) + { return NGX_CONF_ERROR; } } @@ -324,16 +322,17 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c map->default_value = ctx.default_value ? ctx.default_value: &ngx_http_variable_null_value; - if (ctx.dns_wildcards.nelts) { + if (ctx.hash.dns_wildcards.nelts) { - ngx_qsort(ctx.dns_wildcards.elts, (size_t) ctx.dns_wildcards.nelts, + ngx_qsort(ctx.hash.dns_wildcards.elts, + (size_t) ctx.hash.dns_wildcards.nelts, sizeof(ngx_hash_key_t), ngx_http_map_cmp_dns_wildcards); hash.hash = NULL; hash.temp_pool = pool; - if (ngx_hash_wildcard_init(&hash, ctx.dns_wildcards.elts, - ctx.dns_wildcards.nelts) + if (ngx_hash_wildcard_init(&hash, ctx.hash.dns_wildcards.elts, + ctx.hash.dns_wildcards.nelts) != NGX_OK) { return NGX_CONF_ERROR; @@ -363,13 +362,12 @@ ngx_http_map_cmp_dns_wildcards(const voi static char * ngx_http_map(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { - size_t len; - ngx_str_t *value, file, *name; - ngx_uint_t i, n, key; - ngx_hash_key_t *m; + u_char ch; + ngx_int_t rc; + ngx_str_t *value, file; + ngx_uint_t i, key, flags; ngx_http_map_conf_ctx_t *ctx; - ngx_http_variable_value_t *var, *old, **vp; - u_char buf[2048]; + ngx_http_variable_value_t *var, **vp; ctx = cf->ctx; @@ -410,7 +408,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command key = ngx_hash(key, value[1].data[i]); } - key %= NGX_HTTP_MAP_HASH; + key %= NGX_HTTP_CONFIG_HASH; vp = ctx->values_hash[key].elts; @@ -435,13 +433,13 @@ ngx_http_map(ngx_conf_t *cf, ngx_command } } - var = ngx_palloc(ctx->pool, sizeof(ngx_http_variable_value_t)); + var = ngx_palloc(ctx->hash.pool, sizeof(ngx_http_variable_value_t)); if (var == NULL) { return NGX_CONF_ERROR; } var->len = value[1].len; - var->data = ngx_pstrdup(ctx->pool, &value[1]); + var->data = ngx_pstrdup(ctx->hash.pool, &value[1]); if (var->data == NULL) { return NGX_CONF_ERROR; } @@ -459,179 +457,54 @@ ngx_http_map(ngx_conf_t *cf, ngx_command found: - if (value[0].data[0] != '*' || ctx->hostnames == 0) { - - if (ngx_strcmp(value[0].data, "default") != 0) { - - if (value[0].len && value[0].data[0] == '!') { - value[0].len--; - value[0].data++; - } - - key = 0; + ch = value[0].data[0]; - for (i = 0; i < value[0].len; i++) { - value[0].data[i] = ngx_tolower(value[0].data[i]); - key = ngx_hash(key, value[0].data[i]); - } - - key %= NGX_HTTP_MAP_HASH; - - name = ctx->keys_hash[key].elts; - - if (name) { - for (i = 0; i < ctx->keys_hash[key].nelts; i++) { - if (value[0].len != name[i].len) { - continue; - } + if ((ch != '*' && ch != '.') || ctx->hostnames == 0) { - if (ngx_strncmp(value[0].data, name[i].data, value[0].len) - == 0) - { - m = ctx->keys.elts; - for (i = 0; i < ctx->keys.nelts; i++) { - if (ngx_strcmp(value[0].data, m[i].key.data) == 0) { - old = m[i].value; - m[i].value = var; + if (ngx_strcmp(value[0].data, "default") == 0) { - goto duplicate; - } - } - } - } - - } else { - if (ngx_array_init(&ctx->keys_hash[key], cf->pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - } - - name = ngx_array_push(&ctx->keys_hash[key]); - if (name == NULL) { + if (ctx->default_value) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "duplicate default map parameter"); return NGX_CONF_ERROR; } - *name = value[0]; + ctx->default_value = var; - m = ngx_array_push(&ctx->keys); - if (m == NULL) { - return NGX_CONF_ERROR; - } - - m->key = value[0]; - m->key_hash = ngx_hash_key(value[0].data, value[0].len); - m->value = var; + return NGX_CONF_OK; + } - } else { - if (ctx->default_value) { - old = ctx->default_value; - ctx->default_value = var; + if (value[0].len && ch == '!') { + value[0].len--; + value[0].data++; + } - goto duplicate; - } - - ctx->default_value = var; - } + flags = 0; } else { - if (value[0].len < 3 || value[0].data[1] != '.') { + if ((ch == '*' && (value[0].len < 3 || value[0].data[1] != '.')) + || (ch == '.' && value[0].len < 2)) + { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid DNS wildcard \"%V\"", &value[0]); + return NGX_CONF_ERROR; } - key = 0; - - for (i = 2; i < value[0].len; i++) { - value[0].data[i] = ngx_tolower(value[0].data[i]); - key = ngx_hash(key, value[0].data[i]); - } - - key %= NGX_HTTP_MAP_HASH; - - /* convert "*.example.com" into "com.example.\0" */ - - len = 0; - n = 0; - - for (i = value[0].len - 1; i; i--) { - if (value[0].data[i] == '.') { - ngx_memcpy(&buf[n], &value[0].data[i + 1], len); - n += len; - buf[n++] = '.'; - len = 0; - continue; - } - - len++; - } - - buf[n] = '\0'; - - name = ctx->dns_hash[key].elts; - - if (name) { - for (i = 0; i < ctx->dns_hash[key].nelts; i++) { - if (value[0].len != name[i].len) { - continue; - } - - if (ngx_strncmp(value[0].data, name[i].data, value[0].len) - == 0) - { - m = ctx->dns_wildcards.elts; - for (i = 0; i < ctx->dns_wildcards.nelts; i++) { - if (ngx_strcmp(buf, m[i].key.data) == 0) { - old = m[i].value; - m[i].value = var; - - goto duplicate; - } - } - } - } - - } else { - if (ngx_array_init(&ctx->dns_hash[key], cf->pool, 4, - sizeof(ngx_str_t)) - != NGX_OK) - { - return NGX_CONF_ERROR; - } - } - - name = ngx_array_push(&ctx->dns_hash[key]); - if (name == NULL) { - return NGX_CONF_ERROR; - } - - *name = value[0]; - - ngx_memcpy(value[0].data, buf, value[0].len); - value[0].len--; - - m = ngx_array_push(&ctx->dns_wildcards); - if (m == NULL) { - return NGX_CONF_ERROR; - } - - m->key = value[0]; - m->key_hash = 0; - m->value = var; + flags = NGX_HTTP_WILDCARD_HASH; } - return NGX_CONF_OK; + rc = ngx_http_config_add_hash(&ctx->hash, &value[0], var, flags); -duplicate: + if (rc == NGX_OK) { + return NGX_CONF_OK; + } - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "duplicate parameter \"%V\", value: \"%V\", " - "old value: \"%V\"", - &value[0], var, old); + if (rc == NGX_BUSY) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "conflicting parameter \"%V\"", &value[0]); + } - return NGX_CONF_OK; + 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 @@ -1926,6 +1926,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ size_t add; ngx_str_t *value, *url; + ngx_uint_t port; ngx_inet_upstream_t inet_upstream; ngx_http_core_loc_conf_t *clcf; #if (NGX_HTTP_SSL) @@ -1945,12 +1946,14 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ if (ngx_strncasecmp(url->data, "http://", 7) == 0) { add = 7; + port = 80; } else if (ngx_strncasecmp(url->data, "https://", 8) == 0) { #if (NGX_HTTP_SSL) add = 8; + port = 443; plcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); if (plcf->upstream.ssl == NULL) { @@ -2019,7 +2022,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ inet_upstream.name = *url; inet_upstream.url.len = url->len - add; inet_upstream.url.data = url->data + add; - inet_upstream.default_port_value = 80; + inet_upstream.default_port_value = port; inet_upstream.uri_part = 1; plcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); @@ -2032,8 +2035,8 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_ plcf->upstream.uri = inet_upstream.uri; } - plcf->upstream.schema.len = sizeof("http://") - 1; - plcf->upstream.schema.data = (u_char *) "http://"; + plcf->upstream.schema.len = add; + plcf->upstream.schema.data = url->data; clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); diff --git a/src/http/ngx_http_config.c b/src/http/ngx_http_config.c new file mode 100644 --- /dev/null +++ b/src/http/ngx_http_config.c @@ -0,0 +1,214 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +ngx_int_t +ngx_http_config_add_hash(ngx_http_hash_conf_t *h, ngx_str_t *key, void *value, + ngx_uint_t flags) +{ + size_t len; + ngx_str_t *name; + ngx_uint_t i, k, n, skip; + ngx_hash_key_t *hk; + u_char buf[2048]; + + if (!(flags & NGX_HTTP_WILDCARD_HASH)) { + + /* exact hash */ + + k = 0; + + for (i = 0; i < key->len; i++) { + key->data[i] = ngx_tolower(key->data[i]); + k = ngx_hash(k, key->data[i]); + } + + k %= NGX_HTTP_CONFIG_HASH; + + /* check conflicts in exact hash */ + + name = h->keys_hash[k].elts; + + if (name) { + for (i = 0; i < h->keys_hash[k].nelts; i++) { + if (key->len != name[i].len) { + continue; + } + + if (ngx_strncmp(key->data, name[i].data, key->len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&h->keys_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + *name = *key; + + hk = ngx_array_push(&h->keys); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *key; + hk->key_hash = ngx_hash_key(key->data, key->len); + hk->value = value; + + } else { + + /* wildcard hash */ + + skip = (key->data[0] == '*') ? 2 : 1; + k = 0; + + for (i = skip; i < key->len; i++) { + key->data[i] = ngx_tolower(key->data[i]); + k = ngx_hash(k, key->data[i]); + } + + k %= NGX_HTTP_CONFIG_HASH; + + if (skip == 1) { + + /* check conflicts in exact hash for ".example.com" */ + + name = h->keys_hash[k].elts; + + if (name) { + len = key->len - skip; + + for (i = 0; i < h->keys_hash[k].nelts; i++) { + if (len != name[i].len) { + continue; + } + + if (ngx_strncmp(&key->data[1], name[i].data, len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&h->keys_hash[k], h->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&h->keys_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + name->len = key->len - 1; + name->data = ngx_palloc(h->temp_pool, name->len); + if (name->data == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(name->data, &key->data[1], name->len); + } + + + /* + * convert "*.example.com" to "com.example.\0" + * and ".example.com" to "com.example\0" + */ + + len = 0; + n = 0; + + for (i = key->len - 1; i; i--) { + if (key->data[i] == '.') { + ngx_memcpy(&buf[n], &key->data[i + 1], len); + n += len; + buf[n++] = '.'; + len = 0; + continue; + } + + len++; + } + + if (len) { + ngx_memcpy(&buf[n], &key->data[1], len); + n += len; + } + + buf[n] = '\0'; + + + /* check conflicts in wildcard hash */ + + name = h->dns_hash[k].elts; + + if (name) { + len = key->len - skip; + + for (i = 0; i < h->dns_hash[k].nelts; i++) { + if (len != name[i].len) { + continue; + } + + if (ngx_strncmp(key->data + skip, name[i].data, len) == 0) { + return NGX_BUSY; + } + } + + } else { + if (ngx_array_init(&h->dns_hash[k], h->temp_pool, 4, + sizeof(ngx_str_t)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + name = ngx_array_push(&h->dns_hash[k]); + if (name == NULL) { + return NGX_ERROR; + } + + name->len = key->len - skip; + name->data = ngx_palloc(h->temp_pool, name->len); + if (name->data == NULL) { + return NGX_ERROR; + } + ngx_memcpy(name->data, key->data + skip, name->len); + + + ngx_memcpy(key->data, buf, key->len); + key->len--; + + hk = ngx_array_push(&h->dns_wildcards); + if (hk == NULL) { + return NGX_ERROR; + } + + hk->key = *key; + hk->key_hash = 0; + hk->value = value; + } + + return NGX_OK; +} diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -14,9 +14,9 @@ typedef struct { - void **main_conf; - void **srv_conf; - void **loc_conf; + void **main_conf; + void **srv_conf; + void **loc_conf; } ngx_http_conf_ctx_t; @@ -72,5 +72,25 @@ typedef struct { cycle->conf_ctx[ngx_http_module.index])->main_conf[module.ctx_index] +#define NGX_HTTP_CONFIG_HASH 10007 + +#define NGX_HTTP_WILDCARD_HASH 1 + +typedef struct { + ngx_pool_t *pool; + ngx_pool_t *temp_pool; + + ngx_array_t keys; + ngx_array_t *keys_hash; + + ngx_array_t dns_wildcards; + ngx_array_t *dns_hash; +} ngx_http_hash_conf_t; + + +ngx_int_t ngx_http_config_add_hash(ngx_http_hash_conf_t *h, ngx_str_t *key, + void *value, ngx_uint_t flags); + + #endif /* _NGX_HTTP_CONFIG_H_INCLUDED_ */ 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 @@ -90,6 +90,8 @@ static void *ngx_http_upstream_create_ma static char *ngx_http_core_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 *, + 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); @@ -498,9 +500,8 @@ ngx_http_upstream_check_broken_connectio static void ngx_http_upstream_connect(ngx_http_request_t *r, ngx_http_upstream_t *u) { - ngx_int_t rc; - ngx_peer_t *peer; - ngx_connection_t *c; + ngx_int_t rc; + ngx_connection_t *c; r->connection->log->action = "connecting to upstream"; @@ -517,8 +518,7 @@ ngx_http_upstream_connect(ngx_http_reque return; } - peer = &u->peer.peers->peer[u->peer.cur_peer]; - u->state->peer = &peer->name; + u->state->peer = &u->peer.peers->peer[u->peer.cur_peer].name; if (rc == NGX_BUSY) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no live upstreams"); @@ -534,6 +534,7 @@ ngx_http_upstream_connect(ngx_http_reque c = u->peer.connection; c->data = r; + c->write->handler = ngx_http_upstream_send_request_handler; c->read->handler = ngx_http_upstream_process_header; @@ -587,40 +588,10 @@ ngx_http_upstream_connect(ngx_http_reque return; } - /* rc == NGX_OK */ - #if (NGX_HTTP_SSL) - if (u->conf->ssl) { - if (c->ssl == NULL) { - - if (ngx_ssl_create_connection(u->conf->ssl, c, - NGX_SSL_BUFFER|NGX_SSL_CLIENT) - == NGX_ERROR) - { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - c->sendfile = 0; - } - - if (ngx_ssl_set_session(c, peer->ssl_session) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, - NGX_HTTP_INTERNAL_SERVER_ERROR); - return; - } - - rc = ngx_ssl_handshake(c); - - if (rc == NGX_AGAIN) { - c->ssl->handler = ngx_http_upstream_ssl_handshake; - return; - } - - ngx_http_upstream_ssl_handshake(c); - + if (u->conf->ssl && c->ssl == NULL) { + ngx_http_upstream_ssl_init_connection(r, u, c); return; } @@ -633,6 +604,43 @@ ngx_http_upstream_connect(ngx_http_reque #if (NGX_HTTP_SSL) 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; + + if (ngx_ssl_create_connection(u->conf->ssl, c, + NGX_SSL_BUFFER|NGX_SSL_CLIENT) + == NGX_ERROR) + { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + c->sendfile = 0; + + peer = &u->peer.peers->peer[u->peer.cur_peer]; + + if (ngx_ssl_set_session(c, peer->ssl_session) != NGX_OK) { + ngx_http_upstream_finalize_request(r, u, + NGX_HTTP_INTERNAL_SERVER_ERROR); + return; + } + + rc = ngx_ssl_handshake(c); + + if (rc == NGX_AGAIN) { + c->ssl->handler = ngx_http_upstream_ssl_handshake; + return; + } + + ngx_http_upstream_ssl_handshake(c); +} + + +static void ngx_http_upstream_ssl_handshake(ngx_connection_t *c) { ngx_http_request_t *r; @@ -671,7 +679,8 @@ ngx_http_upstream_reinit(ngx_http_reques sizeof(ngx_http_upstream_headers_in_t)); if (ngx_list_init(&r->upstream->headers_in.headers, r->pool, 8, - sizeof(ngx_table_elt_t)) != NGX_OK) + sizeof(ngx_table_elt_t)) + != NGX_OK) { return NGX_ERROR; } @@ -851,6 +860,15 @@ ngx_http_upstream_send_request_handler(n return; } +#if (NGX_HTTP_SSL) + + if (u->conf->ssl && c->ssl == NULL) { + ngx_http_upstream_ssl_init_connection(r, u, c); + return; + } + +#endif + ngx_http_upstream_send_request(r, u); }