changeset 342:4276c2f1f434 NGINX_0_6_15

nginx 0.6.15 *) Feature: cygwin compatibility. Thanks to Vladimir Kutakov. *) Feature: the "merge_slashes" directive. *) Feature: the "gzip_vary" directive. *) Feature: the "server_tokens" directive. *) Bugfix: nginx did not unescape URI in the "include" SSI command. *) Bugfix: the segmentation fault was occurred on start or while reconfiguration if variable was used in the "charset" or "source_charset" directives. *) Bugfix: nginx returned the 400 response on requests like "GET http://www.domain.com HTTP/1.0". Thanks to James Oakley. *) Bugfix: if request with request body was redirected using the "error_page" directive, then nginx tried to read the request body again; bug appeared in 0.6.7. *) Bugfix: a segmentation fault occurred in worker process if no server_name was explicitly defined for server processing request; bug appeared in 0.6.7.
author Igor Sysoev <http://sysoev.ru>
date Mon, 22 Oct 2007 00:00:00 +0400
parents 183b4761fe5b
children 81bf600d64d5
files CHANGES CHANGES.ru auto/headers auto/sources src/core/nginx.h src/core/ngx_md5.h src/core/ngx_sha1.h src/core/ngx_string.c src/core/ngx_string.h src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_ssi_filter_module.c src/http/modules/perl/nginx.pm src/http/ngx_http.h src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h 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_body.c src/http/ngx_http_script.c src/http/ngx_http_special_response.c src/os/unix/ngx_posix_config.h src/os/unix/ngx_process_cycle.c
diffstat 24 files changed, 343 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,34 @@
 
+Changes with nginx 0.6.15                                        22 Oct 2007
+
+    *) Feature: cygwin compatibility.
+       Thanks to Vladimir Kutakov.
+
+    *) Feature: the "merge_slashes" directive.
+
+    *) Feature: the "gzip_vary" directive.
+
+    *) Feature: the "server_tokens" directive.
+
+    *) Bugfix: nginx did not unescape URI in the "include" SSI command.
+
+    *) Bugfix: the segmentation fault was occurred on start or while 
+       reconfiguration if variable was used in the "charset" or 
+       "source_charset" directives.
+
+    *) Bugfix: nginx returned the 400 response on requests like 
+       "GET http://www.domain.com HTTP/1.0".
+       Thanks to James Oakley.
+
+    *) Bugfix: if request with request body was redirected using the 
+       "error_page" directive, then nginx tried to read the request body 
+       again; bug appeared in 0.6.7.
+
+    *) Bugfix: a segmentation fault occurred in worker process if no 
+       server_name was explicitly defined for server processing request; 
+       bug appeared in 0.6.7.
+
+
 Changes with nginx 0.6.14                                        15 Oct 2007
 
     *) Change: now by default the "echo" SSI command uses entity encoding.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,34 @@
 
+Изменения в nginx 0.6.15                                          22.10.2007
+
+    *) Добавление: совместимость с cygwin.
+       Спасибо Владимиру Кутакову.
+
+    *) Добавление: директива merge_slashes.
+
+    *) Добавление: директива gzip_vary.
+
+    *) Добавление: директива server_tokens.
+
+    *) Исправление: nginx не раскодировал URI в команде SSI include.
+
+    *) Исправление: при использовании переменной в директивах charset или 
+       source_charset на старте или во время переконфигурации происходил 
+       segmentation fault,
+
+    *) Исправление: nginx возвращал ошибку 400 на запросы вида 
+       "GET http://www.domain.com HTTP/1.0".
+       Спасибо James Oakley.
+
+    *) Исправление: после перенаправления запроса с телом запроса с помощью 
+       директивы error_page nginx пытался снова прочитать тело запроса; 
+       ошибка появилась в 0.6.7.
+
+    *) Исправление: в рабочем процессе происходил segmentation fault, если 
+       у сервера, обрабатывающему запрос, не был явно определён 
+       server_name; ошибка появилась в 0.6.7.
+
+
 Изменения в nginx 0.6.14                                          15.10.2007
 
     *) Изменение: теперь по умолчанию команда SSI echo использует 
--- a/auto/headers
+++ b/auto/headers
@@ -6,3 +6,5 @@ ngx_include="unistd.h";    . auto/includ
 ngx_include="inttypes.h";  . auto/include
 ngx_include="limits.h";    . auto/include
 ngx_include="sys/filio.h"; . auto/include
+ngx_include="crypt.h";     . auto/include
+ngx_include="malloc.h";    . auto/include
--- a/auto/sources
+++ b/auto/sources
@@ -21,6 +21,8 @@ CORE_DEPS="src/core/nginx.h \
            src/core/ngx_file.h \
            src/core/ngx_crc.h \
            src/core/ngx_crc32.h \
+           src/core/ngx_md5.h \
+           src/core/ngx_sha1.h \
            src/core/ngx_rbtree.h \
            src/core/ngx_radix_tree.h \
            src/core/ngx_slab.h \
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.14"
+#define NGINX_VERSION      "0.6.15"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_md5.h
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_MD5_H_INCLUDED_
+#define _NGX_MD5_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_OPENSSL_MD5_H)
+#include <openssl/md5.h>
+#else
+#include <md5.h>
+#endif
+
+
+typedef MD5_CTX  ngx_md5_t;
+
+
+#if (NGX_OPENSSL_MD5)
+
+#define  ngx_md5_init    MD5_Init
+#define  ngx_md5_update  MD5_Update
+#define  ngx_md5_final   MD5_Final
+
+#else
+
+#define  ngx_md5_init    MD5Init
+#define  ngx_md5_update  MD5Update
+#define  ngx_md5_final   MD5Final
+
+#endif
+
+
+#endif /* _NGX_MD5_H_INCLUDED_ */
new file mode 100644
--- /dev/null
+++ b/src/core/ngx_sha1.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright (C) Igor Sysoev
+ */
+
+
+#ifndef _NGX_SHA1_H_INCLUDED_
+#define _NGX_SHA1_H_INCLUDED_
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+
+
+#if (NGX_HAVE_OPENSSL_SHA1_H)
+#include <openssl/sha.h>
+#else
+#include <sha.h>
+#endif
+
+
+typedef SHA_CTX  ngx_sha1_t;
+
+
+#define  ngx_sha1_init    SHA1_Init
+#define  ngx_sha1_update  SHA1_Update
+#define  ngx_sha1_final   SHA1_Final
+
+
+#endif /* _NGX_SHA1_H_INCLUDED_ */
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1243,7 +1243,9 @@ ngx_unescape_uri(u_char **dst, u_char **
 
         switch (state) {
         case sw_usual:
-            if (ch == '?' && type == NGX_UNESCAPE_URI) {
+            if (ch == '?'
+                && (type & (NGX_UNESCAPE_URI|NGX_UNESCAPE_REDIRECT)))
+            {
                 *d++ = ch;
                 goto done;
             }
@@ -1286,7 +1288,7 @@ ngx_unescape_uri(u_char **dst, u_char **
             if (ch >= '0' && ch <= '9') {
                 ch = (u_char) ((decoded << 4) + ch - '0');
 
-                if (type == NGX_UNESCAPE_URI) {
+                if (type & NGX_UNESCAPE_REDIRECT) {
                     if (ch > '%' && ch < 0x7f) {
                         *d++ = ch;
                         break;
@@ -1306,7 +1308,17 @@ ngx_unescape_uri(u_char **dst, u_char **
             if (c >= 'a' && c <= 'f') {
                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
 
-                if (type == NGX_UNESCAPE_URI) {
+                if (type & NGX_UNESCAPE_URI) {
+                    if (ch == '?') {
+                        *d++ = ch;
+                        goto done;
+                    }
+
+                    *d++ = ch;
+                    break;
+                }
+
+                if (type & NGX_UNESCAPE_REDIRECT) {
                     if (ch == '?') {
                         *d++ = ch;
                         goto done;
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -155,14 +155,15 @@ 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_MEMCACHED  4
-#define NGX_ESCAPE_MAIL_AUTH  5
+#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_ESCAPE_MAIL_AUTH   5
 
-#define NGX_UNESCAPE_URI      1
+#define NGX_UNESCAPE_URI       1
+#define NGX_UNESCAPE_REDIRECT  2
 
 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size,
     ngx_uint_t type);
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -366,8 +366,8 @@ ngx_http_charset_header_filter(ngx_http_
 no_charset_map:
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "no \"charset_map\" between the charsets "
-                  "\"%V\" and \"%V\"", from, to);
+                  "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
+                  from, to);
 
     return ngx_http_next_header_filter(r);
 }
@@ -1462,6 +1462,12 @@ ngx_http_charset_merge_loc_conf(ngx_conf
         return NGX_CONF_OK;
     }
 
+    if (conf->source_charset >= NGX_HTTP_CHARSET_VAR
+        || conf->charset >= NGX_HTTP_CHARSET_VAR)
+    {
+        return NGX_CONF_OK;
+    }
+
     mcf = ngx_http_conf_get_module_main_conf(cf,
                                              ngx_http_charset_filter_module);
     recode = mcf->recodes.elts;
@@ -1519,9 +1525,8 @@ ngx_http_charset_postconfiguration(ngx_c
         }
 
         ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
-                      " no \"charset_map\" between the charsets "
-                      "\"%V\" and \"%V\"",
-                      &charset[c].name, &charset[recode[i].dst].name);
+                   "no \"charset_map\" between the charsets \"%V\" and \"%V\"",
+                   &charset[c].name, &charset[recode[i].dst].name);
         return NGX_ERROR;
 
     next:
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -14,6 +14,7 @@
 typedef struct {
     ngx_flag_t           enable;
     ngx_flag_t           no_buffer;
+    ngx_flag_t           vary;
 
     ngx_array_t         *types;     /* array of ngx_str_t */
 
@@ -192,6 +193,13 @@ static ngx_command_t  ngx_http_gzip_filt
       offsetof(ngx_http_gzip_conf_t, min_length),
       NULL },
 
+    { ngx_string("gzip_vary"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_gzip_conf_t, vary),
+      NULL },
+
       ngx_null_command
 };
 
@@ -261,6 +269,7 @@ ngx_http_gzip_header_filter(ngx_http_req
 {
     ngx_str_t             *type;
     ngx_uint_t             i;
+    ngx_table_elt_t       *header;
     ngx_http_gzip_ctx_t   *ctx;
     ngx_http_gzip_conf_t  *conf;
 
@@ -336,16 +345,31 @@ found:
 
     ctx->request = r;
 
-    r->headers_out.content_encoding = ngx_list_push(&r->headers_out.headers);
-    if (r->headers_out.content_encoding == NULL) {
+    header = ngx_list_push(&r->headers_out.headers);
+    if (header == NULL) {
         return NGX_ERROR;
     }
 
-    r->headers_out.content_encoding->hash = 1;
-    r->headers_out.content_encoding->key.len = sizeof("Content-Encoding") - 1;
-    r->headers_out.content_encoding->key.data = (u_char *) "Content-Encoding";
-    r->headers_out.content_encoding->value.len = sizeof("gzip") - 1;
-    r->headers_out.content_encoding->value.data = (u_char *) "gzip";
+    header->hash = 1;
+    header->key.len = sizeof("Content-Encoding") - 1;
+    header->key.data = (u_char *) "Content-Encoding";
+    header->value.len = sizeof("gzip") - 1;
+    header->value.data = (u_char *) "gzip";
+
+    r->headers_out.content_encoding = header;
+
+    if (conf->vary) {
+        header = ngx_list_push(&r->headers_out.headers);
+        if (header == NULL) {
+            return NGX_ERROR;
+        }
+
+        header->hash = 1;
+        header->key.len = sizeof("Vary") - 1;
+        header->key.data = (u_char *) "Vary";
+        header->value.len = sizeof("Accept-Encoding") - 1;
+        header->value.data = (u_char *) "Accept-Encoding";
+    }
 
     ctx->length = r->headers_out.content_length_n;
 
@@ -996,6 +1020,7 @@ ngx_http_gzip_create_conf(ngx_conf_t *cf
 
     conf->enable = NGX_CONF_UNSET;
     conf->no_buffer = NGX_CONF_UNSET;
+    conf->vary = NGX_CONF_UNSET;
 
     conf->http_version = NGX_CONF_UNSET_UINT;
 
@@ -1031,6 +1056,7 @@ ngx_http_gzip_merge_conf(ngx_conf_t *cf,
                               MAX_MEM_LEVEL - 1);
     ngx_conf_merge_value(conf->min_length, prev->min_length, 20);
     ngx_conf_merge_value(conf->no_buffer, prev->no_buffer, 0);
+    ngx_conf_merge_value(conf->vary, prev->vary, 0);
 
     if (conf->types == NULL) {
         if (prev->types == NULL) {
--- a/src/http/modules/ngx_http_ssi_filter_module.c
+++ b/src/http/modules/ngx_http_ssi_filter_module.c
@@ -1858,6 +1858,8 @@ static ngx_int_t
 ngx_http_ssi_include(ngx_http_request_t *r, ngx_http_ssi_ctx_t *ctx,
     ngx_str_t **params)
 {
+    u_char                      *dst, *src;
+    size_t                       len;
     ngx_int_t                    rc, key;
     ngx_str_t                   *uri, *file, *wait, *set, *stub, args;
     ngx_buf_t                   *b;
@@ -1927,13 +1929,25 @@ ngx_http_ssi_include(ngx_http_request_t 
         return rc;
     }
 
+    dst = uri->data;
+    src = uri->data;
+
+    ngx_unescape_uri(&dst, &src, uri->len, NGX_UNESCAPE_URI);
+
+    len = (uri->data + uri->len) - src;
+    if (len) {
+        dst = ngx_copy(dst, src, len);
+    }
+
+    uri->len = dst - uri->data;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "ssi include: \"%V\"", uri);
+
     args.len = 0;
     args.data = NULL;
     flags = 0;
 
-    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                   "ssi include: \"%V\"", uri);
-
     if (ngx_http_parse_unsafe_uri(r, uri, &args, &flags) != NGX_OK) {
         return NGX_HTTP_SSI_ERROR;
     }
--- 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.6.14';
+our $VERSION = '0.6.15';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -64,7 +64,8 @@ int ngx_http_ssl_servername(ngx_ssl_conn
 #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_complex_uri(ngx_http_request_t *r,
+    ngx_uint_t merge_slashes);
 ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args, ngx_uint_t *flags);
 ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -185,6 +185,13 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_srv_conf_t, ignore_invalid_headers),
       NULL },
 
+    { ngx_string("merge_slashes"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_SRV_CONF_OFFSET,
+      offsetof(ngx_http_core_srv_conf_t, merge_slashes),
+      NULL },
+
     { ngx_string("location"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12,
       ngx_http_core_location,
@@ -427,6 +434,13 @@ static ngx_command_t  ngx_http_core_comm
       offsetof(ngx_http_core_loc_conf_t, recursive_error_pages),
       NULL },
 
+    { ngx_string("server_tokens"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_core_loc_conf_t, server_tokens),
+      NULL },
+
     { ngx_string("error_page"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
                         |NGX_CONF_2MORE,
@@ -681,7 +695,7 @@ ngx_http_core_find_config_phase(ngx_http
         && clcf->client_max_body_size < r->headers_in.content_length_n)
     {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                      "client intented to send too large body: %O bytes",
+                      "client intended to send too large body: %O bytes",
                       r->headers_in.content_length_n);
 
         ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
@@ -1598,7 +1612,7 @@ ngx_http_named_location(ngx_http_request
     }
 
     ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
-                  "could not find name location \"%V\"", name);
+                  "could not find named location \"%V\"", name);
 
     ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
     return NGX_DONE;
@@ -2233,6 +2247,7 @@ ngx_http_core_create_srv_conf(ngx_conf_t
     cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE;
     cscf->optimize_server_names = NGX_CONF_UNSET;
     cscf->ignore_invalid_headers = NGX_CONF_UNSET;
+    cscf->merge_slashes = NGX_CONF_UNSET;
 
     return cscf;
 }
@@ -2292,9 +2307,12 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
             return NGX_CONF_ERROR;
         }
 
+#if (NGX_PCRE)
+        sn->regex = NULL;
+#endif
+        sn->core_srv_conf = conf;
         sn->name.len = conf->server_name.len;
         sn->name.data = conf->server_name.data;
-        sn->core_srv_conf = conf;
     }
 
     ngx_conf_merge_size_value(conf->connection_pool_size,
@@ -2322,6 +2340,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->ignore_invalid_headers,
                               prev->ignore_invalid_headers, 1);
 
+    ngx_conf_merge_value(conf->merge_slashes, prev->merge_slashes, 1);
+
     return NGX_CONF_OK;
 }
 
@@ -2377,6 +2397,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     lcf->msie_refresh = NGX_CONF_UNSET;
     lcf->log_not_found = NGX_CONF_UNSET;
     lcf->recursive_error_pages = NGX_CONF_UNSET;
+    lcf->server_tokens = NGX_CONF_UNSET;
     lcf->types_hash_max_size = NGX_CONF_UNSET_UINT;
     lcf->types_hash_bucket_size = NGX_CONF_UNSET_UINT;
     lcf->open_file_cache = NGX_CONF_UNSET_PTR;
@@ -2565,6 +2586,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t 
     ngx_conf_merge_value(conf->log_not_found, prev->log_not_found, 1);
     ngx_conf_merge_value(conf->recursive_error_pages,
                               prev->recursive_error_pages, 0);
+    ngx_conf_merge_value(conf->server_tokens, prev->server_tokens, 1);
 
     ngx_conf_merge_ptr_value(conf->open_file_cache,
                              prev->open_file_cache, NULL);
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -143,6 +143,7 @@ typedef struct {
 
     ngx_flag_t                 optimize_server_names;
     ngx_flag_t                 ignore_invalid_headers;
+    ngx_flag_t                 merge_slashes;
 } ngx_http_core_srv_conf_t;
 
 
@@ -185,7 +186,6 @@ typedef struct {
 #if (NGX_PCRE)
     ngx_uint_t                 nregex;
     ngx_http_server_name_t    *regex;
-
 #endif
 
     /* the default server configuration for this address:port */
@@ -285,6 +285,7 @@ struct ngx_http_core_loc_conf_s {
     ngx_flag_t    msie_refresh;            /* msie_refresh */
     ngx_flag_t    log_not_found;           /* log_not_found */
     ngx_flag_t    recursive_error_pages;   /* recursive_error_pages */
+    ngx_flag_t    server_tokens;           /* server_tokens */
 
     ngx_array_t  *error_pages;             /* error_page */
 
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -45,7 +45,8 @@ ngx_module_t  ngx_http_header_filter_mod
 };
 
 
-static char ngx_http_server_string[] = "Server: " NGINX_VER CRLF;
+static char ngx_http_server_string[] = "Server: nginx" CRLF;
+static char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF;
 
 
 static ngx_str_t ngx_http_status_lines[] = {
@@ -237,8 +238,11 @@ ngx_http_header_filter(ngx_http_request_
         len += ngx_http_status_lines[status].len;
     }
 
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
     if (r->headers_out.server == NULL) {
-        len += sizeof(ngx_http_server_string) - 1;
+        len += clcf->server_tokens ? sizeof(ngx_http_server_full_string) - 1:
+                                     sizeof(ngx_http_server_string) - 1;
     }
 
     if (r->headers_out.date == NULL) {
@@ -268,8 +272,6 @@ ngx_http_header_filter(ngx_http_request_
         len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1;
     }
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     if (r->headers_out.location
         && r->headers_out.location->value.len
         && r->headers_out.location->value.data[0] == '/')
@@ -365,8 +367,16 @@ ngx_http_header_filter(ngx_http_request_
     *b->last++ = CR; *b->last++ = LF;
 
     if (r->headers_out.server == NULL) {
-        b->last = ngx_cpymem(b->last, ngx_http_server_string,
-                             sizeof(ngx_http_server_string) - 1);
+        if (clcf->server_tokens) {
+            p = (u_char *) ngx_http_server_full_string;
+            len = sizeof(ngx_http_server_full_string) - 1;
+
+        } else {
+            p = (u_char *) ngx_http_server_string;
+            len = sizeof(ngx_http_server_string) - 1;
+        }
+
+        b->last = ngx_cpymem(b->last, p, len);
     }
 
     if (r->headers_out.date == NULL) {
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -335,18 +335,26 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
+            r->host_end = p;
+
             switch (ch) {
             case ':':
-                r->host_end = p;
                 state = sw_port;
                 break;
             case '/':
-                r->host_end = p;
                 r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
+            case ' ':
+                /*
+                 * use single "/" from request line to preserve pointers,
+                 * if request line will be copied to large client buffer
+                 */
+                r->uri_start = r->schema_end + 1;
+                r->uri_end = r->schema_end + 2;
+                state = sw_http_09;
+                break;
             default:
-                r->host_end = p;
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
@@ -362,6 +370,16 @@ ngx_http_parse_request_line(ngx_http_req
                 r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
+            case ' ':
+                r->port_end = p;
+                /*
+                 * use single "/" from request line to preserve pointers,
+                 * if request line will be copied to large client buffer
+                 */
+                r->uri_start = r->schema_end + 1;
+                r->uri_end = r->schema_end + 2;
+                state = sw_http_09;
+                break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
@@ -890,7 +908,7 @@ header_done:
 
 
 ngx_int_t
-ngx_http_parse_complex_uri(ngx_http_request_t *r)
+ngx_http_parse_complex_uri(ngx_http_request_t *r, ngx_uint_t merge_slashes)
 {
     u_char  c, ch, decoded, *p, *u;
     enum {
@@ -998,8 +1016,12 @@ ngx_http_parse_complex_uri(ngx_http_requ
             switch(ch) {
 #if (NGX_WIN32)
             case '\\':
+                break;
 #endif
             case '/':
+                if (merge_slashes) {
+                    *u++ = ch;
+                }
                 break;
             case '.':
                 state = sw_dot;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -602,10 +602,11 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 static void
 ngx_http_process_request_line(ngx_event_t *rev)
 {
-    ssize_t              n;
-    ngx_int_t            rc, rv;
-    ngx_connection_t    *c;
-    ngx_http_request_t  *r;
+    ssize_t                    n;
+    ngx_int_t                  rc, rv;
+    ngx_connection_t          *c;
+    ngx_http_request_t        *r;
+    ngx_http_core_srv_conf_t  *cscf;
 
     c = rev->data;
     r = c->data;
@@ -657,7 +658,9 @@ ngx_http_process_request_line(ngx_event_
                     return;
                 }
 
-                rc = ngx_http_parse_complex_uri(r);
+                cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+                rc = ngx_http_parse_complex_uri(r, cscf->merge_slashes);
 
                 if (rc == NGX_HTTP_PARSE_INVALID_REQUEST) {
                     ngx_log_error(NGX_LOG_INFO, c->log, 0,
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -442,7 +442,7 @@ ngx_http_discard_request_body(ngx_http_r
         ngx_del_timer(rev);
     }
 
-    if (r->headers_in.content_length_n <= 0) {
+    if (r->headers_in.content_length_n <= 0 || r->request_body) {
         return NGX_OK;
     }
 
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -750,7 +750,8 @@ ngx_http_script_regex_end_code(ngx_http_
         dst = e->buf.data;
         src = e->buf.data;
 
-        ngx_unescape_uri(&dst, &src, e->pos - e->buf.data, NGX_UNESCAPE_URI);
+        ngx_unescape_uri(&dst, &src, e->pos - e->buf.data,
+                         NGX_UNESCAPE_REDIRECT);
 
         if (src < e->pos) {
             dst = ngx_copy(dst, src, e->pos - src);
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -10,8 +10,15 @@
 #include <nginx.h>
 
 
+static u_char error_full_tail[] =
+"<hr><center>" NGINX_VER "</center>" CRLF
+"</body>" CRLF
+"</html>" CRLF
+;
+
+
 static u_char error_tail[] =
-"<hr><center>" NGINX_VER "</center>" CRLF
+"<hr><center>nginx</center>" CRLF
 "</body>" CRLF
 "</html>" CRLF
 ;
@@ -471,7 +478,8 @@ ngx_http_special_response_handler(ngx_ht
     if (!r->zero_body) {
         if (error_pages[err].len) {
             r->headers_out.content_length_n = error_pages[err].len
-                                              + sizeof(error_tail) - 1;
+                + (clcf->server_tokens ? sizeof(error_full_tail) - 1:
+                                         sizeof(error_tail) - 1);
 
             if (clcf->msie_padding
                 && r->headers_in.msie
@@ -568,8 +576,14 @@ ngx_http_special_response_handler(ngx_ht
         }
 
         b->memory = 1;
-        b->pos = error_tail;
-        b->last = error_tail + sizeof(error_tail) - 1;
+
+        if (clcf->server_tokens) {
+            b->pos = error_full_tail;
+            b->last = error_full_tail + sizeof(error_full_tail) - 1;
+        } else {
+            b->pos = error_tail;
+            b->last = error_tail + sizeof(error_tail) - 1;
+        }
 
         cl->next = ngx_alloc_chain_link(r->pool);
         if (cl->next == NULL) {
--- a/src/os/unix/ngx_posix_config.h
+++ b/src/os/unix/ngx_posix_config.h
@@ -19,6 +19,12 @@
 #endif
 
 
+#ifdef __CYGWIN__
+#define timezonevar             /* timezone is variable */
+#define NGX_BROKEN_SCM_RIGHTS   1
+#endif
+
+
 #include <sys/types.h>
 #include <sys/time.h>
 #if (NGX_HAVE_UNISTD_H)
@@ -64,6 +70,15 @@
 #include <limits.h>             /* IOV_MAX */
 #endif
 
+#if (NGX_HAVE_MALLOC_H)
+#include <malloc.h>             /* memalign() */
+#endif
+
+#if (NGX_HAVE_CRYPT_H)
+#include <crypt.h>
+#endif
+
+
 #ifndef IOV_MAX
 #define IOV_MAX   16
 #endif
--- a/src/os/unix/ngx_process_cycle.c
+++ b/src/os/unix/ngx_process_cycle.c
@@ -409,6 +409,12 @@ ngx_signal_worker_processes(ngx_cycle_t 
     ngx_err_t      err;
     ngx_channel_t  ch;
 
+#if (NGX_BROKEN_SCM_RIGHTS)
+
+    ch.command = 0;
+
+#else
+
     switch (signo) {
 
     case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
@@ -427,6 +433,8 @@ ngx_signal_worker_processes(ngx_cycle_t 
         ch.command = 0;
     }
 
+#endif
+
     ch.fd = -1;
 
 
@@ -1035,7 +1043,6 @@ static void
 ngx_channel_handler(ngx_event_t *ev)
 {
     ngx_int_t          n;
-    ngx_socket_t       fd;
     ngx_channel_t      ch;
     ngx_connection_t  *c;
 
@@ -1053,17 +1060,7 @@ ngx_channel_handler(ngx_event_t *ev)
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ev->log, 0, "channel: %i", n);
 
     if (n == NGX_ERROR) {
-
-        ngx_free_connection(c);
-
-        fd = c->fd;
-        c->fd = (ngx_socket_t) -1;
-
-        if (close(fd) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
-                          "close() channel failed");
-        }
-
+        ngx_close_connection(c);
         return;
     }