changeset 591:bc110f60c0de NGINX_0_8_41

nginx 0.8.41 *) Security: nginx/Windows worker might be terminated abnormally if a requested file name has invalid UTF-8 encoding. *) Change: now nginx allows to use spaces in a request line. *) Bugfix: the "proxy_redirect" directive changed incorrectly a backend "Refresh" response header line. Thanks to Andrey Andreew and Max Sogin. *) Bugfix: nginx did not support path without host name in "Destination" request header line.
author Igor Sysoev <http://sysoev.ru>
date Tue, 15 Jun 2010 00:00:00 +0400
parents dd4c3325a56f
children c570633043e7
files CHANGES CHANGES.ru auto/install src/core/nginx.h src/http/modules/ngx_http_dav_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_split_clients_module.c src/http/modules/ngx_http_uwsgi_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_header_filter_module.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_request.h
diffstat 15 files changed, 173 insertions(+), 101 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,19 @@
 
+Changes with nginx 0.8.41                                        15 Jun 2010
+
+    *) Security: nginx/Windows worker might be terminated abnormally if a 
+       requested file name has invalid UTF-8 encoding.
+
+    *) Change: now nginx allows to use spaces in a request line.
+
+    *) Bugfix: the "proxy_redirect" directive changed incorrectly a backend 
+       "Refresh" response header line.
+       Thanks to Andrey Andreew and Max Sogin.
+
+    *) Bugfix: nginx did not support path without host name in 
+       "Destination" request header line.
+
+
 Changes with nginx 0.8.40                                        07 Jun 2010
 
     *) Security: now nginx/Windows ignores default file stream name.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,20 @@
 
+Изменения в nginx 0.8.41                                          15.06.2010
+
+    *) Безопасность: рабочий процесс nginx/Windows мог завершаться аварийно 
+       при запросе файла с неверной кодировкой UTF-8.
+
+    *) Изменение: теперь nginx разрешает использовать пробелы в строке 
+       запроса.
+
+    *) Исправление: директива proxy_redirect неправильно изменяла строку 
+       "Refresh" в заголовке ответа бэкенда.
+       Спасибо Андрею Андрееву и Максиму Согину.
+
+    *) Исправление: nginx не поддерживал путь без имени хоста в строке 
+       "Destination" в заголовке запроса.
+
+
 Изменения в nginx 0.8.40                                          07.06.2010
 
     *) Безопасность: теперь nginx/Windows игнорирует имя потока файла по 
--- a/auto/install
+++ b/auto/install
@@ -105,6 +105,11 @@ install:	$NGX_OBJS${ngx_dirsep}nginx${ng
 		|| cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX'
 	cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default'
 
+	test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \
+		|| cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX'
+	cp conf/uwsgi_params \
+		'\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default'
+
 	test -f '\$(DESTDIR)$NGX_CONF_PATH' \
 		|| cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH'
 	cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default'
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8040
-#define NGINX_VERSION      "0.8.40"
+#define nginx_version         8041
+#define NGINX_VERSION      "0.8.41"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -535,6 +535,13 @@ ngx_http_dav_copy_move_handler(ngx_http_
         return NGX_HTTP_BAD_REQUEST;
     }
 
+    p = dest->value.data;
+    /* there is always '\0' even after empty header value */
+    if (p[0] == '/') {
+        last = p + dest->value.len;
+        goto destination_done;
+    }
+
     len = r->headers_in.server.len;
 
     if (len == 0) {
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -628,49 +628,51 @@ ngx_http_fastcgi_handler(ngx_http_reques
 static ngx_int_t
 ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf)
 {
-    ngx_url_t  u;
-
-    ngx_memzero(&u, sizeof(ngx_url_t));
-
-    if (ngx_http_script_run(r, &u.url, flcf->fastcgi_lengths->elts, 0,
+    ngx_url_t             url;
+    ngx_http_upstream_t  *u;
+
+    ngx_memzero(&url, sizeof(ngx_url_t));
+
+    if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0,
                             flcf->fastcgi_values->elts)
         == NULL)
     {
         return NGX_ERROR;
     }
 
-    u.no_resolve = 1;
-
-    if (ngx_parse_url(r->pool, &u) != NGX_OK) {
-         if (u.err) {
+    url.no_resolve = 1;
+
+    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+         if (url.err) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "%s in upstream \"%V\"", u.err, &u.url);
+                          "%s in upstream \"%V\"", url.err, &url.url);
         }
 
         return NGX_ERROR;
     }
 
-    if (u.no_port) {
+    if (url.no_port) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &u.url);
-        return NGX_ERROR;
-    }
-
-    r->upstream->resolved = ngx_pcalloc(r->pool,
-                                        sizeof(ngx_http_upstream_resolved_t));
-    if (r->upstream->resolved == NULL) {
+                      "no port in upstream \"%V\"", &url.url);
         return NGX_ERROR;
     }
 
-    if (u.addrs && u.addrs[0].sockaddr) {
-        r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
-        r->upstream->resolved->socklen = u.addrs[0].socklen;
-        r->upstream->resolved->naddrs = 1;
-        r->upstream->resolved->host = u.addrs[0].name;
+    u = r->upstream;
+
+    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+    if (u->resolved == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (url.addrs && url.addrs[0].sockaddr) {
+        u->resolved->sockaddr = url.addrs[0].sockaddr;
+        u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->naddrs = 1;
+        u->resolved->host = url.addrs[0].name;
 
     } else {
-        r->upstream->resolved->host = u.host;
-        r->upstream->resolved->port = u.port;
+        u->resolved->host = url.host;
+        u->resolved->port = url.port;
     }
 
     return NGX_OK;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -911,7 +911,7 @@ ngx_http_proxy_create_request(ngx_http_r
         loc_len = (r->valid_location && ctx->vars.uri.len) ?
                       plcf->location.len : 0;
 
-        if (r->quoted_uri || r->internal) {
+        if (r->quoted_uri || r->space_in_uri || r->internal) {
             escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len,
                                         r->uri.len - loc_len, NGX_ESCAPE_URI);
         }
@@ -1765,16 +1765,14 @@ ngx_http_proxy_rewrite_redirect_text(ngx
         return NGX_DECLINED;
     }
 
-    len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len;
+    len = pr->replacement.text.len + h->value.len - pr->redirect.len;
 
     data = ngx_pnalloc(r->pool, len);
     if (data == NULL) {
         return NGX_ERROR;
     }
 
-    p = data;
-
-    p = ngx_copy(p, h->value.data, prefix);
+    p = ngx_copy(data, h->value.data, prefix);
 
     if (pr->replacement.text.len) {
         p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len);
@@ -1812,7 +1810,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx
     e.ip = pr->replacement.vars.lengths;
     e.request = r;
 
-    len = prefix + h->value.len - pr->redirect.len;
+    len = h->value.len - pr->redirect.len;
 
     while (*(uintptr_t *) e.ip) {
         lcode = *(ngx_http_script_len_code_pt *) e.ip;
@@ -1824,9 +1822,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx
         return NGX_ERROR;
     }
 
-    p = data;
-
-    p = ngx_copy(p, h->value.data, prefix);
+    p = ngx_copy(data, h->value.data, prefix);
 
     e.ip = pr->replacement.vars.values;
     e.pos = p;
--- a/src/http/modules/ngx_http_split_clients_module.c
+++ b/src/http/modules/ngx_http_split_clients_module.c
@@ -163,6 +163,10 @@ ngx_conf_split_clients_block(ngx_conf_t 
 
     *cf = save;
 
+    if (rv != NGX_CONF_OK) {
+        return rv;
+    }
+
     sum = 0;
     last = 0;
     part = ctx->parts.elts;
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -495,49 +495,51 @@ ngx_http_uwsgi_handler(ngx_http_request_
 static ngx_int_t
 ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf)
 {
-    ngx_url_t  u;
+    ngx_url_t             url;
+    ngx_http_upstream_t  *u;
 
-    ngx_memzero(&u, sizeof(ngx_url_t));
+    ngx_memzero(&url, sizeof(ngx_url_t));
 
-    if (ngx_http_script_run(r, &u.url, uwcf->uwsgi_lengths->elts, 0,
+    if (ngx_http_script_run(r, &url.url, uwcf->uwsgi_lengths->elts, 0,
                             uwcf->uwsgi_values->elts)
         == NULL)
     {
         return NGX_ERROR;
     }
 
-    u.no_resolve = 1;
+    url.no_resolve = 1;
 
-    if (ngx_parse_url(r->pool, &u) != NGX_OK) {
-        if (u.err) {
+    if (ngx_parse_url(r->pool, &url) != NGX_OK) {
+        if (url.err) {
             ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                          "%s in upstream \"%V\"", u.err, &u.url);
+                          "%s in upstream \"%V\"", url.err, &url.url);
         }
 
         return NGX_ERROR;
     }
 
-    if (u.no_port) {
+    if (url.no_port) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "no port in upstream \"%V\"", &u.url);
+                      "no port in upstream \"%V\"", &url.url);
         return NGX_ERROR;
     }
 
-    r->upstream->resolved = ngx_pcalloc(r->pool,
-                                        sizeof(ngx_http_upstream_resolved_t));
-    if (r->upstream->resolved == NULL) {
+    u = r->upstream;
+
+    u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t));
+    if (u->resolved == NULL) {
         return NGX_ERROR;
     }
 
-    if (u.addrs && u.addrs[0].sockaddr) {
-        r->upstream->resolved->sockaddr = u.addrs[0].sockaddr;
-        r->upstream->resolved->socklen = u.addrs[0].socklen;
-        r->upstream->resolved->naddrs = 1;
-        r->upstream->resolved->host = u.addrs[0].name;
+    if (url.addrs && url.addrs[0].sockaddr) {
+        u->resolved->sockaddr = url.addrs[0].sockaddr;
+        u->resolved->socklen = url.addrs[0].socklen;
+        u->resolved->naddrs = 1;
+        u->resolved->host = url.addrs[0].name;
 
     } else {
-        r->upstream->resolved->host = u.host;
-        r->upstream->resolved->port = u.port;
+        u->resolved->host = url.host;
+        u->resolved->port = url.port;
     }
 
     return NGX_OK;
@@ -831,8 +833,6 @@ ngx_http_uwsgi_create_request(ngx_http_r
             body = body->next;
         }
 
-        b->flush = 1;
-
     } else {
         r->upstream->request_bufs = cl;
     }
@@ -1199,38 +1199,6 @@ ngx_http_uwsgi_process_header(ngx_http_r
             ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                            "http uwsgi header done");
 
-            /*
-             * if no "Server" and "Date" in header line,
-             * then add the special empty headers
-             */
-
-            if (r->upstream->headers_in.server == NULL) {
-                h = ngx_list_push(&r->upstream->headers_in.headers);
-                if (h == NULL) {
-                    return NGX_ERROR;
-                }
-
-                h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash(
-                                   ngx_hash ('s', 'e'), 'r'), 'v'), 'e'), 'r');
-
-                ngx_str_set(&h->key, "Server");
-                ngx_str_null(&h->value);
-                h->lowcase_key = (u_char *) "server";
-            }
-
-            if (r->upstream->headers_in.date == NULL) {
-                h = ngx_list_push(&r->upstream->headers_in.headers);
-                if (h == NULL) {
-                    return NGX_ERROR;
-                }
-
-                h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e');
-
-                ngx_str_set(&h->key, "Date");
-                ngx_str_null(&h->value);
-                h->lowcase_key = (u_char *) "date";
-            }
-
             return NGX_OK;
         }
 
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -14,6 +14,7 @@ our @EXPORT = qw(
 
     HTTP_OK
     HTTP_CREATED
+    HTTP_ACCEPTED
     HTTP_NO_CONTENT
     HTTP_PARTIAL_CONTENT
 
@@ -47,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.8.40';
+our $VERSION = '0.8.41';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
@@ -59,6 +60,7 @@ use constant DECLINED                   
 
 use constant HTTP_OK                        => 200;
 use constant HTTP_CREATED                   => 201;
+use constant HTTP_ACCEPTED                  => 202;
 use constant HTTP_NO_CONTENT                => 204;
 use constant HTTP_PARTIAL_CONTENT           => 206;
 
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -824,10 +824,6 @@ ngx_http_handler(ngx_http_request_t *r)
         r->phase_handler = cmcf->phase_engine.server_rewrite_index;
     }
 
-    if (r->unparsed_uri.len) {
-        r->valid_unparsed_uri = 1;
-    }
-
     r->valid_location = 1;
 #if (NGX_HTTP_GZIP)
     r->gzip_tested = 0;
@@ -3707,6 +3703,7 @@ static ngx_http_method_name_t  ngx_metho
    { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH },
    { (u_char *) "LOCK",      (uint32_t) ~NGX_HTTP_LOCK },
    { (u_char *) "UNLOCK",    (uint32_t) ~NGX_HTTP_UNLOCK },
+   { (u_char *) "PATCH",     (uint32_t) ~NGX_HTTP_PATCH },
    { NULL, 0 }
 };
 
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -53,7 +53,7 @@ static ngx_str_t ngx_http_status_lines[]
 
     ngx_string("200 OK"),
     ngx_string("201 Created"),
-    ngx_null_string,  /* "202 Accepted" */
+    ngx_string("202 Accepted"),
     ngx_null_string,  /* "203 Non-Authoritative Information" */
     ngx_string("204 No Content"),
     ngx_null_string,  /* "205 Reset Content" */
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -112,8 +112,10 @@ ngx_http_parse_request_line(ngx_http_req
         sw_schema_slash_slash,
         sw_host,
         sw_port,
+        sw_host_http_09,
         sw_after_slash_in_uri,
         sw_check_uri,
+        sw_check_uri_http_09,
         sw_uri,
         sw_http_09,
         sw_http_H,
@@ -208,6 +210,10 @@ ngx_http_parse_request_line(ngx_http_req
                         r->method = NGX_HTTP_MKCOL;
                     }
 
+                    if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
+                        r->method = NGX_HTTP_PATCH;
+                    }
+
                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
                         r->method = NGX_HTTP_TRACE;
                     }
@@ -353,7 +359,7 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
@@ -379,13 +385,35 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
+        /* space+ after "http://host[:port] " */
+        case sw_host_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+
         /* check "/.", "//", "%", and "\" (Win32) in URI */
         case sw_after_slash_in_uri:
 
@@ -397,7 +425,7 @@ ngx_http_parse_request_line(ngx_http_req
             switch (ch) {
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -462,7 +490,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -499,6 +527,30 @@ ngx_http_parse_request_line(ngx_http_req
             }
             break;
 
+        /* space+ after URI */
+        case sw_check_uri_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                r->space_in_uri = 1;
+                state = sw_check_uri;
+                break;
+            }
+            break;
+
+
         /* URI */
         case sw_uri:
 
@@ -545,7 +597,9 @@ ngx_http_parse_request_line(ngx_http_req
                 state = sw_http_H;
                 break;
             default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
+                r->space_in_uri = 1;
+                state = sw_uri;
+                break;
             }
             break;
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -756,6 +756,7 @@ ngx_http_process_request_line(ngx_event_
             r->unparsed_uri.len = r->uri_end - r->uri_start;
             r->unparsed_uri.data = r->uri_start;
 
+            r->valid_unparsed_uri = r->space_in_uri ? 0 : 1;
 
             r->method_name.len = r->method_end - r->request_start + 1;
             r->method_name.data = r->request_line.data;
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -37,7 +37,8 @@
 #define NGX_HTTP_PROPPATCH                 0x0800
 #define NGX_HTTP_LOCK                      0x1000
 #define NGX_HTTP_UNLOCK                    0x2000
-#define NGX_HTTP_TRACE                     0x4000
+#define NGX_HTTP_PATCH                     0x4000
+#define NGX_HTTP_TRACE                     0x8000
 
 #define NGX_HTTP_CONNECTION_CLOSE          1
 #define NGX_HTTP_CONNECTION_KEEP_ALIVE     2
@@ -64,6 +65,7 @@
 
 #define NGX_HTTP_OK                        200
 #define NGX_HTTP_CREATED                   201
+#define NGX_HTTP_ACCEPTED                  202
 #define NGX_HTTP_NO_CONTENT                204
 #define NGX_HTTP_PARTIAL_CONTENT           206
 
@@ -435,6 +437,9 @@ struct ngx_http_request_s {
     /* URI with "+" */
     unsigned                          plus_in_uri:1;
 
+    /* URI with " " */
+    unsigned                          space_in_uri:1;
+
     unsigned                          invalid_header:1;
 
     unsigned                          add_uri_to_alias:1;