# HG changeset patch # User Igor Sysoev # Date 1180900800 -14400 # Node ID 55328d69b335bdb8866a77f2935c0ddb3940dc77 # Parent 892db29abb4fe00f50bf72363538622b7ecc4e1a 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. diff --git a/CHANGES b/CHANGES --- 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. diff --git a/CHANGES.ru b/CHANGES.ru --- 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 *) Исправление: большое тело запроса могло не передаваться бэкенду; 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.5.22" +#define NGINX_VERSION "0.5.23" #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 @@ -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); } } diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- 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) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- 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, ""); diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- 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; 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.5.22'; +our $VERSION = '0.5.23'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/ngx_http_perl_module.c b/src/http/modules/perl/ngx_http_perl_module.c --- 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(); +} diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h --- 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, 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 @@ -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);