Merge branch 'nginx' (nginx-1.13.0).

Change-Id: Iaacbbdad9eb9e5d76d482c63bf39729b7d0cbb2e
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index 818243e..0753e0d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -412,3 +412,4 @@
 d8b321a876d6254e9e98795e3b194ef053290354 release-1.11.11
 7f394e433f0003222aa6531931ecc0b24740d5e4 release-1.11.12
 3d0e8655f897959e48cc74e87670bb5492a58871 release-1.11.13
+3671096a45bce570a2afa20b9faf42c7fb0f7e66 release-1.13.0
diff --git a/BUILD b/BUILD
index 55656bf..8fdfed4 100644
--- a/BUILD
+++ b/BUILD
@@ -1468,5 +1468,5 @@
     preinst = "@nginx_pkgoss//:debian_preinst",
     prerm = "@nginx_pkgoss//:debian_prerm",
     section = "httpd",
-    version = "1.11.13",
+    version = "1.13.0",
 )
diff --git a/auto/os/darwin b/auto/os/darwin
index 1625fc2..cf472d1 100644
--- a/auto/os/darwin
+++ b/auto/os/darwin
@@ -17,6 +17,9 @@
 MAIN_LINK=
 MODULE_LINK="-shared -Wl,-undefined,dynamic_lookup"
 
+CC_AUX_FLAGS="$CC_AUX_FLAGS -D__APPLE_USE_RFC_3542"
+
+
 # kqueue
 
 echo " + kqueue found"
@@ -86,7 +89,6 @@
 
 # sendfile()
 
-CC_AUX_FLAGS="$CC_AUX_FLAGS"
 ngx_feature="sendfile()"
 ngx_feature_name="NGX_HAVE_SENDFILE"
 ngx_feature_run=yes
diff --git a/auto/unix b/auto/unix
index 5d9ff42..bd72fb6 100644
--- a/auto/unix
+++ b/auto/unix
@@ -394,6 +394,19 @@
 . $NGX_AUTO/feature
 
 
+# BSD way to set IPv4 datagram source address
+
+ngx_feature="IP_SENDSRCADDR"
+ngx_feature_name="NGX_HAVE_IP_SENDSRCADDR"
+ngx_feature_run=no
+ngx_feature_incs="#include <sys/socket.h>
+                  #include <netinet/in.h>"
+ngx_feature_path=
+ngx_feature_libs=
+ngx_feature_test="setsockopt(0, IPPROTO_IP, IP_SENDSRCADDR, NULL, 0)"
+. $NGX_AUTO/feature
+
+
 # Linux way to get IPv4 datagram destination address
 
 ngx_feature="IP_PKTINFO"
diff --git a/build.bzl b/build.bzl
index 42b6b32..ac57805 100644
--- a/build.bzl
+++ b/build.bzl
@@ -663,7 +663,7 @@
         name = "nginx_pkgoss",
         build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
                              _PKGOSS_BUILD_FILE_TAIL,
-        commit = "5ca52610ad80ed63446d4b833ffc4a7f9130d230",  # nginx-1.11.13
+        commit = "fccbb99243f8c57b6b37b30181c092df5d94baa4",  # nginx-1.13.0
         remote = "https://nginx.googlesource.com/nginx-pkgoss",
     )
 
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index ea39ab2..c06ffa4 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,84 @@
 <change_log title="nginx">
 
 
+<changes ver="1.13.0" date="2017-04-25">
+
+<change type="change">
+<para lang="ru">
+теперь SSL renegotiation допускается в соединениях к бэкендам.
+</para>
+<para lang="en">
+SSL renegotiation is now allowed on backend connections.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+параметры rcvbuf и sndbuf директив listen
+в почтовом прокси-сервере и модуле stream.
+</para>
+<para lang="en">
+the "rcvbuf" and "sndbuf" parameters of the "listen" directives
+of the mail proxy and stream modules.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директивы return и error_page теперь могут использоваться для возврата
+перенаправлений с кодом 308.<br/>
+Спасибо Simon Leblanc.
+</para>
+<para lang="en">
+the "return" and "error_page" directives can now be used to return 308
+redirections.<br/>
+Thanks to Simon Leblanc.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+параметр TLSv1.3 в директиве ssl_protocols.
+</para>
+<para lang="en">
+the "TLSv1.3" parameter of the "ssl_protocols" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+при логгировании сигналов теперь указывается PID отправившего сигнал процесса.
+</para>
+<para lang="en">
+when logging signals nginx now logs PID of the process which sent the signal.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в обработке ошибок выделения памяти.
+</para>
+<para lang="en">
+in memory allocation error handling.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если сервер в модуле stream слушал на wildcard-адресе,
+исходящий адрес ответного UDP-пакета
+мог отличаться от адреса назначения исходного пакета.
+</para>
+<para lang="en">
+if a server in the stream module listened on a wildcard address,
+the source address of a response UDP datagram could differ
+from the original datagram destination address.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.11.13" date="2017-04-04">
 
 <change type="feature">
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 12d96ee..790ecf8 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
 #define NGINX_NAME         "nginx"
 #endif
 
-#define nginx_version      1011013
-#define NGINX_VERSION      "1.11.13"
+#define nginx_version      1013000
+#define NGINX_VERSION      "1.13.0"
 #define NGINX_VER          NGINX_NAME "/" NGINX_VERSION
 
 #ifdef NGX_BUILD
diff --git a/src/core/ngx_palloc.h b/src/core/ngx_palloc.h
index d652829..376e012 100644
--- a/src/core/ngx_palloc.h
+++ b/src/core/ngx_palloc.h
@@ -72,9 +72,6 @@
 } ngx_pool_cleanup_file_t;
 
 
-void *ngx_alloc(size_t size, ngx_log_t *log);
-void *ngx_calloc(size_t size, ngx_log_t *log);
-
 ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
 void ngx_destroy_pool(ngx_pool_t *pool);
 void ngx_reset_pool(ngx_pool_t *pool);
diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c
index 7a73ef5..7526f60 100644
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1808,7 +1808,19 @@
                 len++;
 
             } else if (ch <= 0x1f) {
-                len += sizeof("\\u001F") - 2;
+
+                switch (ch) {
+                case '\n':
+                case '\r':
+                case '\t':
+                case '\b':
+                case '\f':
+                    len++;
+                    break;
+
+                default:
+                    len += sizeof("\\u001F") - 2;
+                }
             }
 
             size--;
@@ -1829,12 +1841,37 @@
             *dst++ = ch;
 
         } else {
-            *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
-            *dst++ = '0' + (ch >> 4);
+            *dst++ = '\\';
 
-            ch &= 0xf;
+            switch (ch) {
+            case '\n':
+                *dst++ = 'n';
+                break;
 
-            *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+            case '\r':
+                *dst++ = 'r';
+                break;
+
+            case '\t':
+                *dst++ = 't';
+                break;
+
+            case '\b':
+                *dst++ = 'b';
+                break;
+
+            case '\f':
+                *dst++ = 'f';
+                break;
+
+            default:
+                *dst++ = 'u'; *dst++ = '0'; *dst++ = '0';
+                *dst++ = '0' + (ch >> 4);
+
+                ch &= 0xf;
+
+                *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10);
+            }
         }
 
         size--;
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 1cc886d..2d3f0b7 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -323,6 +323,12 @@
         SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_2);
     }
 #endif
+#ifdef SSL_OP_NO_TLSv1_3
+    SSL_CTX_clear_options(ssl->ctx, SSL_OP_NO_TLSv1_3);
+    if (!(protocols & NGX_SSL_TLSv1_3)) {
+        SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_TLSv1_3);
+    }
+#endif
 
 #ifdef SSL_OP_NO_COMPRESSION
     SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
@@ -854,7 +860,9 @@
     BIO               *rbio, *wbio;
     ngx_connection_t  *c;
 
-    if (where & SSL_CB_HANDSHAKE_START) {
+    if ((where & SSL_CB_HANDSHAKE_START)
+        && SSL_is_server((ngx_ssl_conn_t *) ssl_conn))
+    {
         c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
 
         if (c->ssl->handshaked) {
@@ -1105,7 +1113,7 @@
      * maximum interoperability.
      */
 
-#ifdef SSL_CTRL_SET_CURVES_LIST
+#if (defined SSL_CTX_set1_curves_list || defined SSL_CTRL_SET_CURVES_LIST)
 
     /*
      * OpenSSL 1.0.2+ allows configuring a curve list instead of a single
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 87ffb66..4db5704 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -54,6 +54,11 @@
 #define ngx_ssl_conn_t          SSL
 
 
+#if (OPENSSL_VERSION_NUMBER < 0x10002000L)
+#define SSL_is_server(s)        (s)->server
+#endif
+
+
 struct ngx_ssl_s {
     SSL_CTX                    *ctx;
     ngx_log_t                  *log;
@@ -131,6 +136,7 @@
 #define NGX_SSL_TLSv1    0x0008
 #define NGX_SSL_TLSv1_1  0x0010
 #define NGX_SSL_TLSv1_2  0x0020
+#define NGX_SSL_TLSv1_3  0x0040
 
 
 #define NGX_SSL_BUFFER   1
diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c
index 1e7a0c2..4aa684f 100644
--- a/src/http/modules/ngx_http_auth_basic_module.c
+++ b/src/http/modules/ngx_http_auth_basic_module.c
@@ -361,6 +361,8 @@
 
     basic = ngx_pnalloc(r->pool, len);
     if (basic == NULL) {
+        r->headers_out.www_authenticate->hash = 0;
+        r->headers_out.www_authenticate = NULL;
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 895a52d..566b08b 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1080,6 +1080,7 @@
     } else {
         location = ngx_pnalloc(r->pool, r->uri.len);
         if (location == NULL) {
+            ngx_http_clear_location(r);
             return NGX_ERROR;
         }
 
diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c
index cc25320..7b72fae 100644
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -203,7 +203,7 @@
     }
 
     if (i == 0) {
-        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+        b = ngx_calloc_buf(r->pool);
         if (b == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
@@ -217,7 +217,7 @@
     }
 
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/modules/ngx_http_gzip_filter_module.c b/src/http/modules/ngx_http_gzip_filter_module.c
index f9652d0..287fd36 100644
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -644,7 +644,7 @@
     static u_char  gzheader[10] =
                                { 0x1f, 0x8b, Z_DEFLATED, 0, 0, 0, 0, 0, 0, 3 };
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_ERROR;
     }
diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c
index b9294dd..7652a9a 100644
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -238,7 +238,7 @@
 
     h = ngx_list_push(&r->headers_out.headers);
     if (h == NULL) {
-        return NGX_ERROR;
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
     h->hash = 1;
@@ -248,7 +248,7 @@
 
     /* we need to allocate all before the header would be sent */
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c
index 1a3db09..47ce779 100644
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -193,6 +193,7 @@
     case NGX_HTTP_SEE_OTHER:
     case NGX_HTTP_NOT_MODIFIED:
     case NGX_HTTP_TEMPORARY_REDIRECT:
+    case NGX_HTTP_PERMANENT_REDIRECT:
         safe_status = 1;
         break;
 
@@ -368,11 +369,6 @@
             return NGX_ERROR;
         }
 
-        ccp = ngx_array_push(&r->headers_out.cache_control);
-        if (ccp == NULL) {
-            return NGX_ERROR;
-        }
-
         cc = ngx_list_push(&r->headers_out.headers);
         if (cc == NULL) {
             return NGX_ERROR;
@@ -380,6 +376,12 @@
 
         cc->hash = 1;
         ngx_str_set(&cc->key, "Cache-Control");
+
+        ccp = ngx_array_push(&r->headers_out.cache_control);
+        if (ccp == NULL) {
+            return NGX_ERROR;
+        }
+
         *ccp = cc;
 
     } else {
@@ -567,11 +569,6 @@
         }
     }
 
-    ccp = ngx_array_push(&r->headers_out.cache_control);
-    if (ccp == NULL) {
-        return NGX_ERROR;
-    }
-
     cc = ngx_list_push(&r->headers_out.headers);
     if (cc == NULL) {
         return NGX_ERROR;
@@ -581,6 +578,11 @@
     ngx_str_set(&cc->key, "Cache-Control");
     cc->value = *value;
 
+    ccp = ngx_array_push(&r->headers_out.cache_control);
+    if (ccp == NULL) {
+        return NGX_ERROR;
+    }
+
     *ccp = cc;
 
     return NGX_OK;
diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c
index dbec5d8..6c03e8a 100644
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -581,7 +581,7 @@
     size_t      len;
     ngx_buf_t  *b;
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NULL;
     }
@@ -633,7 +633,7 @@
 {
     ngx_buf_t  *b;
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NULL;
     }
@@ -1067,7 +1067,7 @@
         return NULL;
     }
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         gdFree(out);
         return NULL;
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index f3c0fdd..08a68d0 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -636,7 +636,7 @@
     }
 
     if (mp4 == NULL) {
-        b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+        b = ngx_calloc_buf(r->pool);
         if (b == NULL) {
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 9ed5dd5..a1662c9 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -235,6 +235,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/http/modules/ngx_http_range_filter_module.c b/src/http/modules/ngx_http_range_filter_module.c
index 951a00d..8ffca82 100644
--- a/src/http/modules/ngx_http_range_filter_module.c
+++ b/src/http/modules/ngx_http_range_filter_module.c
@@ -425,6 +425,8 @@
     content_range->value.data = ngx_pnalloc(r->pool,
                                     sizeof("bytes -/") - 1 + 3 * NGX_OFF_T_LEN);
     if (content_range->value.data == NULL) {
+        content_range->hash = 0;
+        r->headers_out.content_range = NULL;
         return NGX_ERROR;
     }
 
@@ -594,6 +596,8 @@
     content_range->value.data = ngx_pnalloc(r->pool,
                                        sizeof("bytes */") - 1 + NGX_OFF_T_LEN);
     if (content_range->value.data == NULL) {
+        content_range->hash = 0;
+        r->headers_out.content_range = NULL;
         return NGX_ERROR;
     }
 
diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c
index bf9e022..57693c6 100644
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -55,6 +55,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index f2435a7..0e16c05 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -169,6 +169,7 @@
 
             location = ngx_pnalloc(r->pool, len);
             if (location == NULL) {
+                ngx_http_clear_location(r);
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
@@ -233,7 +234,7 @@
 
     /* we need to allocate all before the header would be sent */
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c
index de58c6f..6d3de59 100644
--- a/src/http/modules/ngx_http_sub_filter_module.c
+++ b/src/http/modules/ngx_http_sub_filter_module.c
@@ -248,8 +248,6 @@
                                  ctx->matches->nelts);
     }
 
-    ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
-
     ctx->saved.data = ngx_pnalloc(r->pool, ctx->tables->max_match_len - 1);
     if (ctx->saved.data == NULL) {
         return NGX_ERROR;
@@ -260,6 +258,8 @@
         return NGX_ERROR;
     }
 
+    ngx_http_set_ctx(r, ctx, ngx_http_sub_filter_module);
+
     ctx->offset = ctx->tables->min_match_len - 1;
     ctx->last_out = &ctx->out;
 
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index e093e91..19ae027 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -129,6 +129,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c
index 695f3bf..fae5895 100644
--- a/src/http/modules/ngx_http_xslt_filter_module.c
+++ b/src/http/modules/ngx_http_xslt_filter_module.c
@@ -584,7 +584,7 @@
         return NULL;
     }
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         ngx_free(buf);
         return NULL;
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index e3f7361..d4663dc 100644
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -24,6 +24,7 @@
     HTTP_SEE_OTHER
     HTTP_NOT_MODIFIED
     HTTP_TEMPORARY_REDIRECT
+    HTTP_PERMANENT_REDIRECT
 
     HTTP_BAD_REQUEST
     HTTP_UNAUTHORIZED
@@ -72,6 +73,7 @@
 use constant HTTP_SEE_OTHER                 => 303;
 use constant HTTP_NOT_MODIFIED              => 304;
 use constant HTTP_TEMPORARY_REDIRECT        => 307;
+use constant HTTP_PERMANENT_REDIRECT        => 308;
 
 use constant HTTP_BAD_REQUEST               => 400;
 use constant HTTP_UNAUTHORIZED              => 401;
diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs
index 865346a..9f847b3 100644
--- a/src/http/modules/perl/nginx.xs
+++ b/src/http/modules/perl/nginx.xs
@@ -510,10 +510,12 @@
     header->hash = 1;
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->key, key) != NGX_OK) {
+        header->hash = 0;
         XSRETURN_EMPTY;
     }
 
     if (ngx_http_perl_sv2str(aTHX_ r, &header->value, value) != NGX_OK) {
+        header->hash = 0;
         XSRETURN_EMPTY;
     }
 
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 734e1d8..c30c1d1 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1002,6 +1002,7 @@
             p = ngx_pnalloc(r->pool, len);
 
             if (p == NULL) {
+                ngx_http_clear_location(r);
                 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
                 return NGX_OK;
             }
@@ -1894,7 +1895,8 @@
     if (status == NGX_HTTP_MOVED_PERMANENTLY
         || status == NGX_HTTP_MOVED_TEMPORARILY
         || status == NGX_HTTP_SEE_OTHER
-        || status == NGX_HTTP_TEMPORARY_REDIRECT)
+        || status == NGX_HTTP_TEMPORARY_REDIRECT
+        || status == NGX_HTTP_PERMANENT_REDIRECT)
     {
         ngx_http_clear_location(r);
 
@@ -1926,7 +1928,7 @@
         return ngx_http_send_header(r);
     }
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index 8c75f95..b635b35 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1577,7 +1577,7 @@
 
     /* we need to allocate all before the header would be sent */
 
-    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c
index 7b63cff..7152e1b 100644
--- a/src/http/ngx_http_header_filter_module.c
+++ b/src/http/ngx_http_header_filter_module.c
@@ -75,8 +75,9 @@
     ngx_null_string,  /* "305 Use Proxy" */
     ngx_null_string,  /* "306 unused" */
     ngx_string("307 Temporary Redirect"),
+    ngx_string("308 Permanent Redirect"),
 
-#define NGX_HTTP_LAST_3XX  308
+#define NGX_HTTP_LAST_3XX  309
 #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
 
     ngx_string("400 Bad Request"),
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
index 7dbed9d..266340e 100644
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -83,6 +83,7 @@
 #define NGX_HTTP_SEE_OTHER                 303
 #define NGX_HTTP_NOT_MODIFIED              304
 #define NGX_HTTP_TEMPORARY_REDIRECT        307
+#define NGX_HTTP_PERMANENT_REDIRECT        308
 
 #define NGX_HTTP_BAD_REQUEST               400
 #define NGX_HTTP_UNAUTHORIZED              401
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index 2f66484..c4f092e 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -46,13 +46,6 @@
         return NGX_OK;
     }
 
-#if (NGX_HTTP_V2)
-    if (r->stream) {
-        rc = ngx_http_v2_read_request_body(r, post_handler);
-        goto done;
-    }
-#endif
-
     if (ngx_http_test_expect(r) != NGX_OK) {
         rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
         goto done;
@@ -85,6 +78,13 @@
         return NGX_OK;
     }
 
+#if (NGX_HTTP_V2)
+    if (r->stream) {
+        rc = ngx_http_v2_read_request_body(r);
+        goto done;
+    }
+#endif
+
     preread = r->header_in->last - r->header_in->pos;
 
     if (preread) {
@@ -805,7 +805,11 @@
 
     if (r->expect_tested
         || r->headers_in.expect == NULL
-        || r->http_version < NGX_HTTP_VERSION_11)
+        || r->http_version < NGX_HTTP_VERSION_11
+#if (NGX_HTTP_V2)
+        || r->stream != NULL
+#endif
+       )
     {
         return NGX_OK;
     }
diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c
index 85a4d4e..ec5143f 100644
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -89,6 +89,14 @@
 ;
 
 
+static char ngx_http_error_308_page[] =
+"<html>" CRLF
+"<head><title>308 Permanent Redirect</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>308 Permanent Redirect</h1></center>" CRLF
+;
+
+
 static char ngx_http_error_400_page[] =
 "<html>" CRLF
 "<head><title>400 Bad Request</title></head>" CRLF
@@ -336,8 +344,9 @@
     ngx_null_string,                     /* 305 */
     ngx_null_string,                     /* 306 */
     ngx_string(ngx_http_error_307_page),
+    ngx_string(ngx_http_error_308_page),
 
-#define NGX_HTTP_LAST_3XX  308
+#define NGX_HTTP_LAST_3XX  309
 #define NGX_HTTP_OFF_4XX   (NGX_HTTP_LAST_3XX - 301 + NGX_HTTP_OFF_3XX)
 
     ngx_string(ngx_http_error_400_page),
@@ -615,7 +624,8 @@
     if (overwrite != NGX_HTTP_MOVED_PERMANENTLY
         && overwrite != NGX_HTTP_MOVED_TEMPORARILY
         && overwrite != NGX_HTTP_SEE_OTHER
-        && overwrite != NGX_HTTP_TEMPORARY_REDIRECT)
+        && overwrite != NGX_HTTP_TEMPORARY_REDIRECT
+        && overwrite != NGX_HTTP_PERMANENT_REDIRECT)
     {
         r->err_status = NGX_HTTP_MOVED_TEMPORARILY;
     }
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 9e1f3b0..778a16a 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -4972,17 +4972,18 @@
         }
     }
 
-    ph = ngx_array_push(pa);
-    if (ph == NULL) {
-        return NGX_ERROR;
-    }
-
     ho = ngx_list_push(&r->headers_out.headers);
     if (ho == NULL) {
         return NGX_ERROR;
     }
 
     *ho = *h;
+
+    ph = ngx_array_push(pa);
+    if (ph == NULL) {
+        return NGX_ERROR;
+    }
+
     *ph = ho;
 
     return NGX_OK;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 8bc35c8..906b042 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -2251,6 +2251,44 @@
                    "http2 WINDOW_UPDATE frame sid:%ui window:%uz",
                    h2c->state.sid, window);
 
+    if (window == 0) {
+        if (h2c->state.sid == 0) {
+            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+                          "client sent WINDOW_UPDATE frame "
+                          "with incorrect window increment 0");
+
+            return ngx_http_v2_connection_error(h2c,
+                                                NGX_HTTP_V2_PROTOCOL_ERROR);
+        }
+
+        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+                      "client sent WINDOW_UPDATE frame for stream %ui "
+                      "with incorrect window increment 0", h2c->state.sid);
+
+        node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
+
+        if (node && node->stream) {
+            if (ngx_http_v2_terminate_stream(h2c, node->stream,
+                                             NGX_HTTP_V2_PROTOCOL_ERROR)
+                == NGX_ERROR)
+            {
+                return ngx_http_v2_connection_error(h2c,
+                                                    NGX_HTTP_V2_INTERNAL_ERROR);
+            }
+
+        } else {
+            if (ngx_http_v2_send_rst_stream(h2c, h2c->state.sid,
+                                            NGX_HTTP_V2_PROTOCOL_ERROR)
+                == NGX_ERROR)
+            {
+                return ngx_http_v2_connection_error(h2c,
+                                                    NGX_HTTP_V2_INTERNAL_ERROR);
+            }
+        }
+
+        return ngx_http_v2_state_complete(h2c, pos, end);
+    }
+
     if (h2c->state.sid) {
         node = ngx_http_v2_get_node_by_id(h2c, h2c->state.sid, 0);
 
@@ -2263,22 +2301,6 @@
 
         stream = node->stream;
 
-        if (window == 0) {
-            ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
-                          "client sent WINDOW_UPDATE frame for stream %ui "
-                          "with incorrect window increment 0", h2c->state.sid);
-
-            if (ngx_http_v2_terminate_stream(h2c, stream,
-                                             NGX_HTTP_V2_PROTOCOL_ERROR)
-                == NGX_ERROR)
-            {
-                return ngx_http_v2_connection_error(h2c,
-                                                    NGX_HTTP_V2_INTERNAL_ERROR);
-            }
-
-            return ngx_http_v2_state_complete(h2c, pos, end);
-        }
-
         if (window > (size_t) (NGX_HTTP_V2_MAX_WINDOW - stream->send_window)) {
 
             ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
@@ -2317,14 +2339,6 @@
         return ngx_http_v2_state_complete(h2c, pos, end);
     }
 
-    if (window == 0) {
-        ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
-                      "client sent WINDOW_UPDATE frame "
-                      "with incorrect window increment 0");
-
-        return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
-    }
-
     if (window > NGX_HTTP_V2_MAX_WINDOW - h2c->send_window) {
         ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
                       "client violated connection flow control: "
@@ -3604,8 +3618,7 @@
 
 
 ngx_int_t
-ngx_http_v2_read_request_body(ngx_http_request_t *r,
-    ngx_http_client_body_handler_pt post_handler)
+ngx_http_v2_read_request_body(ngx_http_request_t *r)
 {
     off_t                      len;
     size_t                     size;
@@ -3618,35 +3631,11 @@
     ngx_http_v2_connection_t  *h2c;
 
     stream = r->stream;
+    rb = r->request_body;
 
     if (stream->skip_data) {
         r->request_body_no_buffering = 0;
-        post_handler(r);
-        return NGX_OK;
-    }
-
-    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
-    if (rb == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
-    }
-
-    /*
-     * set by ngx_pcalloc():
-     *
-     *     rb->bufs = NULL;
-     *     rb->buf = NULL;
-     *     rb->received = 0;
-     *     rb->free = NULL;
-     *     rb->busy = NULL;
-     */
-
-    rb->post_handler = post_handler;
-
-    r->request_body = rb;
-
-    if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
-        r->request_body_no_buffering = 0;
-        post_handler(r);
+        rb->post_handler(r);
         return NGX_OK;
     }
 
diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
index c13ce53..4804658 100644
--- a/src/http/v2/ngx_http_v2.h
+++ b/src/http/v2/ngx_http_v2.h
@@ -273,8 +273,7 @@
 void ngx_http_v2_init(ngx_event_t *rev);
 void ngx_http_v2_request_headers_init(void);
 
-ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r,
-    ngx_http_client_body_handler_pt post_handler);
+ngx_int_t ngx_http_v2_read_request_body(ngx_http_request_t *r);
 ngx_int_t ngx_http_v2_read_unbuffered_request_body(ngx_http_request_t *r);
 
 void ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc);
diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c
index 9e560bb..5fd5fa0 100644
--- a/src/mail/ngx_mail.c
+++ b/src/mail/ngx_mail.c
@@ -333,6 +333,8 @@
             ls->log.handler = ngx_accept_log_error;
 
             ls->backlog = addr[i].opt.backlog;
+            ls->rcvbuf = addr[i].opt.rcvbuf;
+            ls->sndbuf = addr[i].opt.sndbuf;
 
             ls->keepalive = addr[i].opt.so_keepalive;
 #if (NGX_HAVE_KEEPALIVE_TUNABLE)
diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h
index 6002508..6ecfefc 100644
--- a/src/mail/ngx_mail.h
+++ b/src/mail/ngx_mail.h
@@ -46,6 +46,8 @@
     int                     tcp_keepcnt;
 #endif
     int                     backlog;
+    int                     rcvbuf;
+    int                     sndbuf;
 } ngx_mail_listen_t;
 
 
diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c
index b974d90..276b8ee 100644
--- a/src/mail/ngx_mail_core_module.c
+++ b/src/mail/ngx_mail_core_module.c
@@ -295,7 +295,7 @@
 {
     ngx_mail_core_srv_conf_t  *cscf = conf;
 
-    ngx_str_t                  *value;
+    ngx_str_t                  *value, size;
     ngx_url_t                   u;
     ngx_uint_t                  i, m;
     ngx_mail_listen_t          *ls;
@@ -350,6 +350,8 @@
 
     ls->socklen = u.socklen;
     ls->backlog = NGX_LISTEN_BACKLOG;
+    ls->rcvbuf = -1;
+    ls->sndbuf = -1;
     ls->wildcard = u.wildcard;
     ls->ctx = cf->ctx;
 
@@ -398,6 +400,38 @@
             continue;
         }
 
+        if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
+            size.len = value[i].len - 7;
+            size.data = value[i].data + 7;
+
+            ls->rcvbuf = ngx_parse_size(&size);
+            ls->bind = 1;
+
+            if (ls->rcvbuf == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid rcvbuf \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
+            size.len = value[i].len - 7;
+            size.data = value[i].data + 7;
+
+            ls->sndbuf = ngx_parse_size(&size);
+            ls->bind = 1;
+
+            if (ls->sndbuf == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid sndbuf \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
         if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
             size_t  len;
diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c
index fbc9bc7..aebd179 100644
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -42,6 +42,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/os/unix/ngx_darwin_config.h b/src/os/unix/ngx_darwin_config.h
index cfe3ce2..0dfe633 100644
--- a/src/os/unix/ngx_darwin_config.h
+++ b/src/os/unix/ngx_darwin_config.h
@@ -9,6 +9,9 @@
 #define _NGX_DARWIN_CONFIG_H_INCLUDED_
 
 
+#define __APPLE_USE_RFC_3542    /* IPV6_PKTINFO */
+
+
 #include <sys/types.h>
 #include <sys/time.h>
 #include <unistd.h>
diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c
index 2d37e21..dd50b5c 100644
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -15,13 +15,13 @@
     int     signo;
     char   *signame;
     char   *name;
-    void  (*handler)(int signo);
+    void  (*handler)(int signo, siginfo_t *siginfo, void *ucontext);
 } ngx_signal_t;
 
 
 
 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
-static void ngx_signal_handler(int signo);
+static void ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext);
 static void ngx_process_get_status(void);
 static void ngx_unlock_mutexes(ngx_pid_t pid);
 
@@ -75,9 +75,9 @@
 
     { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
 
-    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
+    { SIGSYS, "SIGSYS, SIG_IGN", "", NULL },
 
-    { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
+    { SIGPIPE, "SIGPIPE, SIG_IGN", "", NULL },
 
     { 0, NULL, "", NULL }
 };
@@ -288,7 +288,15 @@
 
     for (sig = signals; sig->signo != 0; sig++) {
         ngx_memzero(&sa, sizeof(struct sigaction));
-        sa.sa_handler = sig->handler;
+
+        if (sig->handler) {
+            sa.sa_sigaction = sig->handler;
+            sa.sa_flags = SA_SIGINFO;
+
+        } else {
+            sa.sa_handler = SIG_IGN;
+        }
+
         sigemptyset(&sa.sa_mask);
         if (sigaction(sig->signo, &sa, NULL) == -1) {
 #if (NGX_VALGRIND)
@@ -307,7 +315,7 @@
 
 
 static void
-ngx_signal_handler(int signo)
+ngx_signal_handler(int signo, siginfo_t *siginfo, void *ucontext)
 {
     char            *action;
     ngx_int_t        ignore;
@@ -431,8 +439,16 @@
         break;
     }
 
-    ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
-                  "signal %d (%s) received%s", signo, sig->signame, action);
+    if (siginfo && siginfo->si_pid) {
+        ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+                      "signal %d (%s) received from %P%s",
+                      signo, sig->signame, siginfo->si_pid, action);
+
+    } else {
+        ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
+                      "signal %d (%s) received%s",
+                      signo, sig->signame, action);
+    }
 
     if (ignore) {
         ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
diff --git a/src/os/unix/ngx_udp_sendmsg_chain.c b/src/os/unix/ngx_udp_sendmsg_chain.c
index 65bde6f..5f1cfa5 100644
--- a/src/os/unix/ngx_udp_sendmsg_chain.c
+++ b/src/os/unix/ngx_udp_sendmsg_chain.c
@@ -203,6 +203,20 @@
     ngx_err_t      err;
     struct msghdr  msg;
 
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+#if (NGX_HAVE_IP_SENDSRCADDR)
+    u_char             msg_control[CMSG_SPACE(sizeof(struct in_addr))];
+#elif (NGX_HAVE_IP_PKTINFO)
+    u_char             msg_control[CMSG_SPACE(sizeof(struct in_pktinfo))];
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+    u_char             msg_control6[CMSG_SPACE(sizeof(struct in6_pktinfo))];
+#endif
+
+#endif
+
     ngx_memzero(&msg, sizeof(struct msghdr));
 
     if (c->socklen) {
@@ -213,6 +227,82 @@
     msg.msg_iov = vec->iovs;
     msg.msg_iovlen = vec->count;
 
+#if (NGX_HAVE_MSGHDR_MSG_CONTROL)
+
+    if (c->listening && c->listening->wildcard && c->local_sockaddr) {
+
+#if (NGX_HAVE_IP_SENDSRCADDR)
+
+        if (c->local_sockaddr->sa_family == AF_INET) {
+            struct cmsghdr      *cmsg;
+            struct in_addr      *addr;
+            struct sockaddr_in  *sin;
+
+            msg.msg_control = &msg_control;
+            msg.msg_controllen = sizeof(msg_control);
+
+            cmsg = CMSG_FIRSTHDR(&msg);
+            cmsg->cmsg_level = IPPROTO_IP;
+            cmsg->cmsg_type = IP_SENDSRCADDR;
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+
+            sin = (struct sockaddr_in *) c->local_sockaddr;
+
+            addr = (struct in_addr *) CMSG_DATA(cmsg);
+            *addr = sin->sin_addr;
+        }
+
+#elif (NGX_HAVE_IP_PKTINFO)
+
+        if (c->local_sockaddr->sa_family == AF_INET) {
+            struct cmsghdr      *cmsg;
+            struct in_pktinfo   *pkt;
+            struct sockaddr_in  *sin;
+
+            msg.msg_control = &msg_control;
+            msg.msg_controllen = sizeof(msg_control);
+
+            cmsg = CMSG_FIRSTHDR(&msg);
+            cmsg->cmsg_level = IPPROTO_IP;
+            cmsg->cmsg_type = IP_PKTINFO;
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+
+            sin = (struct sockaddr_in *) c->local_sockaddr;
+
+            pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+            ngx_memzero(pkt, sizeof(struct in_pktinfo));
+            pkt->ipi_spec_dst = sin->sin_addr;
+        }
+
+#endif
+
+#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+
+        if (c->local_sockaddr->sa_family == AF_INET6) {
+            struct cmsghdr       *cmsg;
+            struct in6_pktinfo   *pkt6;
+            struct sockaddr_in6  *sin6;
+
+            msg.msg_control = &msg_control6;
+            msg.msg_controllen = sizeof(msg_control6);
+
+            cmsg = CMSG_FIRSTHDR(&msg);
+            cmsg->cmsg_level = IPPROTO_IPV6;
+            cmsg->cmsg_type = IPV6_PKTINFO;
+            cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+
+            sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
+
+            pkt6 = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+            ngx_memzero(pkt6, sizeof(struct in6_pktinfo));
+            pkt6->ipi6_addr = sin6->sin6_addr;
+        }
+
+#endif
+    }
+
+#endif
+
 eintr:
 
     n = sendmsg(c->fd, &msg, 0);
diff --git a/src/stream/ngx_stream.c b/src/stream/ngx_stream.c
index 4a394d7..0efbda8 100644
--- a/src/stream/ngx_stream.c
+++ b/src/stream/ngx_stream.c
@@ -494,6 +494,8 @@
             ls->log.handler = ngx_accept_log_error;
 
             ls->backlog = addr[i].opt.backlog;
+            ls->rcvbuf = addr[i].opt.rcvbuf;
+            ls->sndbuf = addr[i].opt.sndbuf;
 
             ls->wildcard = addr[i].opt.wildcard;
 
diff --git a/src/stream/ngx_stream.h b/src/stream/ngx_stream.h
index 814e3b9..09d2459 100644
--- a/src/stream/ngx_stream.h
+++ b/src/stream/ngx_stream.h
@@ -62,6 +62,8 @@
     int                            tcp_keepcnt;
 #endif
     int                            backlog;
+    int                            rcvbuf;
+    int                            sndbuf;
     int                            type;
 } ngx_stream_listen_t;
 
diff --git a/src/stream/ngx_stream_core_module.c b/src/stream/ngx_stream_core_module.c
index f7870ee..db8c2a3 100644
--- a/src/stream/ngx_stream_core_module.c
+++ b/src/stream/ngx_stream_core_module.c
@@ -582,7 +582,7 @@
 {
     ngx_stream_core_srv_conf_t  *cscf = conf;
 
-    ngx_str_t                    *value;
+    ngx_str_t                    *value, size;
     ngx_url_t                     u;
     ngx_uint_t                    i, backlog;
     ngx_stream_listen_t          *ls, *als;
@@ -620,6 +620,8 @@
 
     ls->socklen = u.socklen;
     ls->backlog = NGX_LISTEN_BACKLOG;
+    ls->rcvbuf = -1;
+    ls->sndbuf = -1;
     ls->type = SOCK_STREAM;
     ls->wildcard = u.wildcard;
     ls->ctx = cf->ctx;
@@ -659,6 +661,38 @@
             continue;
         }
 
+        if (ngx_strncmp(value[i].data, "rcvbuf=", 7) == 0) {
+            size.len = value[i].len - 7;
+            size.data = value[i].data + 7;
+
+            ls->rcvbuf = ngx_parse_size(&size);
+            ls->bind = 1;
+
+            if (ls->rcvbuf == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid rcvbuf \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
+        if (ngx_strncmp(value[i].data, "sndbuf=", 7) == 0) {
+            size.len = value[i].len - 7;
+            size.data = value[i].data + 7;
+
+            ls->sndbuf = ngx_parse_size(&size);
+            ls->bind = 1;
+
+            if (ls->sndbuf == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid sndbuf \"%V\"", &value[i]);
+                return NGX_CONF_ERROR;
+            }
+
+            continue;
+        }
+
         if (ngx_strncmp(value[i].data, "ipv6only=o", 10) == 0) {
 #if (NGX_HAVE_INET6 && defined IPV6_V6ONLY)
             size_t  len;
diff --git a/src/stream/ngx_stream_proxy_module.c b/src/stream/ngx_stream_proxy_module.c
index 81a0891..fe52cb6 100644
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -103,6 +103,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };
 
diff --git a/src/stream/ngx_stream_ssl_module.c b/src/stream/ngx_stream_ssl_module.c
index 2f242b6..593776b 100644
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -45,6 +45,7 @@
     { ngx_string("TLSv1"), NGX_SSL_TLSv1 },
     { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 },
     { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 },
+    { ngx_string("TLSv1.3"), NGX_SSL_TLSv1_3 },
     { ngx_null_string, 0 }
 };