changeset 378:fc497c1dfb7c NGINX_0_6_33

nginx 0.6.33 *) Feature: now nginx returns the 405 status code for POST method requesting a static file only if the file exists. *) Workaround: compatibility with glibc 2.3. Thanks to Eric Benson and Maxim Dounin. *) Bugfix: the resolver did not understand big DNS responses. Thanks to Zyb. *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" error. *) Bugfix: the ngx_http_charset_module did not understand quoted charset name received from backend. *) Bugfix: if the "max_fails=0" parameter was used in upstream with several servers, then a worker process exited on a SIGFPE signal. Thanks to Maxim Dounin. *) Bugfix: the $r->header_in() method did not return value of the "Host", "User-Agent", and "Connection" request header lines; the bug had appeared in 0.6.32. *) Bugfix: a full response was returned for request method HEAD while redirection via an "error_page" directive. *) Bugfix: if a directory has search only rights and the first index file was absent, then nginx returned the 500 status code. *) Bugfix: of recursive error_page for 500 status code.
author Igor Sysoev <http://sysoev.ru>
date Thu, 20 Nov 2008 00:00:00 +0300
parents 15c4ba3bc2fa
children 522189e0ef36
files CHANGES CHANGES.ru src/core/nginx.c src/core/nginx.h src/core/ngx_conf_file.c src/core/ngx_cycle.c src/core/ngx_log.c src/core/ngx_resolver.c src/event/ngx_event_openssl.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_request.c src/http/ngx_http_special_response.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream_round_robin.c src/os/unix/ngx_files.h
diffstat 17 files changed, 197 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,38 @@
 
+Changes with nginx 0.6.33                                        20 Nov 2008
+
+    *) Feature: now nginx returns the 405 status code for POST method 
+       requesting a static file only if the file exists.
+
+    *) Workaround: compatibility with glibc 2.3.
+       Thanks to Eric Benson and Maxim Dounin.
+
+    *) Bugfix: the resolver did not understand big DNS responses.
+       Thanks to Zyb.
+
+    *) Bugfix: in HTTPS mode requests might fail with the "bad write retry" 
+       error.
+
+    *) Bugfix: the ngx_http_charset_module did not understand quoted 
+       charset name received from backend.
+
+    *) Bugfix: if the "max_fails=0" parameter was used in upstream with 
+       several servers, then a worker process exited on a SIGFPE signal.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the $r->header_in() method did not return value of the 
+       "Host", "User-Agent", and "Connection" request header lines; the bug 
+       had appeared in 0.6.32.
+
+    *) Bugfix: a full response was returned for request method HEAD while 
+       redirection via an "error_page" directive.
+
+    *) Bugfix: if a directory has search only rights and the first index 
+       file was absent, then nginx returned the 500 status code.
+
+    *) Bugfix: of recursive error_page for 500 status code.
+
+
 Changes with nginx 0.6.32                                        07 Jul 2008
 
     *) Change: the "none" parameter in the "ssl_session_cache" directive; 
@@ -274,8 +308,7 @@ Changes with nginx 0.6.22               
 Changes with nginx 0.6.21                                        03 Dec 2007
 
     *) Change: if variable values used in a "proxy_pass" directive contain 
-       IP-addresses only, then a "resolver" directive is not mandatory. 
-       resolver
+       IP-addresses only, then a "resolver" directive is not mandatory.
 
     *) Bugfix: a segmentation fault might occur in worker process if a 
        "proxy_pass" directive with URI-part was used; the bug had appeared 
@@ -1427,7 +1460,7 @@ Changes with nginx 0.3.55               
     *) Bugfix: if the request contained "//" or "/./" and escaped symbols 
        after them, then the proxied request was sent unescaped.
 
-    *) Bugfix: the $r->headers_in("Cookie") of the ngx_http_perl_module now 
+    *) Bugfix: the $r->header_in("Cookie") of the ngx_http_perl_module now 
        returns all "Cookie" header lines.
 
     *) Bugfix: a segmentation fault occurred if 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,39 @@
 
+Изменения в nginx 0.6.33                                          20.11.2008
+
+    *) Добавление: теперь nginx возвращает код 405 для метода POST при 
+       запросе статического файла, только если файл существует.
+
+    *) Изменение: совместимость с glibc 2.3.
+       Спасибо Eric Benson и Максиму Дунину.
+
+    *) Исправление: resolver не понимал большие DNS-ответы.
+       Спасибо Zyb.
+
+    *) Исправление: при использовании HTTPS запросы могли завершаться с 
+       ошибкой "bad write retry".
+
+    *) Исправление: модуль ngx_http_charset_module не понимал название 
+       кодировки в кавычках, полученное от бэкенда.
+
+    *) Исправление: при использовании параметра max_fails=0 в upstream'е с 
+       несколькими серверами рабочий процесс выходил по сигналу SIGFPE.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: метод $r->header_in() не возвращал значения строк 
+       "Host", "User-Agent", и "Connection" из заголовка запроса; ошибка 
+       появилась в 0.6.32.
+
+    *) Исправление: при перенаправлении запроса с методом HEAD с помощью 
+       директивы error_page возвращался полный ответ.
+
+    *) Исправление: если у каталога были права доступа только на поиск 
+       файлов и первый индексный файл отсутствовал, то nginx возвращал 
+       ошибку 500.
+
+    *) Исправление: рекурсивной error_page для 500 ошибки.
+
+
 Изменения в nginx 0.6.32                                          07.07.2008
 
     *) Изменение: параметр "none" в директиве ssl_session_cache; теперь 
@@ -1461,7 +1496,7 @@
        закодированные символы в виде "%XX", то проксируемый запрос 
        передавался незакодированным.
 
-    *) Исправление: метод $r->headers_in("Cookie") модуля 
+    *) Исправление: метод $r->header_in("Cookie") модуля 
        ngx_http_perl_module теперь возвращает все строки "Cookie" в 
        заголовке запроса.
 
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -192,6 +192,8 @@ static char **ngx_os_environ;
 int ngx_cdecl
 main(int argc, char *const *argv)
 {
+    char             *p;
+    ssize_t           n;
     ngx_int_t         i;
     ngx_log_t        *log;
     ngx_cycle_t      *cycle, init_cycle;
@@ -241,23 +243,30 @@ main(int argc, char *const *argv)
     }
 
     if (ngx_show_version) {
-        ngx_write_fd(ngx_stderr_fileno, "nginx version: " NGINX_VER CRLF,
-                     sizeof("nginx version: " NGINX_VER CRLF) - 1);
+
+        p = "nginx version: " NGINX_VER CRLF;
+        n = sizeof("nginx version: " NGINX_VER CRLF) - 1;
+
+        if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
+            return 1;
+        }
 
         if (ngx_show_configure) {
 #ifdef NGX_COMPILER
-            ngx_write_fd(ngx_stderr_fileno, "built by " NGX_COMPILER CRLF,
-                         sizeof("built by " NGX_COMPILER CRLF) - 1);
+            p = "built by " NGX_COMPILER CRLF;
+            n = sizeof("built by " NGX_COMPILER CRLF) - 1;
+
+            if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
+                return 1;
+            }
 #endif
 
-#ifndef __WATCOMC__
-
-            /* OpenWatcomC could not build the long NGX_CONFIGURE string */
+            p = "configure arguments: " NGX_CONFIGURE CRLF;
+            n = sizeof("configure arguments :" NGX_CONFIGURE CRLF) - 1;
 
-            ngx_write_fd(ngx_stderr_fileno,
-                        "configure arguments: " NGX_CONFIGURE CRLF,
-                        sizeof("configure arguments :" NGX_CONFIGURE CRLF) - 1);
-#endif
+            if (ngx_write_fd(ngx_stderr_fileno, p, n) != n) {
+                return 1;
+            }
         }
 
         if (!ngx_test_config) {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.32"
+#define NGINX_VERSION      "0.6.33"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -806,6 +806,7 @@ ngx_conf_open_file(ngx_cycle_t *cycle, n
 static void
 ngx_conf_flush_files(ngx_cycle_t *cycle)
 {
+    ssize_t           n, len;
     ngx_uint_t        i;
     ngx_list_part_t  *part;
     ngx_open_file_t  *file;
@@ -826,11 +827,24 @@ ngx_conf_flush_files(ngx_cycle_t *cycle)
             i = 0;
         }
 
-        if (file[i].buffer == NULL || file[i].pos - file[i].buffer == 0) {
+        len = file[i].pos - file[i].buffer;
+
+        if (file[i].buffer == NULL || len == 0) {
             continue;
         }
 
-        ngx_write_fd(file[i].fd, file[i].buffer, file[i].pos - file[i].buffer);
+        n = ngx_write_fd(file[i].fd, file[i].buffer, len);
+
+        if (n == NGX_FILE_ERROR) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                          ngx_write_fd_n " to \"%s\" failed",
+                          file[i].name.data);
+
+        } else if (n != len) {
+            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                          ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
+                          file[i].name.data, n, len);
+        }
     }
 }
 
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -970,6 +970,7 @@ ngx_test_lockfile(u_char *file, ngx_log_
 void
 ngx_reopen_files(ngx_cycle_t *cycle, ngx_uid_t user)
 {
+    ssize_t           n, len;
     ngx_fd_t          fd;
     ngx_uint_t        i;
     ngx_list_part_t  *part;
@@ -993,9 +994,23 @@ ngx_reopen_files(ngx_cycle_t *cycle, ngx
             continue;
         }
 
-        if (file[i].buffer && file[i].pos - file[i].buffer != 0) {
-            ngx_write_fd(file[i].fd, file[i].buffer,
-                         file[i].pos - file[i].buffer);
+        len = file[i].pos - file[i].buffer;
+
+        if (file[i].buffer && len != 0) {
+
+            n = ngx_write_fd(file[i].fd, file[i].buffer, len);
+
+            if (n == NGX_FILE_ERROR) {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
+                              ngx_write_fd_n " to \"%s\" failed",
+                              file[i].name.data);
+
+            } else if (n != len) {
+                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
+                          ngx_write_fd_n " to \"%s\" was incomplete: %z of %uz",
+                          file[i].name.data, n, len);
+            }
+
             file[i].pos = file[i].buffer;
         }
 
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -158,7 +158,7 @@ ngx_log_error_core(ngx_uint_t level, ngx
 
     ngx_linefeed(p);
 
-    ngx_write_fd(log->file->fd, errstr, p - errstr);
+    (void) ngx_write_fd(log->file->fd, errstr, p - errstr);
 }
 
 
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1836,7 +1836,7 @@ ngx_resolver_copy(ngx_resolver_t *r, ngx
         }
 
         if (n & 0xc0) {
-            n = (n & 0x3f << 8) + *p;
+            n = ((n & 0x3f) << 8) + *p;
             p = &buf[n];
 
         } else {
@@ -1886,7 +1886,7 @@ done:
             }
 
         } else {
-            n = (n & 0x3f << 8) + *src;
+            n = ((n & 0x3f) << 8) + *src;
             src = &buf[n];
 
             n = *src++;
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -187,13 +187,6 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_
         SSL_CTX_set_options(ssl->ctx, ngx_ssl_protocols[protocols >> 1]);
     }
 
-    /*
-     * we need this option because in ngx_ssl_send_chain()
-     * we may switch to a buffered write and may copy leftover part of
-     * previously unbuffered data to our internal buffer
-     */
-    SSL_CTX_set_mode(ssl->ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
-
     SSL_CTX_set_read_ahead(ssl->ctx, 1);
 
     return NGX_OK;
@@ -776,14 +769,7 @@ ngx_ssl_send_chain(ngx_connection_t *c, 
     ssize_t      send, size;
     ngx_buf_t   *buf;
 
-    if (!c->ssl->buffer
-        || (in && in->next == NULL && !(c->buffered & NGX_SSL_BUFFERED)))
-    {
-        /*
-         * we avoid a buffer copy if
-         *     we do not need to buffer the output
-         *     or the incoming buf is a single and our buffer is empty
-         */
+    if (!c->ssl->buffer) {
 
         while (in) {
             if (ngx_buf_special(in->buf)) {
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -306,6 +306,19 @@ ngx_http_index_test_dir(ngx_http_request
                 return ngx_http_index_error(r, dir.data, NGX_ENOENT);
             }
 
+            if (of.err == NGX_EACCES) {
+
+                *last = c;
+
+                /*
+                 * ngx_http_index_test_dir() is called after the first index
+                 * file testing has returned an error distinct from NGX_EACCES.
+                 * This means that directory searching is allowed.
+                 */
+
+                return NGX_OK;
+            }
+
             ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
                           ngx_open_file_n " \"%s\" failed", dir.data);
         }
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -58,7 +58,7 @@ ngx_http_static_handler(ngx_http_request
     ngx_open_file_info_t       of;
     ngx_http_core_loc_conf_t  *clcf;
 
-    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
+    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) {
         return NGX_HTTP_NOT_ALLOWED;
     }
 
@@ -71,12 +71,6 @@ ngx_http_static_handler(ngx_http_request
         return NGX_DECLINED;
     }
 
-    rc = ngx_http_discard_request_body(r);
-
-    if (rc != NGX_OK) {
-        return rc;
-    }
-
     log = r->connection->log;
 
     /*
@@ -186,6 +180,16 @@ ngx_http_static_handler(ngx_http_request
 
 #endif
 
+    if (r->method & NGX_HTTP_POST) {
+        return NGX_HTTP_NOT_ALLOWED;
+    }
+
+    rc = ngx_http_discard_request_body(r);
+
+    if (rc != NGX_OK) {
+        return rc;
+    }
+
     log->action = "sending response to client";
 
     r->headers_out.status = NGX_HTTP_OK;
--- 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.6.32';
+our $VERSION = '0.6.33';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -74,15 +74,18 @@ static char *ngx_http_client_errors[] = 
 
 
 ngx_http_header_t  ngx_http_headers_in[] = {
-    { ngx_string("Host"), 0, ngx_http_process_host },
-
-    { ngx_string("Connection"), 0, ngx_http_process_connection },
+    { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host),
+                 ngx_http_process_host },
+
+    { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection),
+                 ngx_http_process_connection },
 
     { ngx_string("If-Modified-Since"),
                  offsetof(ngx_http_headers_in_t, if_modified_since),
                  ngx_http_process_unique_header_line },
 
-    { ngx_string("User-Agent"), 0, ngx_http_process_user_agent },
+    { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent),
+                 ngx_http_process_user_agent },
 
     { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer),
                  ngx_http_process_header_line },
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -327,7 +327,6 @@ static ngx_str_t  ngx_http_get_name = { 
 ngx_int_t
 ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error)
 {
-    ngx_int_t                  rc;
     ngx_uint_t                 i, err;
     ngx_http_err_page_t       *err_page;
     ngx_http_core_loc_conf_t  *clcf;
@@ -335,12 +334,6 @@ ngx_http_special_response_handler(ngx_ht
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http special response: %d, \"%V\"", error, &r->uri);
 
-    rc = ngx_http_discard_request_body(r);
-
-    if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) {
-        error = NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
     r->err_status = error;
 
     if (r->keepalive != 0) {
@@ -370,7 +363,7 @@ ngx_http_special_response_handler(ngx_ht
 
     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
 
-    if (!r->error_page && clcf->error_pages) {
+    if (!r->error_page && clcf->error_pages && r->uri_changes != 0) {
 
         if (clcf->recursive_error_pages == 0) {
             r->error_page = 1;
@@ -385,6 +378,10 @@ ngx_http_special_response_handler(ngx_ht
         }
     }
 
+    if (ngx_http_discard_request_body(r) != NGX_OK) {
+        error = NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
     if (clcf->msie_refresh
         && r->headers_in.msie
         && (error == NGX_HTTP_MOVED_PERMANENTLY
@@ -492,8 +489,10 @@ ngx_http_send_error_page(ngx_http_reques
 
     if (uri->data[0] == '/') {
 
-        r->method = NGX_HTTP_GET;
-        r->method_name = ngx_http_get_name;
+        if (r->method != NGX_HTTP_HEAD) {
+            r->method = NGX_HTTP_GET;
+            r->method_name = ngx_http_get_name;
+        }
 
         return ngx_http_internal_redirect(r, uri, args);
     }
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2625,7 +2625,17 @@ ngx_http_upstream_copy_content_type(ngx_
 
         r->headers_out.content_type_len = last - h->value.data;
 
-        r->headers_out.charset.len = h->value.data + h->value.len - p;
+        if (*p == '"') {
+            p++;
+        }
+
+        last = h->value.data + h->value.len;
+
+        if (*(last - 1) == '"') {
+            last--;
+        }
+
+        r->headers_out.charset.len = last - p;
         r->headers_out.charset.data = p;
 
         return NGX_OK;
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -645,7 +645,9 @@ ngx_http_upstream_free_round_robin_peer(
         peer->fails++;
         peer->accessed = now;
 
-        peer->current_weight -= peer->weight / peer->max_fails;
+        if (peer->max_fails) {
+            peer->current_weight -= peer->weight / peer->max_fails;
+        }
 
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
                        "free rr peer failed: %ui %i",
--- a/src/os/unix/ngx_files.h
+++ b/src/os/unix/ngx_files.h
@@ -68,7 +68,17 @@ ssize_t ngx_write_chain_to_file(ngx_file
 #define ngx_read_fd              read
 #define ngx_read_fd_n            "read()"
 
-#define ngx_write_fd             write
+/*
+ * we use inlined function instead of simple #define
+ * because glibc 2.3 sets warn_unused_result attribute for write()
+ * and in this case gcc 4.3 ignores (void) cast
+ */
+static ngx_inline ssize_t
+ngx_write_fd(ngx_fd_t fd, void *buf, size_t n)
+{
+    return write(fd, buf, n);
+}
+
 #define ngx_write_fd_n           "write()"
 
 #define ngx_linefeed(p)          *p++ = LF;