# HG changeset patch # User Igor Sysoev # Date 1185739200 -14400 # Node ID 1e9e2c5e7c145c502d4f837f443f11873fb74b69 # Parent 10d5a311cc5eb77a679858b64265b48be73943ce nginx 0.5.30 *) Feature: the $args variable can be set with the "set" directive. *) Feature: the $is_args variable. *) Bugfix: if a client has closed connection to mail proxy then nginx might not close connection to backend. *) Bugfix: now nginx escapes space in $memcached_key variable. *) Bugfix: a segmentation fault might occur in worker process when the HTTPS protocol was used in the "proxy_pass" directive. *) Bugfix: the perl $$ variable value in ngx_http_perl_module was equal to the master process identification number. *) Bugfix: fix building on Solaris/amd64 by Sun Studio 11 and early versions; bug appeared in 0.5.29. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,25 @@ +Changes with nginx 0.5.30 30 Jul 2007 + + *) Feature: the $args variable can be set with the "set" directive. + + *) Feature: the $is_args variable. + + *) Bugfix: if a client has closed connection to mail proxy then nginx + might not close connection to backend. + + *) Bugfix: now nginx escapes space in $memcached_key variable. + + *) Bugfix: a segmentation fault might occur in worker process when the + HTTPS protocol was used in the "proxy_pass" directive. + + *) Bugfix: the perl $$ variable value in ngx_http_perl_module was equal + to the master process identification number. + + *) Bugfix: fix building on Solaris/amd64 by Sun Studio 11 and early + versions; bug appeared in 0.5.29. + + Changes with nginx 0.5.29 23 Jul 2007 *) Feature: $nginx_version variable. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,26 @@ +Изменения в nginx 0.5.30 30.07.2007 + + *) Добавление: переменную $args можно устанавливать с помощью set. + + *) Добавление: переменная $is_args. + + *) Исправление: если клиент в почтовом прокси-сервере закрывал + соединение, то nginx мог не закрывать соединение с бэкендом. + + *) Исправление: теперь nginx экранирует пробел в переменной + $memcached_key. + + *) Исправление: при использовании протокола HTTPS в директиве + proxy_pass в рабочем процессе мог произойти segmentation fault. + + *) Исправление: значение perl'овой переменной $$ модуля + ngx_http_perl_module было равно номеру главного процесса. + + *) Исправление: nginx не собирался на Solaris/amd64 Sun Studio 11 и + более ранними версиями; ошибка появилась в 0.5.29. + + Изменения в nginx 0.5.29 23.07.2007 *) Добавление: переменная $nginx_version. diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -39,7 +39,7 @@ if [ "$ngx_sunc_ver" -ge 1424 ]; then else ngx_sparc32="-xarch=v8plus" ngx_sparc64="-xarch=v9" - ngx_amd64="-amd64" + ngx_amd64="-xarch=amd64" fi case "$NGX_MACHINE" in 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.29" +#define NGINX_VERSION "0.5.30" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -1059,7 +1059,27 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - static uint32_t *map[] = { uri, args, html, refresh }; + /* " ", %00-%1F */ + + static uint32_t memcached[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000001, /* 0000 0000 0000 0000 0000 0000 0000 0001 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + }; + + static uint32_t *map[] = { uri, args, html, refresh, memcached }; escape = map[type]; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -150,12 +150,13 @@ size_t ngx_utf_length(u_char *p, size_t u_char *ngx_utf_cpystrn(u_char *dst, u_char *src, size_t n); -#define NGX_ESCAPE_URI 0 -#define NGX_ESCAPE_ARGS 1 -#define NGX_ESCAPE_HTML 2 -#define NGX_ESCAPE_REFRESH 3 +#define NGX_ESCAPE_URI 0 +#define NGX_ESCAPE_ARGS 1 +#define NGX_ESCAPE_HTML 2 +#define NGX_ESCAPE_REFRESH 3 +#define NGX_ESCAPE_MEMCACHED 4 -#define NGX_UNESCAPE_URI 1 +#define NGX_UNESCAPE_URI 1 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type); @@ -164,11 +165,11 @@ void ngx_unescape_uri(u_char **dst, u_ch void ngx_sort(void *base, size_t n, size_t size, int (*cmp)(const void *, const void *)); -#define ngx_qsort qsort +#define ngx_qsort qsort -#define ngx_value_helper(n) #n -#define ngx_value(n) ngx_value_helper(n) +#define ngx_value_helper(n) #n +#define ngx_value(n) ngx_value_helper(n) #endif /* _NGX_STRING_H_INCLUDED_ */ diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -13,50 +13,56 @@ #include -#define NGX_PEER_KEEPALIVE 1 -#define NGX_PEER_NEXT 2 -#define NGX_PEER_FAILED 4 +#define NGX_PEER_KEEPALIVE 1 +#define NGX_PEER_NEXT 2 +#define NGX_PEER_FAILED 4 typedef struct ngx_peer_connection_s ngx_peer_connection_t; typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc, void *data); -#if (NGX_SSL) -typedef void (*ngx_event_save_peer_pt)(ngx_peer_connection_t *pc, void *data); -#endif typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data, ngx_uint_t state); +#if (NGX_SSL) + +typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc, + void *data); +typedef void (*ngx_event_save_peer_session_pt)(ngx_peer_connection_t *pc, + void *data); +#endif struct ngx_peer_connection_s { - ngx_connection_t *connection; + ngx_connection_t *connection; - struct sockaddr *sockaddr; - socklen_t socklen; - ngx_str_t *name; + struct sockaddr *sockaddr; + socklen_t socklen; + ngx_str_t *name; - ngx_uint_t tries; + ngx_uint_t tries; - ngx_event_get_peer_pt get; - ngx_event_free_peer_pt free; - void *data; + ngx_event_get_peer_pt get; + ngx_event_free_peer_pt free; + void *data; #if (NGX_SSL) - ngx_ssl_session_t *ssl_session; - ngx_event_save_peer_pt save_session; + ngx_event_set_peer_session_pt set_session; + ngx_event_save_peer_session_pt save_session; #endif #if (NGX_THREADS) - ngx_atomic_t *lock; + ngx_atomic_t *lock; #endif - int rcvbuf; + int rcvbuf; + + ngx_log_t *log; - ngx_log_t *log; + unsigned cached:1; - unsigned cached:1; - unsigned log_error:2; /* ngx_connection_log_error_e */ + /* ngx_connection_log_error_e */ + unsigned log_error:2; }; diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -226,6 +226,7 @@ static ngx_int_t ngx_http_memcached_create_request(ngx_http_request_t *r) { size_t len; + uintptr_t escape; ngx_buf_t *b; ngx_chain_t *cl; ngx_http_memcached_ctx_t *ctx; @@ -242,10 +243,9 @@ ngx_http_memcached_create_request(ngx_ht return NGX_ERROR; } - len = sizeof("get ") - 1 + vv->len + sizeof(CRLF) - 1; - if (vv->len) { - len += 1 + vv->len; - } + escape = 2 * ngx_escape_uri(NULL, vv->data, vv->len, NGX_ESCAPE_MEMCACHED); + + len = sizeof("get ") - 1 + vv->len + escape + sizeof(CRLF) - 1; b = ngx_create_temp_buf(r->pool, len); if (b == NULL) { @@ -268,7 +268,13 @@ ngx_http_memcached_create_request(ngx_ht ctx->key.data = b->last; - b->last = ngx_copy(b->last, vv->data, vv->len); + if (escape == 0) { + b->last = ngx_copy(b->last, vv->data, vv->len); + + } else { + b->last = (u_char *) ngx_escape_uri(b->last, vv->data, vv->len, + NGX_ESCAPE_MEMCACHED); + } ctx->key.len = b->last - ctx->key.data; diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c @@ -198,9 +198,6 @@ ngx_http_upstream_get_ip_hash_peer(ngx_p pc->sockaddr = peer->sockaddr; pc->socklen = peer->socklen; pc->name = &peer->name; -#if (NGX_SSL) - pc->ssl_session = peer->ssl_session; -#endif /* ngx_unlock_mutex(iphp->rrp.peers->mutex); */ 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.29'; +our $VERSION = '0.5.30'; 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,7 @@ static char *ngx_http_perl_set(ngx_conf_ static void ngx_http_perl_cleanup_perl(void *data); #endif +static ngx_int_t ngx_http_perl_init_worker(ngx_cycle_t *cycle); static void ngx_http_perl_exit(ngx_cycle_t *cycle); @@ -126,7 +127,7 @@ ngx_module_t ngx_http_perl_module = { NGX_HTTP_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ - NULL, /* init process */ + ngx_http_perl_init_worker, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ @@ -1004,6 +1005,27 @@ ngx_http_perl_set(ngx_conf_t *cf, ngx_co } +static ngx_int_t +ngx_http_perl_init_worker(ngx_cycle_t *cycle) +{ + ngx_http_perl_main_conf_t *pmcf; + + pmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_perl_module); + + { + + dTHXa(pmcf->perl); + PERL_SET_CONTEXT(pmcf->perl); + + /* set worker's $$ */ + + sv_setiv(GvSV(gv_fetchpv("$", TRUE, SVt_PV)), (I32) ngx_pid); + + } + + return NGX_OK; +} + static void ngx_http_perl_exit(ngx_cycle_t *cycle) { diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -657,7 +657,7 @@ ngx_http_upstream_ssl_init_connection(ng c->sendfile = 0; u->output.sendfile = 0; - if (ngx_ssl_set_session(c, u->peer.ssl_session) != NGX_OK) { + if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) { ngx_http_upstream_finalize_request(r, u, NGX_HTTP_INTERNAL_SERVER_ERROR); return; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -152,7 +152,10 @@ ngx_http_upstream_init_round_robin_peer( r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer; r->upstream->peer.tries = rrp->peers->number; #if (NGX_HTTP_SSL) - r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer; + r->upstream->peer.set_session = + ngx_http_upstream_set_round_robin_peer_session; + r->upstream->peer.save_session = + ngx_http_upstream_save_round_robin_peer_session; #endif return NGX_OK; @@ -328,9 +331,6 @@ ngx_http_upstream_get_round_robin_peer(n pc->sockaddr = peer->sockaddr; pc->socklen = peer->socklen; pc->name = &peer->name; -#if (NGX_SSL) - pc->ssl_session = peer->ssl_session; -#endif /* ngx_unlock_mutex(rrp->peers->mutex); */ @@ -408,29 +408,72 @@ ngx_http_upstream_free_round_robin_peer( #if (NGX_HTTP_SSL) -void -ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, void *data) +ngx_int_t +ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, + void *data) { ngx_http_upstream_rr_peer_data_t *rrp = data; + ngx_int_t rc; ngx_ssl_session_t *ssl_session; ngx_http_upstream_rr_peer_t *peer; + peer = &rrp->peers->peer[rrp->current]; + + /* TODO: threads only mutex */ + /* ngx_lock_mutex(rrp->peers->mutex); */ + + ssl_session = peer->ssl_session; + + rc = ngx_ssl_set_session(pc->connection, ssl_session); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "set session: %p:%d", + ssl_session, ssl_session ? ssl_session->references : 0); + + /* ngx_unlock_mutex(rrp->peers->mutex); */ + + return rc; +} + + +void +ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, + void *data) +{ + ngx_http_upstream_rr_peer_data_t *rrp = data; + + ngx_ssl_session_t *old_ssl_session, *ssl_session; + ngx_http_upstream_rr_peer_t *peer; + ssl_session = ngx_ssl_get_session(pc->connection); if (ssl_session == NULL) { return; } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "save session: %p:%d", ssl_session, ssl_session->references); + peer = &rrp->peers->peer[rrp->current]; + /* TODO: threads only mutex */ /* ngx_lock_mutex(rrp->peers->mutex); */ + + old_ssl_session = peer->ssl_session; peer->ssl_session = ssl_session; + /* ngx_unlock_mutex(rrp->peers->mutex); */ - if (pc->ssl_session) { + if (old_ssl_session) { + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, + "old session: %p:%d", + old_ssl_session, old_ssl_session->references); + /* TODO: may block */ - ngx_ssl_free_session(pc->ssl_session); + + ngx_ssl_free_session(old_ssl_session); } } diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h --- a/src/http/ngx_http_upstream_round_robin.h +++ b/src/http/ngx_http_upstream_round_robin.h @@ -30,7 +30,7 @@ typedef struct { ngx_uint_t down; /* unsigned down:1; */ #if (NGX_SSL) - ngx_ssl_session_t *ssl_session; + ngx_ssl_session_t *ssl_session; /* local to a process */ #endif } ngx_http_upstream_rr_peer_t; @@ -68,7 +68,10 @@ void ngx_http_upstream_free_round_robin_ void *data, ngx_uint_t state); #if (NGX_HTTP_SSL) -void ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, +ngx_int_t + ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc, + void *data); +void ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc, void *data); #endif diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -13,6 +13,8 @@ static ngx_int_t ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static void ngx_http_variable_request_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_header(ngx_http_request_t *r, @@ -39,6 +41,8 @@ static ngx_int_t ngx_http_variable_serve ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_scheme(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_is_args(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_request_filename(ngx_http_request_t *r, @@ -155,9 +159,14 @@ static ngx_http_variable_t ngx_http_cor offsetof(ngx_http_request_t, args), NGX_HTTP_VAR_NOCACHABLE, 0 }, - { ngx_string("args"), NULL, ngx_http_variable_request, + { ngx_string("args"), + ngx_http_variable_request_set, + ngx_http_variable_request, offsetof(ngx_http_request_t, args), - NGX_HTTP_VAR_NOCACHABLE, 0 }, + NGX_HTTP_VAR_CHANGABLE|NGX_HTTP_VAR_NOCACHABLE, 0 }, + + { ngx_string("is_args"), NULL, ngx_http_variable_is_args, + 0, NGX_HTTP_VAR_NOCACHABLE, 0 }, { ngx_string("request_filename"), NULL, ngx_http_variable_request_filename, 0, @@ -501,6 +510,19 @@ ngx_http_variable_request(ngx_http_reque static void +ngx_http_variable_request_set(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_str_t *s; + + s = (ngx_str_t *) ((char *) r + data); + + s->len = v->len; + s->data = v->data; +} + + +static void ngx_http_variable_request_set_size(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { @@ -860,6 +882,27 @@ ngx_http_variable_scheme(ngx_http_reques static ngx_int_t +ngx_http_variable_is_args(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + v->valid = 1; + v->no_cachable = 0; + v->not_found = 0; + + if (r->args.len == 0) { + v->len = 0; + v->data = NULL; + return NGX_OK; + } + + v->len = 1; + v->data = (u_char *) "?"; + + return NGX_OK; +} + + +static ngx_int_t ngx_http_variable_document_root(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -866,9 +866,11 @@ ngx_mail_proxy_handler(ngx_event_t *ev) c->log->action = "proxying"; - if ((s->connection->read->eof || s->proxy->upstream.connection->read->eof) - && s->buffer->pos == s->buffer->last - && s->proxy->buffer->pos == s->proxy->buffer->last) + if ((s->connection->read->eof && s->buffer->pos == s->buffer->last) + || (s->proxy->upstream.connection->read->eof + && s->proxy->buffer->pos == s->proxy->buffer->last) + || (s->connection->read->eof + && s->proxy->upstream.connection->read->eof)) { action = c->log->action; c->log->action = NULL;