# HG changeset patch # User Igor Sysoev # Date 1306267200 -14400 # Node ID a7a5fa2e395b4029a7d9f0eeb6e9924adc3c645b # Parent 30f948276abe6a29107868cfc5f1c3afe78eb662 nginx 1.0.3 *) Feature: the "auth_basic_user_file" directive supports "$apr1", "{PLAIN}", and "{SSHA}" password encryption methods. Thanks to Maxim Dounin. *) Feature: the "geoip_org" directive and $geoip_org variable. Thanks to Alexander Uskov, Arnaud Granal, and Denis F. Latypoff. *) Feature: ngx_http_geo_module and ngx_http_geoip_module support IPv4 addresses mapped to IPv6 addresses. *) Bugfix: a segmentation fault occurred in a worker process during testing IPv4 address mapped to IPv6 address, if access or deny rules were defined only for IPv6; the bug had appeared in 0.8.22. *) Bugfix: a cached reponse may be broken if proxy/fastcgi/scgi/ uwsgi_cache_bypass and proxy/fastcgi/scgi/uwsgi_no_cache directive values were different; the bug had appeared in 0.8.46. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,25 @@ +Changes with nginx 1.0.3 25 May 2011 + + *) Feature: the "auth_basic_user_file" directive supports "$apr1", + "{PLAIN}", and "{SSHA}" password encryption methods. + Thanks to Maxim Dounin. + + *) Feature: the "geoip_org" directive and $geoip_org variable. + Thanks to Alexander Uskov, Arnaud Granal, and Denis F. Latypoff. + + *) Feature: ngx_http_geo_module and ngx_http_geoip_module support IPv4 + addresses mapped to IPv6 addresses. + + *) Bugfix: a segmentation fault occurred in a worker process during + testing IPv4 address mapped to IPv6 address, if access or deny rules + were defined only for IPv6; the bug had appeared in 0.8.22. + + *) Bugfix: a cached reponse may be broken if proxy/fastcgi/scgi/ + uwsgi_cache_bypass and proxy/fastcgi/scgi/uwsgi_no_cache directive + values were different; the bug had appeared in 0.8.46. + + Changes with nginx 1.0.2 10 May 2011 *) Feature: now shared zones and caches use POSIX semaphores. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,26 @@ +Изменения в nginx 1.0.3 25.05.2011 + + *) Добавление: директива auth_basic_user_file поддерживает шифрование + пароля методами "$apr1", "{PLAIN}" и "{SSHA}". + Спасибо Максиму Дунину. + + *) Добавление: директива geoip_org и переменная $geoip_org. + Спасибо Александру Ускову, Arnaud Granal и Денису Латыпову. + + *) Добавление: модули ngx_http_geo_module и ngx_http_geoip_module + поддерживают адреса IPv4, отображённые на IPv6 адреса. + + *) Исправление: при проверке адреса IPv4, отображённого на адрес IPv6, + в рабочем процессе происходил segmentation fault, если директивы + access или deny были определены только для адресов IPv6; ошибка + появилась в 0.8.22. + + *) Исправление: закэшированный ответ мог быть испорчен, если значения + директив proxy/fastcgi/scgi/uwsgi_cache_bypass и proxy/fastcgi/scgi/ + uwsgi_no_cache были разными; ошибка появилась в 0.8.46. + + Изменения в nginx 1.0.2 10.05.2011 *) Добавление: теперь разделяемые зоны и кэши используют семафоры POSIX. diff --git a/auto/feature b/auto/feature --- a/auto/feature +++ b/auto/feature @@ -52,7 +52,7 @@ if [ -x $NGX_AUTOTEST ]; then yes) # /bin/sh is used to intercept "Killed" or "Abort trap" messages - if /bin/sh -c $NGX_AUTOTEST >/dev/null 2>&1; then + if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " found" ngx_found=yes @@ -67,7 +67,7 @@ if [ -x $NGX_AUTOTEST ]; then value) # /bin/sh is used to intercept "Killed" or "Abort trap" messages - if /bin/sh -c $NGX_AUTOTEST >/dev/null 2>&1; then + if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " found" ngx_found=yes @@ -85,7 +85,7 @@ END bug) # /bin/sh is used to intercept "Killed" or "Abort trap" messages - if /bin/sh -c $NGX_AUTOTEST >/dev/null 2>&1; then + if /bin/sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then echo " not found" else diff --git a/auto/lib/conf b/auto/lib/conf --- a/auto/lib/conf +++ b/auto/lib/conf @@ -43,6 +43,7 @@ if [ $USE_SHA1 = YES ]; then if [ $USE_OPENSSL = YES ]; then have=NGX_HAVE_OPENSSL_SHA1_H . auto/have + have=NGX_HAVE_SHA1 . auto/have SHA1=YES SHA1_LIB=OpenSSL diff --git a/auto/lib/sha1/conf b/auto/lib/sha1/conf --- a/auto/lib/sha1/conf +++ b/auto/lib/sha1/conf @@ -4,6 +4,7 @@ if [ $SHA1 != NONE ]; then + have=NGX_HAVE_SHA1 . auto/have CORE_INCS="$CORE_INCS $SHA1" case "$NGX_CC_NAME" in @@ -41,7 +42,7 @@ else # FreeBSD ngx_feature="sha1 in system md library" - ngx_feature_name= + ngx_feature_name=NGX_HAVE_SHA1 ngx_feature_run=no ngx_feature_incs="#include " ngx_feature_path= diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -197,6 +197,8 @@ if [ $HTTP_RANDOM_INDEX = YES ]; then fi if [ $HTTP_AUTH_BASIC = YES ]; then + USE_MD5=YES + USE_SHA1=YES have=NGX_CRYPT . auto/have HTTP_MODULES="$HTTP_MODULES $HTTP_AUTH_BASIC_MODULE" HTTP_SRCS="$HTTP_SRCS $HTTP_AUTH_BASIC_SRCS" diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -34,7 +34,8 @@ CORE_DEPS="src/core/nginx.h \ src/core/ngx_cycle.h \ src/core/ngx_conf_file.h \ src/core/ngx_resolver.h \ - src/core/ngx_open_file_cache.h" + src/core/ngx_open_file_cache.h \ + src/core/ngx_crypt.h" CORE_SRCS="src/core/nginx.c \ @@ -64,7 +65,8 @@ CORE_SRCS="src/core/nginx.c \ src/core/ngx_cpuinfo.c \ src/core/ngx_conf_file.c \ src/core/ngx_resolver.c \ - src/core/ngx_open_file_cache.c" + src/core/ngx_open_file_cache.c \ + src/core/ngx_crypt.c" REGEX_DEPS=src/core/ngx_regex.h diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 1000002 -#define NGINX_VERSION "1.0.2" +#define nginx_version 1000003 +#define NGINX_VERSION "1.0.3" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_crypt.c b/src/core/ngx_crypt.c new file mode 100644 --- /dev/null +++ b/src/core/ngx_crypt.c @@ -0,0 +1,234 @@ + +/* + * Copyright (C) Maxim Dounin + */ + + +#include +#include +#include +#if (NGX_HAVE_SHA1) +#include +#endif + + +static ngx_int_t ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); +static ngx_int_t ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + +#if (NGX_HAVE_SHA1) + +static ngx_int_t ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + +#endif + + +static u_char *ngx_crypt_to64(u_char *p, uint32_t v, size_t n); + + +ngx_int_t +ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + if (ngx_strncmp(salt, "$apr1$", sizeof("$apr1$") - 1) == 0) { + return ngx_crypt_apr1(pool, key, salt, encrypted); + + } else if (ngx_strncmp(salt, "{PLAIN}", sizeof("{PLAIN}") - 1) == 0) { + return ngx_crypt_plain(pool, key, salt, encrypted); + +#if (NGX_HAVE_SHA1) + } else if (ngx_strncmp(salt, "{SSHA}", sizeof("{SSHA}") - 1) == 0) { + return ngx_crypt_ssha(pool, key, salt, encrypted); +#endif + } + + /* fallback to libc crypt() */ + + return ngx_libc_crypt(pool, key, salt, encrypted); +} + + +static ngx_int_t +ngx_crypt_apr1(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + ngx_int_t n; + ngx_uint_t i; + u_char *p, *last, final[16]; + size_t saltlen, keylen; + ngx_md5_t md5, ctx1; + + /* Apache's apr1 crypt is Paul-Henning Kamp's md5 crypt with $apr1$ magic */ + + keylen = ngx_strlen(key); + + /* true salt: no magic, max 8 chars, stop at first $ */ + + salt += sizeof("$apr1$") - 1; + last = salt + 8; + for (p = salt; *p && *p != '$' && p < last; p++) { /* void */ } + saltlen = p - salt; + + /* hash key and salt */ + + ngx_md5_init(&md5); + ngx_md5_update(&md5, key, keylen); + ngx_md5_update(&md5, "$apr1$", sizeof("$apr1$") - 1); + ngx_md5_update(&md5, salt, saltlen); + + ngx_md5_init(&ctx1); + ngx_md5_update(&ctx1, key, keylen); + ngx_md5_update(&ctx1, salt, saltlen); + ngx_md5_update(&ctx1, key, keylen); + ngx_md5_final(final, &ctx1); + + for (n = keylen; n > 0; n -= 16) { + ngx_md5_update(&md5, final, n > 16 ? 16 : n); + } + + ngx_memzero(final, sizeof(final)); + + for (i = keylen; i; i >>= 1) { + if (i & 1) { + ngx_md5_update(&md5, final, 1); + + } else { + ngx_md5_update(&md5, key, 1); + } + } + + ngx_md5_final(final, &md5); + + for (i = 0; i < 1000; i++) { + ngx_md5_init(&ctx1); + + if (i & 1) { + ngx_md5_update(&ctx1, key, keylen); + + } else { + ngx_md5_update(&ctx1, final, 16); + } + + if (i % 3) { + ngx_md5_update(&ctx1, salt, saltlen); + } + + if (i % 7) { + ngx_md5_update(&ctx1, key, keylen); + } + + if (i & 1) { + ngx_md5_update(&ctx1, final, 16); + + } else { + ngx_md5_update(&ctx1, key, keylen); + } + + ngx_md5_final(final, &ctx1); + } + + /* output */ + + *encrypted = ngx_pnalloc(pool, sizeof("$apr1$") - 1 + saltlen + 16 + 1); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(*encrypted, "$apr1$", sizeof("$apr1$") - 1); + p = ngx_copy(p, salt, saltlen); + *p++ = '$'; + + p = ngx_crypt_to64(p, (final[ 0]<<16) | (final[ 6]<<8) | final[12], 4); + p = ngx_crypt_to64(p, (final[ 1]<<16) | (final[ 7]<<8) | final[13], 4); + p = ngx_crypt_to64(p, (final[ 2]<<16) | (final[ 8]<<8) | final[14], 4); + p = ngx_crypt_to64(p, (final[ 3]<<16) | (final[ 9]<<8) | final[15], 4); + p = ngx_crypt_to64(p, (final[ 4]<<16) | (final[10]<<8) | final[ 5], 4); + p = ngx_crypt_to64(p, final[11], 2); + *p = '\0'; + + return NGX_OK; +} + + +static u_char * +ngx_crypt_to64(u_char *p, uint32_t v, size_t n) +{ + static u_char itoa64[] = + "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + while (n--) { + *p++ = itoa64[v & 0x3f]; + v >>= 6; + } + + return p; +} + + +static ngx_int_t +ngx_crypt_plain(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + size_t len; + u_char *p; + + len = ngx_strlen(key); + + *encrypted = ngx_pnalloc(pool, sizeof("{PLAIN}") - 1 + len + 1); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(*encrypted, "{PLAIN}", sizeof("{PLAIN}") - 1); + ngx_memcpy(p, key, len + 1); + + return NGX_OK; +} + + +#if (NGX_HAVE_SHA1) + +static ngx_int_t +ngx_crypt_ssha(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +{ + size_t len; + ngx_str_t encoded, decoded; + ngx_sha1_t sha1; + + /* "{SSHA}" base64(SHA1(key salt) salt) */ + + /* decode base64 salt to find out true salt */ + + encoded.data = salt + sizeof("{SSHA}") - 1; + encoded.len = ngx_strlen(encoded.data); + + decoded.data = ngx_pnalloc(pool, ngx_base64_decoded_length(encoded.len)); + if (decoded.data == NULL) { + return NGX_ERROR; + } + + ngx_decode_base64(&decoded, &encoded); + + /* update SHA1 from key and salt */ + + ngx_sha1_init(&sha1); + ngx_sha1_update(&sha1, key, ngx_strlen(key)); + ngx_sha1_update(&sha1, decoded.data + 20, decoded.len - 20); + ngx_sha1_final(decoded.data, &sha1); + + /* encode it back to base64 */ + + len = sizeof("{SSHA}") - 1 + ngx_base64_encoded_length(decoded.len) + 1; + + *encrypted = ngx_pnalloc(pool, len); + if (*encrypted == NULL) { + return NGX_ERROR; + } + + encoded.data = ngx_cpymem(*encrypted, "{SSHA}", sizeof("{SSHA}") - 1); + ngx_encode_base64(&encoded, &decoded); + encoded.data[encoded.len] = '\0'; + + return NGX_OK; +} + +#endif /* NGX_HAVE_SHA1 */ diff --git a/src/core/ngx_crypt.h b/src/core/ngx_crypt.h new file mode 100644 --- /dev/null +++ b/src/core/ngx_crypt.h @@ -0,0 +1,19 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_CRYPT_H_INCLUDED_ +#define _NGX_CRYPT_H_INCLUDED_ + + +#include +#include + + +ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, + u_char **encrypted); + + +#endif /* _NGX_CRYPT_H_INCLUDED_ */ diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -108,20 +108,30 @@ ngx_http_access_handler(ngx_http_request { struct sockaddr_in *sin; ngx_http_access_loc_conf_t *alcf; +#if (NGX_HAVE_INET6) + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; +#endif alcf = ngx_http_get_module_loc_conf(r, ngx_http_access_module); + switch (r->connection->sockaddr->sa_family) { + + case AF_INET: + if (alcf->rules) { + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr); + } + break; + #if (NGX_HAVE_INET6) - if (alcf->rules6 && r->connection->sockaddr->sa_family == AF_INET6) { - u_char *p; - in_addr_t addr; - struct sockaddr_in6 *sin6; - + case AF_INET6: sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; p = sin6->sin6_addr.s6_addr; - if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + if (alcf->rules && IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { addr = p[12] << 24; addr += p[13] << 16; addr += p[14] << 8; @@ -129,14 +139,11 @@ ngx_http_access_handler(ngx_http_request return ngx_http_access_inet(r, alcf, htonl(addr)); } - return ngx_http_access_inet6(r, alcf, p); - } + if (alcf->rules6) { + return ngx_http_access_inet6(r, alcf, p); + } #endif - - if (alcf->rules && r->connection->sockaddr->sa_family == AF_INET) { - sin = (struct sockaddr_in *) r->connection->sockaddr; - return ngx_http_access_inet(r, alcf, sin->sin_addr.s_addr); } return NGX_DECLINED; diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -7,6 +7,7 @@ #include #include #include +#include #define NGX_HTTP_AUTH_BUF_SIZE 2048 diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -257,17 +257,41 @@ ngx_http_geo_real_addr(ngx_http_request_ { struct sockaddr_in *sin; ngx_http_variable_value_t *v; +#if (NGX_HAVE_INET6) + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; +#endif if (ctx->index == -1) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http geo started: %V", &r->connection->addr_text); - if (r->connection->sockaddr->sa_family != AF_INET) { - return 0; + switch (r->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ntohl(sin->sin_addr.s_addr); + +#if (NGX_HAVE_INET6) + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + p = sin6->sin6_addr.s6_addr; + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + + return addr; + } + +#endif } - sin = (struct sockaddr_in *) r->connection->sockaddr; - return ntohl(sin->sin_addr.s_addr); + return INADDR_NONE; } v = ngx_http_get_flushed_variable(r, ctx->index); diff --git a/src/http/modules/ngx_http_geoip_module.c b/src/http/modules/ngx_http_geoip_module.c --- a/src/http/modules/ngx_http_geoip_module.c +++ b/src/http/modules/ngx_http_geoip_module.c @@ -14,6 +14,7 @@ typedef struct { GeoIP *country; + GeoIP *org; GeoIP *city; } ngx_http_geoip_conf_t; @@ -28,6 +29,8 @@ typedef const char *(*ngx_http_geoip_var static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_geoip_org_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_geoip_region_name_variable(ngx_http_request_t *r, @@ -42,6 +45,8 @@ static ngx_int_t ngx_http_geoip_add_vari static void *ngx_http_geoip_create_conf(ngx_conf_t *cf); static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static void ngx_http_geoip_cleanup(void *data); @@ -56,6 +61,13 @@ static ngx_command_t ngx_http_geoip_com 0, NULL }, + { ngx_string("geoip_org"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, + ngx_http_geoip_org, + NGX_HTTP_MAIN_CONF_OFFSET, + 0, + NULL }, + { ngx_string("geoip_city"), NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, ngx_http_geoip_city, @@ -112,6 +124,10 @@ static ngx_http_variable_t ngx_http_geo ngx_http_geoip_country_variable, (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 }, + { ngx_string("geoip_org"), NULL, + ngx_http_geoip_org_variable, + (uintptr_t) GeoIP_name_by_ipnum, 0, 0 }, + { ngx_string("geoip_city_continent_code"), NULL, ngx_http_geoip_city_variable, offsetof(GeoIPRecord, continent_code), 0, 0 }, @@ -164,6 +180,44 @@ static ngx_http_variable_t ngx_http_geo }; +static u_long +ngx_http_geoip_addr(ngx_http_request_t *r) +{ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + u_char *p; + u_long addr; + struct sockaddr_in6 *sin6; +#endif + + switch (r->connection->sockaddr->sa_family) { + + case AF_INET: + sin = (struct sockaddr_in *) r->connection->sockaddr; + return ntohl(sin->sin_addr.s_addr); + +#if (NGX_HAVE_INET6) + + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + p = sin6->sin6_addr.s6_addr; + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + + return addr; + } + +#endif + } + + return INADDR_NONE; +} + + static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) @@ -171,9 +225,7 @@ ngx_http_geoip_country_variable(ngx_http ngx_http_geoip_variable_handler_pt handler = (ngx_http_geoip_variable_handler_pt) data; - u_long addr; const char *val; - struct sockaddr_in *sin; ngx_http_geoip_conf_t *gcf; gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); @@ -182,14 +234,45 @@ ngx_http_geoip_country_variable(ngx_http goto not_found; } - if (r->connection->sockaddr->sa_family != AF_INET) { + val = handler(gcf->country, ngx_http_geoip_addr(r)); + + if (val == NULL) { goto not_found; } - sin = (struct sockaddr_in *) r->connection->sockaddr; - addr = ntohl(sin->sin_addr.s_addr); + v->len = ngx_strlen(val); + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = (u_char *) val; + + return NGX_OK; + +not_found: + + v->not_found = 1; + + return NGX_OK; +} + - val = handler(gcf->country, addr); +static ngx_int_t +ngx_http_geoip_org_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_http_geoip_variable_handler_pt handler = + (ngx_http_geoip_variable_handler_pt) data; + + const char *val; + ngx_http_geoip_conf_t *gcf; + + gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); + + if (gcf->org == NULL) { + goto not_found; + } + + val = handler(gcf->org, ngx_http_geoip_addr(r)); if (val == NULL) { goto not_found; @@ -364,18 +447,12 @@ ngx_http_geoip_city_int_variable(ngx_htt static GeoIPRecord * ngx_http_geoip_get_city_record(ngx_http_request_t *r) { - u_long addr; - struct sockaddr_in *sin; ngx_http_geoip_conf_t *gcf; gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module); - if (gcf->city && r->connection->sockaddr->sa_family == AF_INET) { - - sin = (struct sockaddr_in *) r->connection->sockaddr; - addr = ntohl(sin->sin_addr.s_addr); - - return GeoIP_record_by_ipnum(gcf->city, addr); + if (gcf->city) { + return GeoIP_record_by_ipnum(gcf->city, ngx_http_geoip_addr(r)); } return NULL; @@ -441,7 +518,7 @@ ngx_http_geoip_country(ngx_conf_t *cf, n if (gcf->country == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "GeoIO_open(\"%V\") failed", &value[1]); + "GeoIP_open(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } @@ -475,6 +552,57 @@ ngx_http_geoip_country(ngx_conf_t *cf, n static char * +ngx_http_geoip_org(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_geoip_conf_t *gcf = conf; + + ngx_str_t *value; + + if (gcf->org) { + return "is duplicate"; + } + + value = cf->args->elts; + + gcf->org = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE); + + if (gcf->org == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "GeoIP_open(\"%V\") failed", &value[1]); + + return NGX_CONF_ERROR; + } + + if (cf->args->nelts == 3) { + if (ngx_strcmp(value[2].data, "utf8") == 0) { + GeoIP_set_charset (gcf->org, GEOIP_CHARSET_UTF8); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + } + + switch (gcf->org->databaseType) { + + case GEOIP_ISP_EDITION: + case GEOIP_ORG_EDITION: + case GEOIP_DOMAIN_EDITION: + case GEOIP_ASNUM_EDITION: + + return NGX_CONF_OK; + + default: + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid GeoIP database \"%V\" type:%d", + &value[1], gcf->org->databaseType); + return NGX_CONF_ERROR; + } +} + + +static char * ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_geoip_conf_t *gcf = conf; @@ -491,7 +619,7 @@ ngx_http_geoip_city(ngx_conf_t *cf, ngx_ if (gcf->city == NULL) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "GeoIO_open(\"%V\") failed", &value[1]); + "GeoIP_open(\"%V\") failed", &value[1]); return NGX_CONF_ERROR; } @@ -532,6 +660,10 @@ ngx_http_geoip_cleanup(void *data) GeoIP_delete(gcf->country); } + if (gcf->org) { + GeoIP_delete(gcf->org); + } + if (gcf->city) { GeoIP_delete(gcf->city); } diff --git a/src/http/modules/ngx_http_split_clients_module.c b/src/http/modules/ngx_http_split_clients_module.c --- a/src/http/modules/ngx_http_split_clients_module.c +++ b/src/http/modules/ngx_http_split_clients_module.c @@ -94,7 +94,7 @@ ngx_http_split_clients_variable(ngx_http for (i = 0; i < ctx->parts.nelts; i++) { ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "%D %D", hash, part[i].percent); + "http split: %uD %uD", hash, part[i].percent); if (hash < part[i].percent) { *v = part[i].value; 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 @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '1.0.2'; +our $VERSION = '1.0.3'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c --- a/src/http/ngx_http_file_cache.c +++ b/src/http/ngx_http_file_cache.c @@ -174,8 +174,6 @@ ngx_http_file_cache_create(ngx_http_requ ngx_pool_cleanup_t *cln; ngx_http_file_cache_t *cache; - ngx_http_file_cache_create_key(r); - c = r->cache; cache = c->file_cache; @@ -906,7 +904,7 @@ ngx_http_file_cache_free(ngx_http_cache_ ngx_http_file_cache_t *cache; ngx_http_file_cache_node_t *fcn; - if (c->updated) { + if (c->updated || c->node == NULL) { return; } 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 @@ -641,19 +641,6 @@ ngx_http_upstream_cache(ngx_http_request if (c == NULL) { - switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) { - - case NGX_ERROR: - return NGX_ERROR; - - case NGX_DECLINED: - u->cache_status = NGX_HTTP_CACHE_BYPASS; - return NGX_DECLINED; - - default: /* NGX_OK */ - break; - } - if (!(r->method & u->conf->cache_methods)) { return NGX_DECLINED; } @@ -674,6 +661,19 @@ ngx_http_upstream_cache(ngx_http_request ngx_http_file_cache_create_key(r); + switch (ngx_http_test_predicates(r, u->conf->cache_bypass)) { + + case NGX_ERROR: + return NGX_ERROR; + + case NGX_DECLINED: + u->cache_status = NGX_HTTP_CACHE_BYPASS; + return NGX_DECLINED; + + default: /* NGX_OK */ + break; + } + u->cacheable = 1; c = r->cache; @@ -2135,18 +2135,6 @@ ngx_http_upstream_send_response(ngx_http if (u->cache_status == NGX_HTTP_CACHE_BYPASS) { - if (ngx_http_file_cache_new(r) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); - return; - } - - if (u->create_key(r) != NGX_OK) { - ngx_http_upstream_finalize_request(r, u, 0); - return; - } - - /* TODO: add keys */ - r->cache->min_uses = u->conf->cache_min_uses; r->cache->body_start = u->conf->buffer_size; r->cache->file_cache = u->conf->cache->data; diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c --- a/src/os/unix/ngx_user.c +++ b/src/os/unix/ngx_user.c @@ -23,7 +23,7 @@ #if (NGX_HAVE_GNU_CRYPT_R) ngx_int_t -ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) { char *value; size_t len; @@ -58,7 +58,7 @@ ngx_crypt(ngx_pool_t *pool, u_char *key, #else ngx_int_t -ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) +ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted) { char *value; size_t len; diff --git a/src/os/unix/ngx_user.h b/src/os/unix/ngx_user.h --- a/src/os/unix/ngx_user.h +++ b/src/os/unix/ngx_user.h @@ -16,7 +16,7 @@ typedef uid_t ngx_uid_t; typedef gid_t ngx_gid_t; -ngx_int_t ngx_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, +ngx_int_t ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted);