changeset 262:e0b1d0a6c629 NGINX_0_5_1

nginx 0.5.1 *) Bugfix: the "post_action" directive might not run after a unsuccessful completion of a request. *) Workaround: for Eudora for Mac; bug appeared in 0.4.11. Thanks to Bron Gondwana. *) Bugfix: if the "upstream" name was used in the "fastcgi_pass", then the message "no port in upstream" was issued; bug appeared in 0.5.0. *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the same servers but different ports, then these directives uses the first described port; bug appeared in 0.5.0. *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the unix domain sockets, then these directives used first described socket; bug appeared in 0.5.0. *) Bugfix: ngx_http_auth_basic_module ignored the user if it was in the last line in the password file and there was no the carriage return, the line feed, or the ":" symbol after the password. *) Bugfix: the $upstream_response_time variable might be equal to "0.000", although response time was more than 1 millisecond.
author Igor Sysoev <http://sysoev.ru>
date Mon, 11 Dec 2006 00:00:00 +0300
parents e6ae240d5952
children 34f7e991e4f7
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_inet.c src/core/ngx_times.c src/http/modules/ngx_http_auth_basic_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_memcached_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_request.c src/http/ngx_http_upstream.c src/http/ngx_http_upstream.h src/http/ngx_http_upstream_round_robin.c src/imap/ngx_imap_handler.c
diffstat 15 files changed, 227 insertions(+), 87 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,31 @@
 
+Changes with nginx 0.5.1                                         11 Dec 2006
+
+    *) Bugfix: the "post_action" directive might not run after a 
+       unsuccessful completion of a request.
+
+    *) Workaround: for Eudora for Mac; bug appeared in 0.4.11.
+       Thanks to Bron Gondwana.
+
+    *) Bugfix: if the "upstream" name was used in the "fastcgi_pass", then 
+       the message "no port in upstream" was issued; bug appeared in 0.5.0.
+
+    *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the 
+       same servers but different ports, then these directives uses the 
+       first described port; bug appeared in 0.5.0.
+
+    *) Bugfix: if the "proxy_pass" and "fastcgi_pass" directives used the 
+       unix domain sockets, then these directives used first described 
+       socket; bug appeared in 0.5.0.
+
+    *) Bugfix: ngx_http_auth_basic_module ignored the user if it was in the 
+       last line in the password file and there was no the carriage return, 
+       the line feed, or the ":" symbol after the password.
+
+    *) Bugfix: the $upstream_response_time variable might be equal to 
+       "0.000", although response time was more than 1 millisecond.
+
+
 Changes with nginx 0.5.0                                         04 Dec 2006
 
     *) Change: the parameters in the "%name" form in the "log_format" 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,34 @@
 
+Изменения в nginx 0.5.1                                           11.12.2006
+
+    *) Исправление: директива post_action могла не работать после 
+       неудачного завершения запроса.
+
+    *) Изменение: обход ошибки в Eudora для Mac; ошибка появилась в 
+       0.4.11.
+       Спасибо Bron Gondwana.
+
+    *) Исправление: при указании в директиве fastcgi_pass имени описанного 
+       upstream'а выдавалось сообщение "no port in upstream"; ошибка 
+       появилась в 0.5.0.
+
+    *) Исправление: если в директивах proxy_pass и fastcgi_pass 
+       использовались одинаковых имена серверов, но с разными портами, то 
+       эти директивы использовали первый описанный порт; ошибка появилась в 
+       0.5.0.
+
+    *) Исправление: если в директивах proxy_pass и fastcgi_pass 
+       использовались unix domain сокеты, то эти директивы использовали 
+       первый описанный сокет; ошибка появилась в 0.5.0.
+
+    *) Исправление: ngx_http_auth_basic_module игнорировал пользователя, 
+       если он был указан в последней строке файла паролей и после пароля 
+       не было перевода строки, возврата каретки или символа ":".
+
+    *) Исправление: переменная $upstream_response_time могла быть равна 
+       "0.000", хотя время обработки было больше 1 миллисекунды.
+
+
 Изменения в nginx 0.5.0                                           04.12.2006
 
     *) Изменение: параметры в виде "%name" в директиве log_format больше не 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.5.0"
+#define NGINX_VERSION      "0.5.1"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_inet.c
+++ b/src/core/ngx_inet.c
@@ -287,6 +287,9 @@ ngx_parse_url(ngx_conf_t *cf, ngx_url_t 
         u->addrs[0].name.len = len + 5;
         u->addrs[0].name.data = u->url.data;
 
+        u->host.len = len;
+        u->host.data = p;
+
         u->host_header.len = sizeof("localhost") - 1;
         u->host_header.data = (u_char *) "localhost";
 
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -70,12 +70,6 @@ ngx_time_update(time_t sec, ngx_uint_t m
         return;
     }
 
-    if (slot == NGX_TIME_SLOTS) {
-        slot = 0;
-    } else {
-        slot++;
-    }
-
     if (sec == 0) {
         ngx_gettimeofday(&tv);
 
@@ -87,14 +81,22 @@ ngx_time_update(time_t sec, ngx_uint_t m
 
     tp = &cached_time[slot];
 
-    tp->msec = msec;
-
     if (tp->sec == sec) {
+        tp->msec = msec;
         ngx_unlock(&ngx_time_lock);
         return;
     }
 
+    if (slot == NGX_TIME_SLOTS) {
+        slot = 0;
+    } else {
+        slot++;
+    }
+
+    tp = &cached_time[slot];
+
     tp->sec = sec;
+    tp->msec = msec;
 
     ngx_gmtime(sec, &gmt);
 
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -154,6 +154,8 @@ ngx_http_auth_basic_handler(ngx_http_req
     offset = 0;
 
     for ( ;; ) {
+        i = left;
+
         n = ngx_read_file(&file, buf + left, NGX_HTTP_AUTH_BUF_SIZE - left,
                           offset);
 
@@ -228,6 +230,18 @@ ngx_http_auth_basic_handler(ngx_http_req
 
     ngx_http_auth_basic_close(&file);
 
+    if (state == sw_passwd) {
+        pwd.len = i - passwd;
+        pwd.data = ngx_palloc(r->pool, pwd.len + 1);
+        if (pwd.data == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        ngx_cpystrn(pwd.data, &buf[passwd], pwd.len + 1);
+
+        return ngx_http_auth_basic_crypt_handler(r, NULL, &pwd, &alcf->realm);
+    }
+
     return ngx_http_auth_basic_set_realm(r, &alcf->realm);
 }
 
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -2010,6 +2010,7 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
+    u.upstream = 1;
     u.no_resolve = 1;
 
     lcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0);
--- a/src/http/modules/ngx_http_memcached_module.c
+++ b/src/http/modules/ngx_http_memcached_module.c
@@ -583,6 +583,7 @@ ngx_http_memcached_pass(ngx_conf_t *cf, 
     ngx_memzero(&u, sizeof(ngx_url_t));
 
     u.url = value[1];
+    u.upstream = 1;
     u.no_resolve = 1;
     /* u.uri_part = 1;  may be used as namespace */
 
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2159,6 +2159,7 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
     u.url.len = url->len - add;
     u.url.data = url->data + add;
     u.default_portn = port;
+    u.upstream = 1;
     u.no_resolve = 1;
     u.uri_part = 1;
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -17,7 +17,7 @@ our @EXPORT = qw(
     HTTP_SERVER_ERROR
 );
 
-our $VERSION = '0.5.0';
+our $VERSION = '0.5.1';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2247,6 +2247,8 @@ ngx_http_post_action(ngx_http_request_t 
     r->header_only = 1;
     r->post_action = 1;
 
+    r->read_event_handler = ngx_http_block_read;
+
     ngx_http_internal_redirect(r, &clcf->post_action, NULL);
 
     return NGX_OK;
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -493,17 +493,16 @@ ngx_http_upstream_connect(ngx_http_reque
 {
     ngx_int_t          rc;
     ngx_time_t        *tp;
-    ngx_msec_int_t     ms;
     ngx_connection_t  *c;
 
     r->connection->log->action = "connecting to upstream";
 
     r->connection->single_connection = 0;
 
-    if (u->state && u->state->response_time) {
+    if (u->state && u->state->response_sec) {
         tp = ngx_timeofday();
-        ms = tp->sec * 1000 + tp->msec - u->state->response_time;
-        u->state->response_time = (ms >= 0) ? ms : 0;
+        u->state->response_sec = tp->sec - u->state->response_sec;
+        u->state->response_msec = tp->msec - u->state->response_msec;
     }
 
     u->state = ngx_array_push(&u->states);
@@ -516,7 +515,8 @@ ngx_http_upstream_connect(ngx_http_reque
     ngx_memzero(u->state, sizeof(ngx_http_upstream_state_t));
 
     tp = ngx_timeofday();
-    u->state->response_time = tp->sec * 1000 + tp->msec;
+    u->state->response_sec = tp->sec;
+    u->state->response_msec = tp->msec;
 
     rc = ngx_event_connect_peer(&u->peer);
 
@@ -2043,18 +2043,17 @@ static void
 ngx_http_upstream_finalize_request(ngx_http_request_t *r,
     ngx_http_upstream_t *u, ngx_int_t rc)
 {
-    ngx_time_t      *tp;
-    ngx_msec_int_t   ms;
+    ngx_time_t  *tp;
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "finalize http upstream request: %i", rc);
 
     *u->cleanup = NULL;
 
-    if (u->state->response_time) {
+    if (u->state->response_sec) {
         tp = ngx_timeofday();
-        ms = tp->sec * 1000 + tp->msec - u->state->response_time;
-        u->state->response_time = (ms >= 0) ? ms : 0;
+        u->state->response_sec = tp->sec - u->state->response_sec;
+        u->state->response_msec = tp->msec - u->state->response_msec;
     }
 
     u->finalize_request(r, rc);
@@ -2531,6 +2530,7 @@ ngx_http_upstream_response_time_variable
     u_char                     *p;
     size_t                      len;
     ngx_uint_t                  i;
+    ngx_msec_int_t              ms;
     ngx_http_upstream_t        *u;
     ngx_http_upstream_state_t  *state;
 
@@ -2562,9 +2562,9 @@ ngx_http_upstream_response_time_variable
             *p++ = '-';
 
         } else {
-            p = ngx_sprintf(p, "%d.%03d",
-                            state[i].response_time / 1000,
-                            state[i].response_time % 1000);
+            ms = state[i].response_sec * 1000 + state[i].response_msec;
+            ms = (ms >= 0) ? ms : 0;
+            p = ngx_sprintf(p, "%d.%03d", ms / 1000, ms % 1000);
         }
 
         if (++i == u->states.nelts) {
@@ -2843,7 +2843,8 @@ ngx_http_upstream_add(ngx_conf_t *cf, ng
     uscfp = umcf->upstreams.elts;
 
     for (i = 0; i < umcf->upstreams.nelts; i++) {
-        if (uscfp[i]->host.len != u->host.len
+        if (uscfp[i]->port != u->portn
+            || uscfp[i]->host.len != u->host.len
             || ngx_strncasecmp(uscfp[i]->host.data, u->host.data, u->host.len)
                != 0)
         {
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -35,7 +35,8 @@ typedef struct {
     ngx_uint_t                      bl_state;
 
     ngx_uint_t                      status;
-    ngx_msec_t                      response_time;
+    time_t                          response_sec;
+    ngx_uint_t                      response_msec;
 
     ngx_str_t                      *peer;
 } ngx_http_upstream_state_t;
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -69,13 +69,20 @@ ngx_http_upstream_init_round_robin(ngx_c
     if (ngx_inet_resolve_host(cf, &u) != NGX_OK) {
         if (u.err) {
             ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                          "%s in upstream host \"%V\" is not found in %s:%ui",
+                          "%s in upstream \"%V\" in %s:%ui",
                           u.err, &us->host, us->file_name.data, us->line);
         }
 
         return NGX_ERROR;
     }
 
+    if (us->port == 0) {
+        ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+                      "no port in upstream \"%V\" in %s:%ui",
+                      &us->host, us->file_name.data, us->line);
+        return NGX_ERROR;
+    }
+
     n = u.naddrs;
 
     peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_rr_peers_t)
--- a/src/imap/ngx_imap_handler.c
+++ b/src/imap/ngx_imap_handler.c
@@ -12,6 +12,8 @@
 
 static void ngx_imap_init_session(ngx_connection_t *c);
 static void ngx_imap_init_protocol(ngx_event_t *rev);
+static ngx_int_t ngx_imap_decode_auth_plain(ngx_imap_session_t *s,
+    ngx_str_t *encoded);
 static void ngx_imap_do_auth(ngx_imap_session_t *s);
 static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s);
 static u_char *ngx_imap_log_error(ngx_log_t *log, u_char *buf, size_t len);
@@ -660,7 +662,7 @@ ngx_pop3_auth_state(ngx_event_t *rev)
     u_char                    *text, *p, *last;
     ssize_t                    size;
     ngx_int_t                  rc;
-    ngx_str_t                 *arg, salt, plain;
+    ngx_str_t                 *arg, salt;
     ngx_connection_t          *c;
     ngx_imap_session_t        *s;
     ngx_imap_core_srv_conf_t  *cscf;
@@ -796,16 +798,17 @@ ngx_pop3_auth_state(ngx_event_t *rev)
                     break;
                 }
 
-                if (s->args.nelts != 1) {
-                    rc = NGX_IMAP_PARSE_INVALID_COMMAND;
-                    break;
-                }
-
                 arg = s->args.elts;
 
                 if (arg[0].len == 5) {
 
                     if (ngx_strncasecmp(arg[0].data, "LOGIN", 5) == 0) {
+
+                        if (s->args.nelts != 1) {
+                            rc = NGX_IMAP_PARSE_INVALID_COMMAND;
+                            break;
+                        }
+
                         s->imap_state = ngx_pop3_auth_login_username;
 
                         size = sizeof(pop3_username) - 1;
@@ -814,11 +817,41 @@ ngx_pop3_auth_state(ngx_event_t *rev)
                         break;
 
                     } else if (ngx_strncasecmp(arg[0].data, "PLAIN", 5) == 0) {
-                        s->imap_state = ngx_pop3_auth_plain;
+
+                        if (s->args.nelts == 1) {
+                            s->imap_state = ngx_pop3_auth_plain;
+
+                            size = sizeof(pop3_next) - 1;
+                            text = pop3_next;
+
+                            break;
+                        }
+
+                        if (s->args.nelts == 2) {
+
+                            /*
+                             * workaround for Eudora for Mac: it sends
+                             *    AUTH PLAIN [base64 encoded]
+                             */
 
-                        size = sizeof(pop3_next) - 1;
-                        text = pop3_next;
+                            rc = ngx_imap_decode_auth_plain(s, &arg[1]);
+
+                            if (rc == NGX_OK) {
+                                ngx_imap_do_auth(s);
+                                return;
+                            }
 
+                            if (rc == NGX_ERROR) {
+                                ngx_imap_session_internal_server_error(s);
+                                return;
+                            }
+
+                            /* rc == NGX_IMAP_PARSE_INVALID_COMMAND */
+
+                            break;
+                        }
+
+                        rc = NGX_IMAP_PARSE_INVALID_COMMAND;
                         break;
                     }
 
@@ -999,64 +1032,21 @@ ngx_pop3_auth_state(ngx_event_t *rev)
         case ngx_pop3_auth_plain:
             arg = s->args.elts;
 
-#if (NGX_DEBUG_IMAP_PASSWD)
-            ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0,
-                           "pop3 auth plain: \"%V\"", &arg[0]);
-#endif
+            rc = ngx_imap_decode_auth_plain(s, &arg[0]);
 
-            plain.data = ngx_palloc(c->pool,
-                                    ngx_base64_decoded_length(arg[0].len));
-            if (plain.data == NULL){
+            if (rc == NGX_OK) {
+                ngx_imap_do_auth(s);
+                return;
+            }
+
+            if (rc == NGX_ERROR) {
                 ngx_imap_session_internal_server_error(s);
                 return;
             }
 
-            if (ngx_decode_base64(&plain, &arg[0]) != NGX_OK) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent invalid base64 encoding "
-                              "in AUTH PLAIN command");
-                rc = NGX_IMAP_PARSE_INVALID_COMMAND;
-                break;
-            }
-
-            p = plain.data;
-            last = p + plain.len;
-
-            while (p < last && *p++) { /* void */ }
-
-            if (p == last) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent invalid login "
-                              "in AUTH PLAIN command");
-                rc = NGX_IMAP_PARSE_INVALID_COMMAND;
-                break;
-            }
-
-            s->login.data = p;
+            /* rc == NGX_IMAP_PARSE_INVALID_COMMAND */
 
-            while (p < last && *p) { p++; }
-
-            if (p == last) {
-                ngx_log_error(NGX_LOG_INFO, c->log, 0,
-                              "client sent invalid password "
-                              "in AUTH PLAIN command");
-                rc = NGX_IMAP_PARSE_INVALID_COMMAND;
-                break;
-            }
-
-            s->login.len = p++ - s->login.data;
-
-            s->passwd.len = last - p;
-            s->passwd.data = p;
-
-#if (NGX_DEBUG_IMAP_PASSWD)
-            ngx_log_debug2(NGX_LOG_DEBUG_IMAP, c->log, 0,
-                           "pop3 auth plain: \"%V\" \"%V\"",
-                           &s->login, &s->passwd);
-#endif
-
-            ngx_imap_do_auth(s);
-            return;
+            break;
 
         case ngx_pop3_auth_cram_md5:
             arg = s->args.elts;
@@ -1132,6 +1122,66 @@ ngx_pop3_auth_state(ngx_event_t *rev)
 }
 
 
+static ngx_int_t
+ngx_imap_decode_auth_plain(ngx_imap_session_t *s, ngx_str_t *encoded)
+{
+    u_char     *p, *last;
+    ngx_str_t   plain;
+
+#if (NGX_DEBUG_IMAP_PASSWD)
+    ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
+                   "pop3 auth plain: \"%V\"", encoded);
+#endif
+
+    plain.data = ngx_palloc(s->connection->pool,
+                            ngx_base64_decoded_length(encoded->len));
+    if (plain.data == NULL){
+        return NGX_ERROR;
+    }
+
+    if (ngx_decode_base64(&plain, encoded) != NGX_OK) {
+        ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
+                      "client sent invalid base64 encoding "
+                      "in AUTH PLAIN command");
+        return NGX_IMAP_PARSE_INVALID_COMMAND;
+    }
+
+    p = plain.data;
+    last = p + plain.len;
+
+    while (p < last && *p++) { /* void */ }
+
+    if (p == last) {
+        ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
+                      "client sent invalid login in AUTH PLAIN command");
+        return NGX_IMAP_PARSE_INVALID_COMMAND;
+    }
+
+    s->login.data = p;
+
+    while (p < last && *p) { p++; }
+
+    if (p == last) {
+        ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
+                      "client sent invalid password in AUTH PLAIN command");
+        return NGX_IMAP_PARSE_INVALID_COMMAND;
+    }
+
+    s->login.len = p++ - s->login.data;
+
+    s->passwd.len = last - p;
+    s->passwd.data = p;
+
+#if (NGX_DEBUG_IMAP_PASSWD)
+    ngx_log_debug2(NGX_LOG_DEBUG_IMAP, s->connection->log, 0,
+                   "pop3 auth plain: \"%V\" \"%V\"",
+                   &s->login, &s->passwd);
+#endif
+
+    return NGX_OK;
+}
+
+
 static void
 ngx_imap_do_auth(ngx_imap_session_t *s)
 {