changeset 380:3ce4580ae286 NGINX_0_6_34

nginx 0.6.34 *) Change: now the EAGAIN error returned by connect() is not considered as temporary error. *) Change: now the "gzip_vary" directive turned on issues a "Vary: Accept-Encoding" header line for uncompressed responses too. *) Feature: the "expires" directive supports daily time. *) Feature: the "Expect" request header line support. *) Feature: now the "rewrite" directive does a redirect automatically if the "https://" protocol is used. *) Bugfix: the "listen" directive parameters such as "backlog", "rcvbuf", etc. were not set, if a default server was not the first one. *) Bugfix: the "log_not_found" directive did not work for index files tests. *) Bugfix: now if FastCGI server sends a "Location" header line without status line, then nginx uses 302 status code. Thanks to Maxim Dounin. *) Bugfix: the ngx_http_flv_module did not support several values in a query string. *) Bugfix: when a request to a directory was redirected with the slash added, nginx dropped a query string from the original request.
author Igor Sysoev <http://sysoev.ru>
date Thu, 27 Nov 2008 00:00:00 +0300
parents 522189e0ef36
children 0d28fd57288c
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_times.c src/core/ngx_times.h src/event/ngx_event_connect.c src/http/modules/ngx_http_charset_filter_module.c src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_gzip_filter_module.c src/http/modules/ngx_http_gzip_static_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_index_module.c src/http/modules/ngx_http_proxy_module.c src/http/modules/ngx_http_rewrite_module.c src/http/modules/ngx_http_static_module.c src/http/modules/perl/nginx.pm src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_header_filter_module.c src/http/ngx_http_request.c src/http/ngx_http_request.h src/http/ngx_http_upstream.c
diffstat 23 files changed, 290 insertions(+), 63 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,37 @@
 
+Changes with nginx 0.6.34                                        27 Nov 2008
+
+    *) Change: now the EAGAIN error returned by connect() is not considered 
+       as temporary error.
+
+    *) Change: now the "gzip_vary" directive turned on issues a 
+       "Vary: Accept-Encoding" header line for uncompressed responses too.
+
+    *) Feature: the "expires" directive supports daily time.
+
+    *) Feature: the "Expect" request header line support.
+
+    *) Feature: now the "rewrite" directive does a redirect automatically 
+       if the "https://" protocol is used.
+
+    *) Bugfix: the "listen" directive parameters such as "backlog", 
+       "rcvbuf", etc. were not set, if a default server was not the first 
+       one.
+
+    *) Bugfix: the "log_not_found" directive did not work for index files 
+       tests.
+
+    *) Bugfix: now if FastCGI server sends a "Location" header line without 
+       status line, then nginx uses 302 status code.
+       Thanks to Maxim Dounin.
+
+    *) Bugfix: the ngx_http_flv_module did not support several values in a 
+       query string.
+
+    *) Bugfix: when a request to a directory was redirected with the slash 
+       added, nginx dropped a query string from the original request.
+
+
 Changes with nginx 0.6.33                                        20 Nov 2008
 
     *) Feature: now nginx returns the 405 status code for POST method 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,38 @@
 
+Изменения в nginx 0.6.34                                          27.11.2008
+
+    *) Изменение: теперь ошибка EAGAIN при вызове connect() не считается 
+       временной.
+
+    *) Изменение: теперь директива "gzip_vary on" выдаёт строку 
+       "Vary: Accept-Encoding" в заголовке ответа и для несжатых ответов.
+
+    *) Добавление: директива expires поддерживает суточное время.
+
+    *) Добавление: поддержка строки "Expect" в заголовке запроса.
+
+    *) Добавление: теперь при использовании протокола "https://" в 
+       директиве rewrite автоматически делается редирект.
+
+    *) Исправление: параметры директивы listen, такие как backlog, rcvbuf и 
+       прочие, не устанавливались, если сервером по умолчанию был не первый 
+       сервер.
+
+    *) Исправление: директива log_not_found не работала при поиске 
+       индексных файлов.
+
+    *) Исправление: теперь, если FastCGI-сервер присылает строку "Location" 
+       в заголовке ответа без строки статуса, то nginx использует код 
+       статуса 302.
+       Спасибо Максиму Дунину.
+
+    *) Исправление: модуль ngx_http_flv_module не поддерживал несколько 
+       значений в аргументах запроса.
+
+    *) Исправление: при редиректе запроса к каталогу с добавлением слэша 
+       nginx не добавлял аргументы из оригинального запроса.
+
+
 Изменения в nginx 0.6.33                                          20.11.2008
 
     *) Добавление: теперь nginx возвращает код 405 для метода POST при 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.33"
+#define NGINX_VERSION      "0.6.34"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_times.c
+++ b/src/core/ngx_times.c
@@ -291,3 +291,42 @@ ngx_gmtime(time_t t, ngx_tm_t *tp)
     tp->ngx_tm_year = (ngx_tm_year_t) year;
     tp->ngx_tm_wday = (ngx_tm_wday_t) wday;
 }
+
+
+time_t
+ngx_next_time(time_t when)
+{
+    time_t     now, next;
+    struct tm  tm;
+
+    now = ngx_time();
+
+    ngx_libc_localtime(now, &tm);
+
+    tm.tm_hour = (int) (when / 3600);
+    when %= 3600;
+    tm.tm_min = (int) (when / 60);
+    tm.tm_sec = (int) (when % 60);
+
+    next = mktime(&tm);
+
+    if (next == -1) {
+        return -1;
+    }
+
+    if (next - now > 0) {
+        return next;
+    }
+
+    tm.tm_mday++;
+
+    /* mktime() should normalize a date (Jan 32, etc) */
+
+    next = mktime(&tm);
+
+    if (next != -1) {
+        return next;
+    }
+
+    return -1;
+}
--- a/src/core/ngx_times.h
+++ b/src/core/ngx_times.h
@@ -25,6 +25,9 @@ u_char *ngx_http_time(u_char *buf, time_
 u_char *ngx_http_cookie_time(u_char *buf, time_t t);
 void ngx_gmtime(time_t t, ngx_tm_t *tp);
 
+time_t ngx_next_time(time_t when);
+#define ngx_next_time_n      "mktime()"
+
 
 extern volatile ngx_time_t  *ngx_cached_time;
 
--- a/src/event/ngx_event_connect.c
+++ b/src/event/ngx_event_connect.c
@@ -139,11 +139,22 @@ ngx_event_connect_peer(ngx_peer_connecti
     if (rc == -1) {
         err = ngx_socket_errno;
 
-        /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
 
-        if (err != NGX_EINPROGRESS && err != NGX_EAGAIN) {
-
+        if (err != NGX_EINPROGRESS
+#if (NGX_WIN32)
+            /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
+            && err != NGX_EAGAIN
+#endif
+            )
+        {
             if (err == NGX_ECONNREFUSED
+#if (NGX_LINUX)
+                /*
+                 * Linux returns EAGAIN instead of ECONNREFUSED
+                 * for unix sockets if listen queue is full
+                 */
+                || err == NGX_EAGAIN
+#endif
                 || err == NGX_ENETDOWN
                 || err == NGX_ENETUNREACH
                 || err == NGX_EHOSTDOWN
--- a/src/http/modules/ngx_http_charset_filter_module.c
+++ b/src/http/modules/ngx_http_charset_filter_module.c
@@ -204,6 +204,12 @@ ngx_http_charset_header_filter(ngx_http_
 
     if (r == r->main) {
 
+        if (r->headers_out.content_encoding
+            && r->headers_out.content_encoding->value.len)
+        {
+            return ngx_http_next_header_filter(r);
+        }
+
         if (r->headers_out.content_type.len == 0) {
             return ngx_http_next_header_filter(r);
         }
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -1189,6 +1189,13 @@ ngx_http_fastcgi_process_header(ngx_http
                     u->headers_in.status_n = status;
                     u->headers_in.status_line = *status_line;
 
+                } else if (u->headers_in.location) {
+                    u->headers_in.status_n = 302;
+                    u->headers_in.status_line.len =
+                                           sizeof("302 Moved Temporarily") - 1;
+                    u->headers_in.status_line.data =
+                                           (u_char *) "302 Moved Temporarily";
+
                 } else {
                     u->headers_in.status_n = 200;
                     u->headers_in.status_line.len = sizeof("200 OK") - 1;
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -60,7 +60,7 @@ ngx_module_t  ngx_http_flv_module = {
 static ngx_int_t
 ngx_http_flv_handler(ngx_http_request_t *r)
 {
-    u_char                    *p, *last;
+    u_char                    *p, *n, *last;
     off_t                      start, len;
     size_t                     root;
     ngx_int_t                  rc;
@@ -168,7 +168,13 @@ ngx_http_flv_handler(ngx_http_request_t 
         if (p) {
             p += 6;
 
-            start = ngx_atoof(p, r->args.len - (p - r->args.data));
+            for (n = p; n < r->args.data + r->args.len; n++) {
+                if (*n == '&') {
+                    break;
+                }
+            }
+
+            start = ngx_atoof(p, n - p);
 
             if (start == NGX_ERROR || start >= len) {
                 start = 0;
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -204,12 +204,11 @@ static ngx_http_output_body_filter_pt   
 static ngx_int_t
 ngx_http_gzip_header_filter(ngx_http_request_t *r)
 {
-    ngx_str_t                 *type;
-    ngx_uint_t                 i;
-    ngx_table_elt_t           *h;
-    ngx_http_gzip_ctx_t       *ctx;
-    ngx_http_gzip_conf_t      *conf;
-    ngx_http_core_loc_conf_t  *clcf;
+    ngx_str_t             *type;
+    ngx_uint_t             i;
+    ngx_table_elt_t       *h;
+    ngx_http_gzip_ctx_t   *ctx;
+    ngx_http_gzip_conf_t  *conf;
 
     conf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_filter_module);
 
@@ -264,21 +263,6 @@ found:
 
     r->headers_out.content_encoding = h;
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
-    if (clcf->gzip_vary) {
-        h = ngx_list_push(&r->headers_out.headers);
-        if (h == NULL) {
-            return NGX_ERROR;
-        }
-
-        h->hash = 1;
-        h->key.len = sizeof("Vary") - 1;
-        h->key.data = (u_char *) "Vary";
-        h->value.len = sizeof("Accept-Encoding") - 1;
-        h->value.data = (u_char *) "Accept-Encoding";
-    }
-
     ctx->length = r->headers_out.content_length_n;
 
     r->main_filter_need_in_memory = 1;
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -203,19 +203,6 @@ ngx_http_gzip_static_handler(ngx_http_re
 
     r->headers_out.content_encoding = h;
 
-    if (clcf->gzip_vary) {
-        h = ngx_list_push(&r->headers_out.headers);
-        if (h == NULL) {
-            return NGX_ERROR;
-        }
-
-        h->hash = 1;
-        h->key.len = sizeof("Vary") - 1;
-        h->key.data = (u_char *) "Vary";
-        h->value.len = sizeof("Accept-Encoding") - 1;
-        h->value.data = (u_char *) "Accept-Encoding";
-    }
-
     /* we need to allocate all before the header would be sent */
 
     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -36,6 +36,7 @@ struct ngx_http_header_val_s {
 #define NGX_HTTP_EXPIRES_MAX       2
 #define NGX_HTTP_EXPIRES_ACCESS    3
 #define NGX_HTTP_EXPIRES_MODIFIED  4
+#define NGX_HTTP_EXPIRES_DAILY     5
 
 
 typedef struct {
@@ -187,7 +188,7 @@ static ngx_int_t
 ngx_http_set_expires(ngx_http_request_t *r, ngx_http_headers_conf_t *conf)
 {
     size_t            len;
-    time_t            since;
+    time_t            now, expires_time, max_age;
     ngx_uint_t        i;
     ngx_table_elt_t  *expires, *cc, **ccp;
 
@@ -279,16 +280,24 @@ ngx_http_set_expires(ngx_http_request_t 
         return NGX_OK;
     }
 
+    now = ngx_time();
+
     if (conf->expires == NGX_HTTP_EXPIRES_ACCESS
         || r->headers_out.last_modified_time == -1)
     {
-        since = ngx_time();
+        expires_time = now + conf->expires_time;
+        max_age = conf->expires_time;
+
+    } else if (conf->expires == NGX_HTTP_EXPIRES_DAILY) {
+        expires_time = ngx_next_time(conf->expires_time);
+        max_age = expires_time - now;
 
     } else {
-        since = r->headers_out.last_modified_time;
+        expires_time = r->headers_out.last_modified_time + conf->expires_time;
+        max_age = expires_time - now;
     }
 
-    ngx_http_time(expires->value.data, since + conf->expires_time);
+    ngx_http_time(expires->value.data, expires_time);
 
     if (conf->expires_time < 0) {
         cc->value.len = sizeof("no-cache") - 1;
@@ -303,8 +312,7 @@ ngx_http_set_expires(ngx_http_request_t 
         return NGX_ERROR;
     }
 
-    cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T",
-                                since + conf->expires_time - ngx_time())
+    cc->value.len = ngx_sprintf(cc->value.data, "max-age=%T", max_age)
                     - cc->value.data;
 
     return NGX_OK;
@@ -514,7 +522,18 @@ ngx_http_headers_expires(ngx_conf_t *cf,
         n = 2;
     }
 
-    if (value[n].data[0] == '+') {
+    if (value[n].data[0] == '@') {
+        value[n].data++;
+        value[n].len--;
+        minus = 0;
+
+        if (hcf->expires == NGX_HTTP_EXPIRES_MODIFIED) {
+            return "daily time can not be used with \"modified\" parameter";
+        }
+
+        hcf->expires = NGX_HTTP_EXPIRES_DAILY;
+
+    } else if (value[n].data[0] == '+') {
         value[n].data++;
         value[n].len--;
         minus = 0;
@@ -534,6 +553,12 @@ ngx_http_headers_expires(ngx_conf_t *cf,
         return "invalid value";
     }
 
+    if (hcf->expires == NGX_HTTP_EXPIRES_DAILY
+        && hcf->expires_time > 24 * 60 * 60)
+    {
+        return "daily time value must be less than 24 hours";
+    }
+
     if (hcf->expires_time == NGX_PARSE_LARGE_TIME) {
         return "value must be less than 68 years";
     }
--- a/src/http/modules/ngx_http_index_module.c
+++ b/src/http/modules/ngx_http_index_module.c
@@ -27,8 +27,8 @@ typedef struct {
 
 static ngx_int_t ngx_http_index_test_dir(ngx_http_request_t *r,
     ngx_http_core_loc_conf_t *clcf, u_char *path, u_char *last);
-static ngx_int_t ngx_http_index_error(ngx_http_request_t *r, u_char *file,
-    ngx_err_t err);
+static ngx_int_t ngx_http_index_error(ngx_http_request_t *r,
+    ngx_http_core_loc_conf_t *clcf, u_char *file, ngx_err_t err);
 
 static ngx_int_t ngx_http_index_init(ngx_conf_t *cf);
 static void *ngx_http_index_create_loc_conf(ngx_conf_t *cf);
@@ -225,7 +225,7 @@ ngx_http_index_handler(ngx_http_request_
             }
 
             if (of.err == NGX_ENOTDIR || of.err == NGX_EACCES) {
-                return ngx_http_index_error(r, path.data, of.err);
+                return ngx_http_index_error(r, clcf, path.data, of.err);
             }
 
             if (!dir_tested) {
@@ -303,7 +303,7 @@ ngx_http_index_test_dir(ngx_http_request
 
             if (of.err == NGX_ENOENT) {
                 *last = c;
-                return ngx_http_index_error(r, dir.data, NGX_ENOENT);
+                return ngx_http_index_error(r, clcf, dir.data, NGX_ENOENT);
             }
 
             if (of.err == NGX_EACCES) {
@@ -340,7 +340,8 @@ ngx_http_index_test_dir(ngx_http_request
 
 
 static ngx_int_t
-ngx_http_index_error(ngx_http_request_t *r, u_char *file, ngx_err_t err)
+ngx_http_index_error(ngx_http_request_t *r, ngx_http_core_loc_conf_t  *clcf,
+    u_char *file, ngx_err_t err)
 {
     if (err == NGX_EACCES) {
         ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
@@ -349,8 +350,10 @@ ngx_http_index_error(ngx_http_request_t 
         return NGX_HTTP_FORBIDDEN;
     }
 
-    ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
-                  "\"%s\" is not found", file);
+    if (clcf->log_not_found) {
+        ngx_log_error(NGX_LOG_ERR, r->connection->log, err,
+                      "\"%s\" is not found", file);
+    }
 
     return NGX_HTTP_NOT_FOUND;
 }
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -424,6 +424,7 @@ static ngx_keyval_t  ngx_http_proxy_head
     { ngx_string("Host"), ngx_string("$proxy_host") },
     { ngx_string("Connection"), ngx_string("close") },
     { ngx_string("Keep-Alive"), ngx_string("") },
+    { ngx_string("Expect"), ngx_string("") },
     { ngx_null_string, ngx_null_string }
 };
 
--- a/src/http/modules/ngx_http_rewrite_module.c
+++ b/src/http/modules/ngx_http_rewrite_module.c
@@ -357,6 +357,12 @@ ngx_http_rewrite(ngx_conf_t *cf, ngx_com
         last = 1;
     }
 
+    if (ngx_strncmp(value[2].data, "https://", sizeof("https://") - 1) == 0) {
+        regex->status = NGX_HTTP_MOVED_TEMPORARILY;
+        regex->redirect = 1;
+        last = 1;
+    }
+
     if (cf->args->nelts == 4) {
         if (ngx_strcmp(value[3].data, "last") == 0) {
             last = 1;
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -48,7 +48,7 @@ static ngx_int_t
 ngx_http_static_handler(ngx_http_request_t *r)
 {
     u_char                    *last, *location;
-    size_t                     root;
+    size_t                     root, len;
     ngx_str_t                  path;
     ngx_int_t                  rc;
     ngx_uint_t                 level;
@@ -144,26 +144,39 @@ ngx_http_static_handler(ngx_http_request
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        if (!clcf->alias && clcf->root_lengths == NULL) {
+        len = r->uri.len + 1;
+
+        if (!clcf->alias && clcf->root_lengths == NULL && r->args.len == 0) {
             location = path.data + clcf->root.len;
 
+            *last = '/';
+
         } else {
-            location = ngx_palloc(r->pool, r->uri.len + 1);
+            if (r->args.len) {
+                len += r->args.len + 1;
+            }
+
+            location = ngx_palloc(r->pool, len);
             if (location == NULL) {
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
             last = ngx_copy(location, r->uri.data, r->uri.len);
-        }
+
+            *last = '/';
 
-        *last = '/';
+            if (r->args.len) {
+                *++last = '?';
+                ngx_memcpy(++last, r->args.data, r->args.len);
+            }
+        }
 
         /*
          * we do not need to set the r->headers_out.location->hash and
          * r->headers_out.location->key fields
          */
 
-        r->headers_out.location->value.len = r->uri.len + 1;
+        r->headers_out.location->value.len = len;
         r->headers_out.location->value.data = location;
 
         return NGX_HTTP_MOVED_PERMANENTLY;
--- 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.33';
+our $VERSION = '0.6.34';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -558,6 +558,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
                         in_addr[a].core_srv_conf = cscfp[s];
                         in_addr[a].default_server = 1;
+                        in_addr[a].listen_conf = &lscf[l].conf;
                     }
 
                     goto found;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -30,6 +30,7 @@ typedef struct {
 
 static ngx_int_t ngx_http_core_find_location(ngx_http_request_t *r,
     ngx_array_t *locations, ngx_uint_t regex_start, size_t len);
+static ngx_int_t ngx_http_core_send_continue(ngx_http_request_t *r);
 
 static ngx_int_t ngx_http_core_preconfiguration(ngx_conf_t *cf);
 static void *ngx_http_core_create_main_conf(ngx_conf_t *cf);
@@ -785,7 +786,7 @@ ngx_http_core_find_config_phase(ngx_http
 {
     u_char                    *p;
     size_t                     len;
-    ngx_int_t                  rc;
+    ngx_int_t                  rc, expect;
     ngx_http_core_loc_conf_t  *clcf;
     ngx_http_core_srv_conf_t  *cscf;
 
@@ -832,6 +833,14 @@ ngx_http_core_find_config_phase(ngx_http
         return NGX_OK;
     }
 
+    if (r->headers_in.expect) {
+        expect = ngx_http_core_send_continue(r);
+
+        if (expect != NGX_OK) {
+            ngx_http_finalize_request(r, expect);
+            return NGX_OK;
+        }
+    }
 
     if (rc == NGX_HTTP_LOCATION_AUTO_REDIRECT) {
         r->headers_out.location = ngx_list_push(&r->headers_out.headers);
@@ -1252,6 +1261,45 @@ ngx_http_core_find_location(ngx_http_req
 }
 
 
+static ngx_int_t
+ngx_http_core_send_continue(ngx_http_request_t *r)
+{
+    ngx_int_t   n;
+    ngx_str_t  *expect;
+
+    if (r->expect_tested) {
+        return NGX_OK;
+    }
+
+    r->expect_tested = 1;
+
+    expect = &r->headers_in.expect->value;
+
+    if (expect->len != sizeof("100-continue") - 1
+        || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
+                           sizeof("100-continue") - 1)
+           != 0)
+    {
+        return NGX_OK;
+    }
+
+    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "send 100 Continue");
+
+    n = r->connection->send(r->connection,
+                            (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
+                            sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
+
+    if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
+        return NGX_OK;
+    }
+
+    /* we assume that such small packet should be send successfully */
+
+    return NGX_HTTP_INTERNAL_SERVER_ERROR;
+}
+
+
 ngx_int_t
 ngx_http_set_content_type(ngx_http_request_t *r)
 {
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -347,6 +347,12 @@ ngx_http_header_filter(ngx_http_request_
         len += sizeof("Connection: closed" CRLF) - 1;
     }
 
+#if (NGX_HTTP_GZIP)
+    if (r->gzip && clcf->gzip_vary) {
+        len += sizeof("Vary: Accept-Encoding" CRLF) - 1;
+    }
+#endif
+
     part = &r->headers_out.headers.part;
     header = part->elts;
 
@@ -516,6 +522,13 @@ ngx_http_header_filter(ngx_http_request_
                              sizeof("Connection: close" CRLF) - 1);
     }
 
+#if (NGX_HTTP_GZIP)
+    if (r->gzip && clcf->gzip_vary) {
+        b->last = ngx_cpymem(b->last, "Vary: Accept-Encoding" CRLF,
+                             sizeof("Vary: Accept-Encoding" CRLF) - 1);
+    }
+#endif
+
     part = &r->headers_out.headers.part;
     header = part->elts;
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -109,6 +109,10 @@ ngx_http_header_t  ngx_http_headers_in[]
                  offsetof(ngx_http_headers_in_t, transfer_encoding),
                  ngx_http_process_header_line },
 
+    { ngx_string("Expect"),
+                 offsetof(ngx_http_headers_in_t, expect),
+                 ngx_http_process_unique_header_line },
+
 #if (NGX_HTTP_GZIP)
     { ngx_string("Accept-Encoding"),
                  offsetof(ngx_http_headers_in_t, accept_encoding),
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -171,6 +171,7 @@ typedef struct {
     ngx_table_elt_t                  *if_range;
 
     ngx_table_elt_t                  *transfer_encoding;
+    ngx_table_elt_t                  *expect;
 
 #if (NGX_HTTP_GZIP)
     ngx_table_elt_t                  *accept_encoding;
@@ -467,6 +468,7 @@ struct ngx_http_request_s {
     unsigned                          request_complete:1;
     unsigned                          request_output:1;
     unsigned                          header_sent:1;
+    unsigned                          expect_tested:1;
     unsigned                          done:1;
     unsigned                          utf8:1;
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -137,7 +137,8 @@ ngx_http_upstream_header_t  ngx_http_ups
                  ngx_http_upstream_copy_header_line, 0, 0 },
 
     { ngx_string("Location"),
-                 ngx_http_upstream_ignore_header_line, 0,
+                 ngx_http_upstream_process_header_line,
+                 offsetof(ngx_http_upstream_headers_in_t, location),
                  ngx_http_upstream_rewrite_location, 0, 0 },
 
     { ngx_string("Refresh"),