changeset 320:1e9e2c5e7c14 NGINX_0_5_30

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.
author Igor Sysoev <http://sysoev.ru>
date Mon, 30 Jul 2007 00:00:00 +0400
parents 10d5a311cc5e
children 6762c33c7da8
files CHANGES CHANGES.ru auto/cc/sunc src/core/nginx.h src/core/ngx_string.c src/core/ngx_string.h src/event/ngx_event_connect.h src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_upstream_ip_hash_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream_round_robin.c src/http/ngx_http_upstream_round_robin.h src/http/ngx_http_variables.c src/mail/ngx_mail_proxy_module.c
diffstat 16 files changed, 244 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- 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.
--- 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.
--- 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
--- 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"
--- 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];
--- 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_ */
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -13,50 +13,56 @@
 #include <ngx_event.h>
 
 
-#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;
 };
 
 
--- 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;
 
--- 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); */
 
--- 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);
--- 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)
 {
--- 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;
--- 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);
     }
 }
 
--- 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
 
--- 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)
 {
--- 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;