From c31cf8658577383463126940303953bbbcf52751 Mon Sep 17 00:00:00 2001 From: Dobrica Pavlinusic Date: Sat, 21 Mar 2009 18:02:57 +0100 Subject: [PATCH] upstream nginx-0.7.42 --- nginx/CHANGES | 25 ++++ nginx/CHANGES.ru | 24 ++++ nginx/src/core/nginx.h | 2 +- nginx/src/core/ngx_connection.c | 28 +++- nginx/src/core/ngx_connection.h | 11 +- nginx/src/core/ngx_shmtx.h | 14 +- .../http/modules/ngx_http_auth_basic_module.c | 120 +++++++++++++++--- .../src/http/modules/ngx_http_index_module.c | 2 +- nginx/src/http/modules/perl/nginx.pm | 2 +- nginx/src/http/ngx_http.c | 4 + nginx/src/http/ngx_http_core_module.c | 55 ++++++-- nginx/src/http/ngx_http_core_module.h | 3 + nginx/src/http/ngx_http_request.c | 9 +- 13 files changed, 260 insertions(+), 39 deletions(-) diff --git a/nginx/CHANGES b/nginx/CHANGES index 8129db7..7000d57 100644 --- a/nginx/CHANGES +++ b/nginx/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/nginx/CHANGES.ru b/nginx/CHANGES.ru index 575fa6c..d44de11 100644 --- a/nginx/CHANGES.ru +++ b/nginx/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/nginx/src/core/nginx.h b/nginx/src/core/nginx.h index 2c0406c..cc0945b 100644 --- a/nginx/src/core/nginx.h +++ b/nginx/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/nginx/src/core/ngx_connection.c b/nginx/src/core/ngx_connection.c index f48eefb..f413ffb 100644 --- a/nginx/src/core/ngx_connection.c +++ b/nginx/src/core/ngx_connection.c @@ -282,6 +282,23 @@ ngx_open_listening_sockets(ngx_cycle_t *cycle) 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,11 +799,15 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { 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 @@ -803,6 +824,7 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { 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/nginx/src/core/ngx_connection.h b/nginx/src/core/ngx_connection.h index d9b80f9..cc6a929 100644 --- a/nginx/src/core/ngx_connection.h +++ b/nginx/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/nginx/src/core/ngx_shmtx.h b/nginx/src/core/ngx_shmtx.h index e6fb6aa..57fe0b9 100644 --- a/nginx/src/core/ngx_shmtx.h +++ b/nginx/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/nginx/src/http/modules/ngx_http_auth_basic_module.c b/nginx/src/http/modules/ngx_http_auth_basic_module.c index 1c23339..7506f7f 100644 --- a/nginx/src/http/modules/ngx_http_auth_basic_module.c +++ b/nginx/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_loc_conf(ngx_conf_t *cf, 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_basic_commands[] = { { 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_request_t *r) 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_request_t *r) 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_request_t *r) 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_conf_t *cf, void *parent, void *child) 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 *post, void *data) 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/nginx/src/http/modules/ngx_http_index_module.c b/nginx/src/http/modules/ngx_http_index_module.c index f9ce849..fd20105 100644 --- a/nginx/src/http/modules/ngx_http_index_module.c +++ b/nginx/src/http/modules/ngx_http_index_module.c @@ -198,7 +198,7 @@ ngx_http_index_handler(ngx_http_request_t *r) 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/nginx/src/http/modules/perl/nginx.pm b/nginx/src/http/modules/perl/nginx.pm index a780ee4..9979a72 100644 --- a/nginx/src/http/modules/perl/nginx.pm +++ b/nginx/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/nginx/src/http/ngx_http.c b/nginx/src/http/ngx_http.c index 626686c..d519bf9 100644 --- a/nginx/src/http/ngx_http.c +++ b/nginx/src/http/ngx_http.c @@ -1768,6 +1768,10 @@ ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr) 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/nginx/src/http/ngx_http_core_module.c b/nginx/src/http/ngx_http_core_module.c index a2d4e86..66698d5 100644 --- a/nginx/src/http/ngx_http_core_module.c +++ b/nginx/src/http/ngx_http_core_module.c @@ -1122,7 +1122,7 @@ ngx_http_core_try_files_phase(ngx_http_request_t *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_request_t *r) 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_request_t *r, ngx_str_t *path, 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_request_t *r, ngx_str_t *path, 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_command_t *cmd, void *conf) 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/nginx/src/http/ngx_http_core_module.h b/nginx/src/http/ngx_http_core_module.h index 7ad18ed..705659d 100644 --- a/nginx/src/http/ngx_http_core_module.h +++ b/nginx/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/nginx/src/http/ngx_http_request.c b/nginx/src/http/ngx_http_request.c index c018d68..0280c63 100644 --- a/nginx/src/http/ngx_http_request.c +++ b/nginx/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_request_t *r, u_char *host, size_t len) #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_t *r) (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; } -- 2.20.1