# HG changeset patch # User Igor Sysoev # Date 1237150800 -10800 # Node ID bb941a2996a6026f35c76f60ec2cd56c23f34ae5 # Parent 6ef558ffc0eb303b8e2a5fc7eb7c588adfeaa147 nginx 0.7.42 *) Change: now the "Invalid argument" error returned by setsockopt(TCP_NODELAY) on Solaris, is ignored. *) Change: now if a file specified in a "auth_basic_user_file" directive is absent, then the 405 error is returned instead of the 500 one. *) Feature: the "auth_basic_user_file" directive supports variables. Thanks to Kirill A. Korinskiy. *) Feature: the "listen" directive supports the "ipv6only" parameter. Thanks to Zhang Hua. *) Bugfix: in an "alias" directive with references to captures of regular expressions; the bug had appeared in 0.7.40. *) Bugfix: compatibility with Tru64 UNIX. Thanks to Dustin Marquess. *) Bugfix: nginx could not be built without PCRE library; the bug had appeared in 0.7.41. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,29 @@ +Changes with nginx 0.7.42 16 Mar 2009 + + *) Change: now the "Invalid argument" error returned by + setsockopt(TCP_NODELAY) on Solaris, is ignored. + + *) Change: now if a file specified in a "auth_basic_user_file" + directive is absent, then the 405 error is returned instead of the + 500 one. + + *) Feature: the "auth_basic_user_file" directive supports variables. + Thanks to Kirill A. Korinskiy. + + *) Feature: the "listen" directive supports the "ipv6only" parameter. + Thanks to Zhang Hua. + + *) Bugfix: in an "alias" directive with references to captures of + regular expressions; the bug had appeared in 0.7.40. + + *) Bugfix: compatibility with Tru64 UNIX. + Thanks to Dustin Marquess. + + *) Bugfix: nginx could not be built without PCRE library; the bug had + appeared in 0.7.41. + + Changes with nginx 0.7.41 11 Mar 2009 *) Bugfix: a segmentation fault might occur in worker process, if a diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,28 @@ +Изменения в nginx 0.7.42 16.03.2009 + + *) Изменение: ошибка "Invalid argument", возвращаемая + setsockopt(TCP_NODELAY) на Solaris, теперь игнорируется. + + *) Изменение: при отсутствии файла, указанного в директиве + auth_basic_user_file, теперь возвращается ошибка 403 вместо 500. + + *) Добавление: директива auth_basic_user_file поддерживает переменные. + Спасибо Кириллу Коринскому. + + *) Добавление: директива listen поддерживает параметр ipv6only. + Спасибо Zhang Hua. + + *) Исправление: в директиве alias со ссылками на выделения в регулярных + выражениях; ошибка появилась в 0.7.40. + + *) Исправление: совместимость с Tru64 UNIX. + Спасибо Dustin Marquess. + + *) Исправление: nginx не собирался без библиотеки PCRE; ошибка + появилась в 0.7.41. + + Изменения в nginx 0.7.41 11.03.2009 *) Исправление: в рабочем процессе мог произойти segmentation fault, 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.7.41" +#define NGINX_VERSION "0.7.42" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -282,6 +282,23 @@ ngx_open_listening_sockets(ngx_cycle_t * return NGX_ERROR; } +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + + if (ls[i].sockaddr->sa_family == AF_INET6 && ls[i].ipv6only) { + int ipv6only; + + ipv6only = (ls[i].ipv6only == 1); + + if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *) &ipv6only, sizeof(int)) + == -1) + { + ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno, + "setsockopt(IPV6_V6ONLY) %V failed, ignored", + &ls[i].addr_text); + } + } +#endif /* TODO: close on exit */ if (!(ngx_event_flags & NGX_USE_AIO_EVENT)) { @@ -782,12 +799,16 @@ ngx_connection_error(ngx_connection_t *c { ngx_uint_t level; - if (err == NGX_ECONNRESET - && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) - { + if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) { return 0; } +#if (NGX_SOLARIS) + if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) { + return 0; + } +#endif + if (err == 0 || err == NGX_ECONNRESET #if !(NGX_WIN32) @@ -803,6 +824,7 @@ ngx_connection_error(ngx_connection_t *c { switch (c->log_error) { + case NGX_ERROR_IGNORE_EINVAL: case NGX_ERROR_IGNORE_ECONNRESET: case NGX_ERROR_INFO: level = NGX_LOG_INFO; diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -56,6 +56,10 @@ struct ngx_listening_s { unsigned shared:1; /* shared between threads or processes */ unsigned addr_ntop:1; +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif + #if (NGX_HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; unsigned delete_deferred:1; @@ -69,10 +73,11 @@ struct ngx_listening_s { typedef enum { - NGX_ERROR_CRIT = 0, + NGX_ERROR_ALERT = 0, NGX_ERROR_ERR, NGX_ERROR_INFO, - NGX_ERROR_IGNORE_ECONNRESET + NGX_ERROR_IGNORE_ECONNRESET, + NGX_ERROR_IGNORE_EINVAL } ngx_connection_log_error_e; @@ -131,7 +136,7 @@ struct ngx_connection_s { unsigned buffered:8; - unsigned log_error:2; /* ngx_connection_log_error_e */ + unsigned log_error:3; /* ngx_connection_log_error_e */ unsigned single_connection:1; unsigned unexpected_eof:1; diff --git a/src/core/ngx_shmtx.h b/src/core/ngx_shmtx.h --- a/src/core/ngx_shmtx.h +++ b/src/core/ngx_shmtx.h @@ -57,7 +57,15 @@ ngx_shmtx_trylock(ngx_shmtx_t *mtx) return 0; } - ngx_log_abort(err, ngx_trylock_fd_n " failed"); +#if __osf__ /* Tru64 UNIX */ + + if (err == NGX_EACCESS) { + return 0; + } + +#endif + + ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name); return 0; } @@ -74,7 +82,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx) return; } - ngx_log_abort(err, ngx_lock_fd_n " failed"); + ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name); } @@ -89,7 +97,7 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx) return; } - ngx_log_abort(err, ngx_unlock_fd_n " failed"); + ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name); } 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 @@ -13,13 +13,15 @@ typedef struct { - ngx_str_t passwd; + ngx_str_t passwd; } ngx_http_auth_basic_ctx_t; typedef struct { - ngx_str_t realm; - ngx_str_t user_file; + ngx_str_t realm; + ngx_str_t user_file; + ngx_array_t *user_file_lengths; + ngx_array_t *user_file_values; } ngx_http_auth_basic_loc_conf_t; @@ -34,6 +36,8 @@ static char *ngx_http_auth_basic_merge_l void *parent, void *child); static ngx_int_t ngx_http_auth_basic_init(ngx_conf_t *cf); static char *ngx_http_auth_basic(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static ngx_conf_post_handler_pt ngx_http_auth_basic_p = ngx_http_auth_basic; @@ -51,7 +55,7 @@ static ngx_command_t ngx_http_auth_basi { ngx_string("auth_basic_user_file"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LMT_CONF |NGX_CONF_TAKE1, - ngx_conf_set_str_slot, + ngx_http_auth_basic_user_file, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_auth_basic_loc_conf_t, user_file), NULL }, @@ -98,8 +102,9 @@ ngx_http_auth_basic_handler(ngx_http_req ssize_t n; ngx_fd_t fd; ngx_int_t rc; - ngx_str_t pwd; - ngx_uint_t i, login, left, passwd; + ngx_err_t err; + ngx_str_t pwd, user_file; + ngx_uint_t i, level, login, left, passwd; ngx_file_t file; ngx_http_auth_basic_ctx_t *ctx; ngx_http_auth_basic_loc_conf_t *alcf; @@ -137,18 +142,44 @@ ngx_http_auth_basic_handler(ngx_http_req return NGX_HTTP_INTERNAL_SERVER_ERROR; } - fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (alcf->user_file_lengths) { + if (ngx_http_script_run(r, &user_file, alcf->user_file_lengths->elts, 1, + alcf->user_file_values->elts) + == NULL) + { + return NGX_ERROR; + } + + user_file.data[--user_file.len] = '\0'; + + } else { + user_file = alcf->user_file; + } + + fd = ngx_open_file(user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); if (fd == NGX_INVALID_FILE) { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, - ngx_open_file_n " \"%s\" failed", alcf->user_file.data); - return NGX_HTTP_INTERNAL_SERVER_ERROR; + err = ngx_errno; + + if (err == NGX_ENOENT) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_FORBIDDEN; + + } else { + level = NGX_LOG_CRIT; + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_log_error(level, r->connection->log, err, + ngx_open_file_n " \"%s\" failed", user_file.data); + + return rc; } ngx_memzero(&file, sizeof(ngx_file_t)); file.fd = fd; - file.name = alcf->user_file; + file.name = user_file; file.log = r->connection->log; state = sw_login; @@ -255,7 +286,7 @@ ngx_http_auth_basic_handler(ngx_http_req ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "user \"%V\" was not found in \"%V\"", - &r->headers_in.user, &alcf->user_file); + &r->headers_in.user, &user_file); return ngx_http_auth_basic_set_realm(r, &alcf->realm); } @@ -370,13 +401,10 @@ ngx_http_auth_basic_merge_loc_conf(ngx_c conf->realm = prev->realm; } - if (conf->user_file.data) { - if (ngx_conf_full_name(cf->cycle, &conf->user_file, 1) != NGX_OK) { - return NGX_CONF_ERROR; - } - - } else { + if (conf->user_file.data == NULL) { conf->user_file = prev->user_file; + conf->user_file_lengths = prev->user_file_lengths; + conf->user_file_values = prev->user_file_values; } return NGX_CONF_OK; @@ -433,3 +461,59 @@ ngx_http_auth_basic(ngx_conf_t *cf, void return NGX_CONF_OK; } + + +static char * +ngx_http_auth_basic_user_file(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_auth_basic_loc_conf_t *alcf = conf; + + ngx_str_t *value; + ngx_uint_t n; + ngx_http_core_loc_conf_t *clcf; + ngx_http_script_compile_t sc; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + + if (alcf->user_file.data) { + return "is duplicate"; + } + + value = cf->args->elts; + + alcf->user_file = value[1]; + + if (alcf->user_file.len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &alcf->user_file); + return NGX_CONF_ERROR; + } + + if (alcf->user_file.data[0] != '$') { + if (ngx_conf_full_name(cf->cycle, &alcf->user_file, 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + n = ngx_http_script_variables_count(&alcf->user_file); + + if (n == 0) { + return NGX_CONF_OK; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &alcf->user_file; + sc.lengths = &alcf->user_file_lengths; + sc.values = &alcf->user_file_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/http/modules/ngx_http_index_module.c b/src/http/modules/ngx_http_index_module.c --- a/src/http/modules/ngx_http_index_module.c +++ b/src/http/modules/ngx_http_index_module.c @@ -198,7 +198,7 @@ ngx_http_index_handler(ngx_http_request_ path.len = e.pos - path.data; - *e.pos++ = '\0'; + *e.pos = '\0'; } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.41'; +our $VERSION = '0.7.42'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -1768,6 +1768,10 @@ ngx_http_add_listening(ngx_conf_t *cf, n ls->deferred_accept = addr->listen_conf->deferred_accept; #endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + ls->ipv6only = addr->listen_conf->ipv6only; +#endif + return ls; } 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 @@ -1122,7 +1122,7 @@ ngx_http_core_try_files_phase(ngx_http_r path.len = e.pos - path.data; - *e.pos++ = '\0'; + *e.pos = '\0'; if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) { ngx_memcpy(name, name + alias, len - alias); @@ -1378,13 +1378,15 @@ ngx_http_core_find_location(ngx_http_req ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "test location: ~ \"%V\"", &(*clcfp)->name); - if ((*clcfp)->captures && r->captures == NULL) { + if ((*clcfp)->captures) { len = (NGX_HTTP_MAX_CAPTURES + 1) * 3; - r->captures = ngx_palloc(r->pool, len * sizeof(int)); if (r->captures == NULL) { - return NGX_ERROR; + r->captures = ngx_palloc(r->pool, len * sizeof(int)); + if (r->captures == NULL) { + return NGX_ERROR; + } } } @@ -1672,13 +1674,11 @@ ngx_http_map_uri_to_path(ngx_http_reques return NULL; } - reserved += r->uri.len - alias + 1; - if (clcf->root_lengths == NULL) { *root_length = clcf->root.len; - path->len = clcf->root.len + reserved; + path->len = clcf->root.len + reserved + r->uri.len - alias + 1; path->data = ngx_pnalloc(r->pool, path->len); if (path->data == NULL) { @@ -1688,7 +1688,7 @@ ngx_http_map_uri_to_path(ngx_http_reques last = ngx_copy(path->data, clcf->root.data, clcf->root.len); } else { - if (ngx_http_script_run(r, path, clcf->root_lengths->elts, reserved, + if (ngx_http_script_run(r, path, clcf->root_lengths->elts, ++reserved, clcf->root_values->elts) == NULL) { @@ -3332,6 +3332,45 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx continue; } + if (ngx_strncmp(value[n].data, "ipv6only=o", 10) == 0) { +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + struct sockaddr *sa; + + sa = (struct sockaddr *) ls->sockaddr; + + if (sa->sa_family == AF_INET6) { + + if (ngx_strcmp(&value[n].data[10], "n") == 0) { + ls->conf.ipv6only = 1; + + } else if (ngx_strcmp(&value[n].data[10], "ff") == 0) { + ls->conf.ipv6only = 2; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid ipv6only flags \"%s\"", + &value[n].data[9]); + return NGX_CONF_ERROR; + } + + ls->conf.bind = 1; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "ipv6only is not supported " + "on addr \"%s\", ignored", + ls->conf.addr); + } + + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bind ipv6only is not supported " + "on this platform"); + return NGX_CONF_ERROR; +#endif + } + if (ngx_strcmp(value[n].data, "ssl") == 0) { #if (NGX_HTTP_SSL) ls->conf.ssl = 1; diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -44,6 +44,9 @@ typedef struct { #if (NGX_HTTP_SSL) unsigned ssl:1; #endif +#if (NGX_HAVE_INET6 && defined IPV6_V6ONLY) + unsigned ipv6only:2; +#endif int backlog; int rcvbuf; 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 @@ -1611,7 +1611,6 @@ static ngx_int_t ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len) { u_char *server; - size_t ncaptures; ngx_uint_t hash; ngx_http_virtual_names_t *vn; ngx_http_core_loc_conf_t *clcf; @@ -1646,6 +1645,7 @@ ngx_http_find_virtual_server(ngx_http_re #if (NGX_PCRE) if (vn->nregex) { + size_t ncaptures; ngx_int_t n; ngx_uint_t i; ngx_str_t name; @@ -2421,8 +2421,15 @@ ngx_http_set_keepalive(ngx_http_request_ (const void *) &tcp_nodelay, sizeof(int)) == -1) { +#if (NGX_SOLARIS) + /* Solaris returns EINVAL if a socket has been shut down */ + c->log_error = NGX_ERROR_IGNORE_EINVAL; +#endif + ngx_connection_error(c, ngx_socket_errno, "setsockopt(TCP_NODELAY) failed"); + + c->log_error = NGX_ERROR_INFO; ngx_http_close_connection(c); return; }