changeset 306:55328d69b335 NGINX_0_5_23

nginx 0.5.23 *) Feature: the ngx_http_ssl_module supports Server Name Indication TLS extension. *) Feature: the "fastcgi_catch_stderr" directive. Thanks to Nick S. Grechukh, OWOX project. *) Bugfix: a segmentation fault occurred in master process if two virtual servers should bind() to the overlapping ports. *) Bugfix: if nginx was built with ngx_http_perl_module and perl supported threads, then during second reconfiguration the error messages "panic: MUTEX_LOCK" and "perl_parse() failed" were issued. *) Bugfix: in the HTTPS protocol in the "proxy_pass" directive.
author Igor Sysoev <http://sysoev.ru>
date Mon, 04 Jun 2007 00:00:00 +0400
parents 892db29abb4f
children 0bcb7f864b94
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_connection.c src/core/ngx_output_chain.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http.h src/http/ngx_http_request.c
diffstat 11 files changed, 197 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,25 @@
 
+Changes with nginx 0.5.23                                        04 Jun 2007
+
+    *) Feature: the ngx_http_ssl_module supports Server Name Indication TLS 
+       extension.
+
+    *) Feature: the "fastcgi_catch_stderr" directive.
+       Thanks to Nick S. Grechukh, OWOX project.
+
+    *) Bugfix: a segmentation fault occurred in master process if two 
+       virtual servers should bind() to the overlapping ports.
+
+    *) Bugfix: if nginx was built with ngx_http_perl_module and perl 
+       supported threads, then during second reconfiguration the error 
+       messages "panic: MUTEX_LOCK" and "perl_parse() failed" were issued.
+
+    *) Bugfix: in the HTTPS protocol in the "proxy_pass" directive.
+
+
 Changes with nginx 0.5.22                                        29 May 2007
 
-    *) Bugfix: the big request body might not be passed to backend; bug 
+    *) Bugfix: a big request body might not be passed to backend; bug 
        appeared in 0.5.21.
 
 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,23 @@
 
+Изменения в nginx 0.5.23                                          04.06.2007
+
+    *) Добавление: модуль ngx_http_ssl_module поддерживает расширение TLS 
+       Server Name Indication.
+
+    *) Добавление: директива fastcgi_catch_stderr.
+       Спасибо Николаю Гречуху, проект OWOX.
+
+    *) Исправление: на Линуксе в основном процессе происходил segmentation 
+       fault, если два виртуальных сервера должны bind()ится к 
+       пересекающимся портам.
+
+    *) Исправление: если nginx был собран с модулем ngx_http_perl_module и 
+       perl поддерживал потоки, то во время второй переконфигурации 
+       выдавались ошибки "panic: MUTEX_LOCK" и "perl_parse() failed".
+
+    *) Исправление: в использовании протокола HTTPS в директиве proxy_pass.
+
+
 Изменения в nginx 0.5.22                                          29.05.2007
 
     *) Исправление: большое тело запроса могло не передаваться бэкенду; 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.22"
+#define NGINX_VERSION      "0.5.23"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -270,10 +270,11 @@ ngx_open_listening_sockets(ngx_cycle_t *
                               "setsockopt(SO_REUSEADDR) %V failed",
                               &ls[i].addr_text);
 
-                if (ngx_close_socket(s) == -1)
+                if (ngx_close_socket(s) == -1) {
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_close_socket_n " %V failed",
                                   &ls[i].addr_text);
+                }
 
                 return NGX_ERROR;
             }
@@ -286,10 +287,11 @@ ngx_open_listening_sockets(ngx_cycle_t *
                                   ngx_nonblocking_n " %V failed",
                                   &ls[i].addr_text);
 
-                    if (ngx_close_socket(s) == -1)
+                    if (ngx_close_socket(s) == -1) {
                         ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                       ngx_close_socket_n " %V failed",
                                       &ls[i].addr_text);
+                    }
 
                     return NGX_ERROR;
                 }
@@ -308,10 +310,11 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 ngx_log_error(NGX_LOG_EMERG, log, err,
                               "bind() to %V failed", &ls[i].addr_text);
 
-                if (ngx_close_socket(s) == -1)
+                if (ngx_close_socket(s) == -1) {
                     ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
                                   ngx_close_socket_n " %V failed",
                                   &ls[i].addr_text);
+                }
 
                 if (err != NGX_EADDRINUSE) {
                     return NGX_ERROR;
@@ -322,6 +325,20 @@ ngx_open_listening_sockets(ngx_cycle_t *
                 continue;
             }
 
+            if (listen(s, ls[i].backlog) == -1) {
+                ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                              "listen() to %V, backlog %d failed",
+                              &ls[i].addr_text, ls[i].backlog);
+
+                if (ngx_close_socket(s) == -1) {
+                    ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno,
+                                  ngx_close_socket_n " %V failed",
+                                  &ls[i].addr_text);
+                }
+
+                return NGX_ERROR;
+            }
+
             ls[i].listen = 1;
 
             ls[i].fd = s;
@@ -402,10 +419,12 @@ ngx_configure_listening_socket(ngx_cycle
 #endif
 
         if (ls[i].listen) {
+
+            /* change backlog via listen() */
+
             if (listen(ls[i].fd, ls[i].backlog) == -1) {
                 ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_socket_errno,
-                              "changing the listen() backlog to %d "
-                              "for %V failed, ignored",
+                              "listen() to %V, backlog %d failed, ignored",
                               &ls[i].addr_text, ls[i].backlog);
             }
         }
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -377,8 +377,9 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
             dst->in_file = 0;
         }
 
-        if (src->last_buf && src->pos == src->last) {
-            dst->last_buf = 1;
+        if (src->pos == src->last) {
+            dst->flush = src->flush;
+            dst->last_buf = src->last_buf;
         }
 
     } else {
@@ -417,8 +418,9 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst
 
         src->file_pos += n;
 
-        if (src->last_buf && src->file_pos == src->file_last) {
-            dst->last_buf = 1;
+        if (src->pos == src->last) {
+            dst->flush = src->flush;
+            dst->last_buf = src->last_buf;
         }
     }
 
@@ -444,8 +446,9 @@ ngx_chain_writer(void *data, ngx_chain_t
 
         size += ngx_buf_size(in->buf);
 
-        ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
-                       "chain writer buf size: %uO", ngx_buf_size(in->buf));
+        ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0,
+                       "chain writer buf fl:%d s:%uO",
+                       in->buf->flush, ngx_buf_size(in->buf));
 
         cl = ngx_alloc_chain_link(ctx->pool);
         if (cl == NULL) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -19,6 +19,7 @@ typedef struct {
     ngx_array_t                   *params_len;
     ngx_array_t                   *params;
     ngx_array_t                   *params_source;
+    ngx_array_t                   *catch_stderr;
 } ngx_http_fastcgi_loc_conf_t;
 
 
@@ -345,6 +346,13 @@ static ngx_command_t  ngx_http_fastcgi_c
       offsetof(ngx_http_fastcgi_loc_conf_t, upstream.hide_headers),
       NULL },
 
+    { ngx_string("fastcgi_catch_stderr"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_str_array_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_fastcgi_loc_conf_t, catch_stderr),
+      NULL },
+
       ngx_null_command
 };
 
@@ -833,13 +841,14 @@ static ngx_int_t
 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
 {
     u_char                         *start, *last;
-    ngx_str_t                      *status_line, line;
+    ngx_str_t                      *status_line, line, *pattern;
     ngx_int_t                       rc, status;
     ngx_uint_t                      i;
     ngx_table_elt_t                *h;
     ngx_http_upstream_t            *u;
     ngx_http_fastcgi_ctx_t         *f;
     ngx_http_upstream_header_t     *hh;
+    ngx_http_fastcgi_loc_conf_t    *flcf;
     ngx_http_upstream_main_conf_t  *umcf;
 
     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
@@ -948,6 +957,20 @@ ngx_http_fastcgi_process_header(ngx_http
                 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                               "FastCGI sent in stderr: \"%V\"", &line);
 
+                flcf = ngx_http_get_module_loc_conf(r, ngx_http_fastcgi_module);
+
+                if (flcf->catch_stderr) {
+                    pattern = flcf->catch_stderr->elts;
+
+                    line.data[line.len - 1] = '\0';
+
+                    for (i = 0; i < flcf->catch_stderr->nelts; i++) {
+                        if (ngx_strstr(line.data, pattern[i].data)) {
+                            return NGX_HTTP_BAD_GATEWAY;
+                        }
+                    }
+                }
+
                 if (u->buffer.pos == u->buffer.last) {
 
                     if (!f->fastcgi_stdout) {
@@ -1528,6 +1551,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_con
      *     conf->upstream.hide_headers_hash = { NULL, 0 };
      *     conf->upstream.hide_headers = NULL;
      *     conf->upstream.pass_headers = NULL;
+     *     conf->upstream.catch_stderr = NULL;
      *     conf->upstream.schema = { 0, NULL };
      *     conf->upstream.uri = { 0, NULL };
      *     conf->upstream.location = NULL;
@@ -1719,6 +1743,8 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf
     ngx_conf_merge_value(conf->upstream.intercept_errors,
                               prev->upstream.intercept_errors, 0);
 
+    ngx_conf_merge_ptr_value(conf->catch_stderr, prev->catch_stderr, NULL);
+
 
     ngx_conf_merge_str_value(conf->index, prev->index, "");
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -345,6 +345,19 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
         return NGX_CONF_ERROR;
     }
 
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+
+    if (SSL_CTX_set_tlsext_servername_callback(conf->ssl.ctx,
+                                               ngx_http_ssl_servername)
+        == 0)
+    {
+        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
+                      "SSL_CTX_set_tlsext_servername_callback() failed");
+        return NGX_CONF_ERROR;
+    }
+
+#endif
+
     cln = ngx_pool_cleanup_add(cf->pool, 0);
     if (cln == NULL) {
         return NGX_CONF_ERROR;
--- 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.5.22';
+our $VERSION = '0.5.23';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -67,6 +67,8 @@ static char *ngx_http_perl_set(ngx_conf_
 static void ngx_http_perl_cleanup_perl(void *data);
 #endif
 
+static void ngx_http_perl_exit(ngx_cycle_t *cycle);
+
 
 static ngx_command_t  ngx_http_perl_commands[] = {
 
@@ -128,7 +130,7 @@ ngx_module_t  ngx_http_perl_module = {
     NULL,                                  /* init thread */
     NULL,                                  /* exit thread */
     NULL,                                  /* exit process */
-    NULL,                                  /* exit master */
+    ngx_http_perl_exit,                    /* exit master */
     NGX_MODULE_V1_PADDING
 };
 
@@ -478,12 +480,13 @@ ngx_http_perl_init_interpreter(ngx_conf_
 
 #endif
 
-    PERL_SYS_INIT(&ngx_argc, &ngx_argv);
+    if (nginx_stash == NULL) {
+        PERL_SYS_INIT(&ngx_argc, &ngx_argv);
+    }
 
     pmcf->perl = ngx_http_perl_create_interpreter(cf, pmcf);
 
     if (pmcf->perl == NULL) {
-        PERL_SYS_TERM();
         return NGX_CONF_ERROR;
     }
 
@@ -788,8 +791,6 @@ ngx_http_perl_cleanup_perl(void *data)
     (void) perl_destruct(perl);
 
     perl_free(perl);
-
-    PERL_SYS_TERM();
 }
 
 #endif
@@ -1001,3 +1002,10 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co
 
     return NGX_CONF_OK;
 }
+
+
+static void
+ngx_http_perl_exit(ngx_cycle_t *cycle)
+{
+    PERL_SYS_TERM();
+}
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -59,6 +59,10 @@ struct ngx_http_log_ctx_s {
 
 void ngx_http_init_connection(ngx_connection_t *c);
 
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg);
+#endif
+
 ngx_int_t ngx_http_parse_request_line(ngx_http_request_t *r, ngx_buf_t *b);
 ngx_int_t ngx_http_parse_complex_uri(ngx_http_request_t *r);
 ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -25,8 +25,8 @@ static ngx_int_t ngx_http_process_cookie
     ngx_table_elt_t *h, ngx_uint_t offset);
 
 static ngx_int_t ngx_http_process_request_header(ngx_http_request_t *r);
-static void ngx_http_find_virtual_server(ngx_http_request_t *r,
-    ngx_http_virtual_names_t *vn, ngx_uint_t hash);
+static void ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host,
+    size_t len, ngx_uint_t hash);
 
 static void ngx_http_request_handler(ngx_event_t *ev);
 static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
@@ -544,6 +544,54 @@ ngx_http_ssl_handshake_handler(ngx_conne
     return;
 }
 
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+
+int
+ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
+{
+    u_char                   *p;
+    ngx_uint_t                hash;
+    const char               *servername;
+    ngx_connection_t         *c;
+    ngx_http_request_t       *r;
+    ngx_http_ssl_srv_conf_t  *sscf;
+
+    servername = SSL_get_servername(ssl_conn, TLSEXT_NAMETYPE_host_name);
+
+    if (servername == NULL) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    c = ngx_ssl_get_connection(ssl_conn);
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
+                   "SSL server name: \"%s\"", servername);
+
+    r = c->data;
+
+    if (r->virtual_names == NULL) {
+        return SSL_TLSEXT_ERR_NOACK;
+    }
+
+    /* it seems browsers send low case server name */
+
+    hash = 0;
+
+    for (p = (u_char *) servername; *p; p++) {
+        hash = ngx_hash(hash, *p);
+    }
+
+    ngx_http_find_virtual_server(r, (u_char *) servername,
+                                 p - (u_char *) servername, hash);
+
+    sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
+
+    SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
+
+    return SSL_TLSEXT_ERR_OK;
+}
+
+#endif
 
 #endif
 
@@ -1203,7 +1251,7 @@ static ngx_int_t
 ngx_http_process_request_header(ngx_http_request_t *r)
 {
     size_t                    len;
-    u_char                   *ua, *user_agent, ch;
+    u_char                   *host, *ua, *user_agent, ch;
     ngx_uint_t                hash;
 #if (NGX_HTTP_SSL)
     long                      rc;
@@ -1234,7 +1282,18 @@ ngx_http_process_request_header(ngx_http
         r->headers_in.host_name_len = len;
 
         if (r->virtual_names) {
-            ngx_http_find_virtual_server(r, r->virtual_names, hash);
+
+            host = r->host_start;
+
+            if (host == NULL) {
+                host = r->headers_in.host->value.data;
+                len = r->headers_in.host_name_len;
+
+            } else {
+                len = r->host_end - host;
+            }
+
+            ngx_http_find_virtual_server(r, host, len, hash);
         }
 
     } else {
@@ -1394,23 +1453,14 @@ ngx_http_process_request_header(ngx_http
 
 
 static void
-ngx_http_find_virtual_server(ngx_http_request_t *r,
-    ngx_http_virtual_names_t *vn, ngx_uint_t hash)
+ngx_http_find_virtual_server(ngx_http_request_t *r, u_char *host, size_t len,
+    ngx_uint_t hash)
 {
-    size_t                     len;
-    u_char                    *host;
+    ngx_http_virtual_names_t  *vn;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
 
-    host = r->host_start;
-
-    if (host == NULL) {
-        host = r->headers_in.host->value.data;
-        len = r->headers_in.host_name_len;
-
-    } else {
-        len = r->host_end - host;
-    }
+    vn = r->virtual_names;
 
     if (vn->hash.buckets) {
         cscf = ngx_hash_find(&vn->hash, hash, host, len);