changeset 9066:0af598651e33 quic

Merged with the default branch.
author Sergey Kandaurov <pluknet@nginx.com>
date Wed, 29 Mar 2023 11:14:25 +0400
parents efd91f6afa8d (current diff) 5f1d05a21287 (diff)
children f68fdb017141
files auto/os/linux src/core/ngx_connection.h src/event/ngx_event_openssl.c src/http/modules/ngx_http_ssl_module.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_request.c src/stream/ngx_stream_proxy_module.c src/stream/ngx_stream_ssl_module.c
diffstat 36 files changed, 1105 insertions(+), 180 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags
+++ b/.hgtags
@@ -471,3 +471,4 @@ 5da2c0902e8e2aa4534008a582a60c61c135960e
 a63d0a70afea96813ba6667997bc7d68b5863f0d release-1.23.1
 aa901551a7ebad1e8b0f8c11cb44e3424ba29707 release-1.23.2
 ff3afd1ce6a6b65057741df442adfaa71a0e2588 release-1.23.3
+ac779115ed6ee4f3039e9aea414a54e560450ee2 release-1.23.4
--- a/auto/cc/conf
+++ b/auto/cc/conf
@@ -117,7 +117,7 @@ else
             . auto/cc/acc
         ;;
 
-        msvc*)
+        msvc)
             # MSVC++ 6.0 SP2, MSVC++ Toolkit 2003
 
             . auto/cc/msvc
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -11,8 +11,8 @@
 # MSVC 2015 (14.0)                        cl 19.00
 
 
-NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'Compiler Version' 2>&1 \
-                                 | sed -e 's/^.* Version \(.*\)/\1/'`
+NGX_MSVC_VER=`$NGX_WINE $CC 2>&1 | grep 'C/C++.* [0-9][0-9]*\.[0-9]' 2>&1 \
+                                 | sed -e 's/^.* \([0-9][0-9]*\.[0-9].*\)/\1/'`
 
 echo " + cl version: $NGX_MSVC_VER"
 
@@ -22,6 +22,21 @@ have=NGX_COMPILER value="\"cl $NGX_MSVC_
 ngx_msvc_ver=`echo $NGX_MSVC_VER | sed -e 's/^\([0-9]*\).*/\1/'`
 
 
+# detect x64 builds
+
+case "$NGX_MSVC_VER" in
+
+    *x64)
+        NGX_MACHINE=amd64
+    ;;
+
+    *)
+        NGX_MACHINE=i386
+    ;;
+
+esac
+
+
 # optimizations
 
 # maximize speed, equivalent to -Og -Oi -Ot -Oy -Ob2 -Gs -GF -Gy
--- a/auto/configure
+++ b/auto/configure
@@ -44,6 +44,7 @@ if test -z "$NGX_PLATFORM"; then
 else
     echo "building for $NGX_PLATFORM"
     NGX_SYSTEM=$NGX_PLATFORM
+    NGX_MACHINE=i386
 fi
 
 . auto/cc/conf
--- a/auto/lib/openssl/make
+++ b/auto/lib/openssl/make
@@ -7,11 +7,24 @@ case "$CC" in
 
     cl)
 
+        case "$NGX_MACHINE" in
+
+            amd64)
+                OPENSSL_TARGET=VC-WIN64A
+            ;;
+
+            *)
+                OPENSSL_TARGET=VC-WIN32
+            ;;
+
+        esac
+
         cat << END                                            >> $NGX_MAKEFILE
 
 $OPENSSL/openssl/include/openssl/ssl.h:	$NGX_MAKEFILE
 	\$(MAKE) -f auto/lib/openssl/makefile.msvc			\
-		OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT"
+		OPENSSL="$OPENSSL" OPENSSL_OPT="$OPENSSL_OPT"		\
+		OPENSSL_TARGET="$OPENSSL_TARGET"
 
 END
 
--- a/auto/lib/openssl/makefile.msvc
+++ b/auto/lib/openssl/makefile.msvc
@@ -6,7 +6,7 @@
 all:
 	cd $(OPENSSL)
 
-	perl Configure VC-WIN32 no-shared no-threads			\
+	perl Configure $(OPENSSL_TARGET) no-shared no-threads		\
 		--prefix="%cd%/openssl" 				\
 		--openssldir="%cd%/openssl/ssl" 			\
 		$(OPENSSL_OPT)
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -282,7 +282,6 @@ ngx_feature="UDP_SEGMENT"
 ngx_feature_name="NGX_HAVE_UDP_SEGMENT"
 ngx_feature_run=no
 ngx_feature_incs="#include <sys/socket.h>
-                  #include <stdint.h>
                   #include <netinet/udp.h>"
 ngx_feature_path=
 ngx_feature_libs=
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,163 @@
 <change_log title="nginx">
 
 
+<changes ver="1.23.4" date="2023-03-28">
+
+<change type="change">
+<para lang="ru">
+теперь протокол TLSv1.3 разрешён по умолчанию.
+</para>
+<para lang="en">
+now TLSv1.3 protocol is enabled by default.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь nginx выдаёт предупреждение
+при переопределении параметров listen-сокета, задающих используемые протоколы.
+</para>
+<para lang="en">
+now nginx issues a warning
+if protocol parameters of a listening socket are redefined.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+теперь, если клиент использует pipelining,
+nginx закрывает соединения с ожиданием дополнительных данных (lingering close).
+</para>
+<para lang="en">
+now nginx closes connections with lingering
+if pipelining was used by the client.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+поддержка byte ranges для ответов модуля ngx_http_gzip_static_module.
+</para>
+<para lang="en">
+byte ranges support in the ngx_http_gzip_static_module.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+диапазоны портов в директиве listen не работали;
+ошибка появилась в 1.23.3.<br/>
+Спасибо Валентину Бартеневу.
+</para>
+<para lang="en">
+port ranges in the "listen" directive did not work;
+the bug had appeared in 1.23.3.<br/>
+Thanks to Valentin Bartenev.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+для обработки запроса мог быть выбран неверный location,
+если в конфигурации использовался
+префиксный location длиннее 255 символов.
+</para>
+<para lang="en">
+incorrect location might be chosen to process a request
+if a prefix location longer than 255 characters
+was used in the configuration.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+не-ASCII символы в именах файлов на Windows
+не поддерживались модулями ngx_http_autoindex_module и
+ngx_http_dav_module, а также директивой include.
+</para>
+<para lang="en">
+non-ASCII characters in file names on Windows were not supported
+by the ngx_http_autoindex_module, the ngx_http_dav_module,
+and the "include" directive.
+</para>
+</change>
+
+<change type="change">
+<para lang="ru">
+уровень логгирования ошибок SSL
+"data length too long", "length too short", "bad legacy version",
+"no shared signature algorithms", "bad digest length",
+"missing sigalgs extension", "encrypted length too long",
+"bad length", "bad key update", "mixed handshake and non handshake data",
+"ccs received early", "data between ccs and finished",
+"packet length too long", "too many warn alerts", "record too small",
+и "got a fin before a ccs"
+понижен с уровня crit до info.
+</para>
+<para lang="en">
+the logging level of the
+"data length too long", "length too short", "bad legacy version",
+"no shared signature algorithms", "bad digest length",
+"missing sigalgs extension", "encrypted length too long",
+"bad length", "bad key update", "mixed handshake and non handshake data",
+"ccs received early", "data between ccs and finished",
+"packet length too long", "too many warn alerts", "record too small",
+and "got a fin before a ccs" SSL errors
+has been lowered from "crit" to "info".
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании HTTP/2 и директивы error_page
+для перенаправления ошибок с кодом 400
+могла происходить утечка сокетов.
+</para>
+<para lang="en">
+a socket leak might occur
+when using HTTP/2 and the "error_page" directive
+to redirect errors with code 400.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+сообщения об ошибках записи в syslog
+не содержали информации о том, что
+ошибки происходили в процессе записи в syslog.<br/>
+Спасибо Safar Safarly.
+</para>
+<para lang="en">
+messages about logging to syslog errors
+did not contain information
+that the errors happened while logging to syslog.<br/>
+Thanks to Safar Safarly.
+</para>
+</change>
+
+<change type="workaround">
+<para lang="ru">
+при использовании zlib-ng
+в логах появлялись сообщения "gzip filter failed to use preallocated memory".
+</para>
+<para lang="en">
+"gzip filter failed to use preallocated memory" alerts appeared in logs
+when using zlib-ng.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в почтовом прокси-сервере.
+</para>
+<para lang="en">
+in the mail proxy server.
+</para>
+</change>
+
+</changes>
+
+
 <changes ver="1.23.3" date="2022-12-13">
 
 <change type="bugfix">
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@ TEMP =		tmp
 
 CC =		cl
 OBJS =		objs.msvc8
-OPENSSL =	openssl-1.1.1s
+OPENSSL =	openssl-1.1.1t
 ZLIB =		zlib-1.2.13
 PCRE =		pcre2-10.39
 
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -177,6 +177,7 @@ struct ngx_connection_s {
     unsigned            timedout:1;
     unsigned            error:1;
     unsigned            destroyed:1;
+    unsigned            pipeline:1;
 
     unsigned            idle:1;
     unsigned            reusable:1;
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1364,7 +1364,12 @@ ngx_utf8_decode(u_char **p, size_t n)
 
     u = **p;
 
-    if (u >= 0xf0) {
+    if (u >= 0xf8) {
+
+        (*p)++;
+        return 0xffffffff;
+
+    } else if (u >= 0xf0) {
 
         u &= 0x07;
         valid = 0xffff;
--- a/src/core/ngx_syslog.c
+++ b/src/core/ngx_syslog.c
@@ -18,6 +18,7 @@
 static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
 static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
 static void ngx_syslog_cleanup(void *data);
+static u_char *ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len);
 
 
 static char  *facilities[] = {
@@ -66,6 +67,9 @@ ngx_syslog_process_conf(ngx_conf_t *cf, 
         ngx_str_set(&peer->tag, "nginx");
     }
 
+    peer->hostname = &cf->cycle->hostname;
+    peer->logp = &cf->cycle->new_log;
+
     peer->conn.fd = (ngx_socket_t) -1;
 
     peer->conn.read = &ngx_syslog_dummy_event;
@@ -243,7 +247,7 @@ ngx_syslog_add_header(ngx_syslog_peer_t 
     }
 
     return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
-                       &ngx_cycle->hostname, &peer->tag);
+                       peer->hostname, &peer->tag);
 }
 
 
@@ -286,15 +290,19 @@ ngx_syslog_send(ngx_syslog_peer_t *peer,
 {
     ssize_t  n;
 
+    if (peer->log.handler == NULL) {
+        peer->log = *peer->logp;
+        peer->log.handler = ngx_syslog_log_error;
+        peer->log.data = peer;
+        peer->log.action = "logging to syslog";
+    }
+
     if (peer->conn.fd == (ngx_socket_t) -1) {
         if (ngx_syslog_init_peer(peer) != NGX_OK) {
             return NGX_ERROR;
         }
     }
 
-    /* log syslog socket events with valid log */
-    peer->conn.log = ngx_cycle->log;
-
     if (ngx_send) {
         n = ngx_send(&peer->conn, buf, len);
 
@@ -306,7 +314,7 @@ ngx_syslog_send(ngx_syslog_peer_t *peer,
     if (n == NGX_ERROR) {
 
         if (ngx_close_socket(peer->conn.fd) == -1) {
-            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+            ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                           ngx_close_socket_n " failed");
         }
 
@@ -324,24 +332,25 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *
 
     fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
     if (fd == (ngx_socket_t) -1) {
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                       ngx_socket_n " failed");
         return NGX_ERROR;
     }
 
     if (ngx_nonblocking(fd) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                       ngx_nonblocking_n " failed");
         goto failed;
     }
 
     if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                       "connect() failed");
         goto failed;
     }
 
     peer->conn.fd = fd;
+    peer->conn.log = &peer->log;
 
     /* UDP sockets are always ready to write */
     peer->conn.write->ready = 1;
@@ -351,7 +360,7 @@ ngx_syslog_init_peer(ngx_syslog_peer_t *
 failed:
 
     if (ngx_close_socket(fd) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                       ngx_close_socket_n " failed");
     }
 
@@ -372,7 +381,30 @@ ngx_syslog_cleanup(void *data)
     }
 
     if (ngx_close_socket(peer->conn.fd) == -1) {
-        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
+        ngx_log_error(NGX_LOG_ALERT, &peer->log, ngx_socket_errno,
                       ngx_close_socket_n " failed");
     }
 }
+
+
+static u_char *
+ngx_syslog_log_error(ngx_log_t *log, u_char *buf, size_t len)
+{
+    u_char             *p;
+    ngx_syslog_peer_t  *peer;
+
+    p = buf;
+
+    if (log->action) {
+        p = ngx_snprintf(buf, len, " while %s", log->action);
+        len -= p - buf;
+    }
+
+    peer = log->data;
+
+    if (peer) {
+        p = ngx_snprintf(p, len, ", server: %V", &peer->server.name);
+    }
+
+    return p;
+}
--- a/src/core/ngx_syslog.h
+++ b/src/core/ngx_syslog.h
@@ -9,14 +9,20 @@
 
 
 typedef struct {
-    ngx_uint_t        facility;
-    ngx_uint_t        severity;
-    ngx_str_t         tag;
+    ngx_uint_t         facility;
+    ngx_uint_t         severity;
+    ngx_str_t          tag;
+
+    ngx_str_t         *hostname;
 
-    ngx_addr_t        server;
-    ngx_connection_t  conn;
-    unsigned          busy:1;
-    unsigned          nohostname:1;
+    ngx_addr_t         server;
+    ngx_connection_t   conn;
+
+    ngx_log_t          log;
+    ngx_log_t         *logp;
+
+    unsigned           busy:1;
+    unsigned           nohostname:1;
 } ngx_syslog_peer_t;
 
 
--- a/src/event/ngx_event_connectex.c
+++ b/src/event/ngx_event_connectex.c
@@ -127,8 +127,8 @@ void ngx_iocp_wait_events(int main)
     conn[0] = NULL;
 
     for ( ;; ) {
-        offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1: 0;
-        timeout = (nevents == 1 && !first) ? 60000: INFINITE;
+        offset = (nevents == WSA_MAXIMUM_WAIT_EVENTS + 1) ? 1 : 0;
+        timeout = (nevents == 1 && !first) ? 60000 : INFINITE;
 
         n = WSAWaitForMultipleEvents(nevents - offset, events[offset],
                                      0, timeout, 0);
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -3393,29 +3393,58 @@ ngx_ssl_connection_error(ngx_connection_
 
     } else if (sslerr == SSL_ERROR_SSL) {
 
-        n = ERR_GET_REASON(ERR_peek_error());
+        n = ERR_GET_REASON(ERR_peek_last_error());
 
             /* handshake failures */
         if (n == SSL_R_BAD_CHANGE_CIPHER_SPEC                        /*  103 */
 #ifdef SSL_R_NO_SUITABLE_KEY_SHARE
             || n == SSL_R_NO_SUITABLE_KEY_SHARE                      /*  101 */
 #endif
+#ifdef SSL_R_BAD_ALERT
+            || n == SSL_R_BAD_ALERT                                  /*  102 */
+#endif
 #ifdef SSL_R_BAD_KEY_SHARE
             || n == SSL_R_BAD_KEY_SHARE                              /*  108 */
 #endif
 #ifdef SSL_R_BAD_EXTENSION
             || n == SSL_R_BAD_EXTENSION                              /*  110 */
 #endif
+            || n == SSL_R_BAD_DIGEST_LENGTH                          /*  111 */
+#ifdef SSL_R_MISSING_SIGALGS_EXTENSION
+            || n == SSL_R_MISSING_SIGALGS_EXTENSION                  /*  112 */
+#endif
+            || n == SSL_R_BAD_PACKET_LENGTH                          /*  115 */
 #ifdef SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM
             || n == SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM            /*  118 */
 #endif
+#ifdef SSL_R_BAD_KEY_UPDATE
+            || n == SSL_R_BAD_KEY_UPDATE                             /*  122 */
+#endif
             || n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG                  /*  129 */
+            || n == SSL_R_CCS_RECEIVED_EARLY                         /*  133 */
+#ifdef SSL_R_DECODE_ERROR
+            || n == SSL_R_DECODE_ERROR                               /*  137 */
+#endif
+#ifdef SSL_R_DATA_BETWEEN_CCS_AND_FINISHED
+            || n == SSL_R_DATA_BETWEEN_CCS_AND_FINISHED              /*  145 */
+#endif
+            || n == SSL_R_DATA_LENGTH_TOO_LONG                       /*  146 */
             || n == SSL_R_DIGEST_CHECK_FAILED                        /*  149 */
+            || n == SSL_R_ENCRYPTED_LENGTH_TOO_LONG                  /*  150 */
             || n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST              /*  151 */
             || n == SSL_R_EXCESSIVE_MESSAGE_SIZE                     /*  152 */
+#ifdef SSL_R_GOT_A_FIN_BEFORE_A_CCS
+            || n == SSL_R_GOT_A_FIN_BEFORE_A_CCS                     /*  154 */
+#endif
             || n == SSL_R_HTTPS_PROXY_REQUEST                        /*  155 */
             || n == SSL_R_HTTP_REQUEST                               /*  156 */
             || n == SSL_R_LENGTH_MISMATCH                            /*  159 */
+#ifdef SSL_R_LENGTH_TOO_SHORT
+            || n == SSL_R_LENGTH_TOO_SHORT                           /*  160 */
+#endif
+#ifdef SSL_R_NO_RENEGOTIATION
+            || n == SSL_R_NO_RENEGOTIATION                           /*  182 */
+#endif
 #ifdef SSL_R_NO_CIPHERS_PASSED
             || n == SSL_R_NO_CIPHERS_PASSED                          /*  182 */
 #endif
@@ -3425,7 +3454,13 @@ ngx_ssl_connection_error(ngx_connection_
 #endif
             || n == SSL_R_NO_COMPRESSION_SPECIFIED                   /*  187 */
             || n == SSL_R_NO_SHARED_CIPHER                           /*  193 */
+#ifdef SSL_R_PACKET_LENGTH_TOO_LONG
+            || n == SSL_R_PACKET_LENGTH_TOO_LONG                     /*  198 */
+#endif
             || n == SSL_R_RECORD_LENGTH_MISMATCH                     /*  213 */
+#ifdef SSL_R_TOO_MANY_WARNING_ALERTS
+            || n == SSL_R_TOO_MANY_WARNING_ALERTS                    /*  220 */
+#endif
 #ifdef SSL_R_CLIENTHELLO_TLSEXT
             || n == SSL_R_CLIENTHELLO_TLSEXT                         /*  226 */
 #endif
@@ -3435,6 +3470,9 @@ ngx_ssl_connection_error(ngx_connection_
 #ifdef SSL_R_CALLBACK_FAILED
             || n == SSL_R_CALLBACK_FAILED                            /*  234 */
 #endif
+#ifdef SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG
+            || n == SSL_R_TLS_RSA_ENCRYPTED_VALUE_LENGTH_IS_WRONG    /*  234 */
+#endif
 #ifdef SSL_R_NO_APPLICATION_PROTOCOL
             || n == SSL_R_NO_APPLICATION_PROTOCOL                    /*  235 */
 #endif
@@ -3445,11 +3483,21 @@ ngx_ssl_connection_error(ngx_connection_
 #ifdef SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS
             || n == SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS             /*  253 */
 #endif
+#ifdef SSL_R_INVALID_COMPRESSION_LIST
+            || n == SSL_R_INVALID_COMPRESSION_LIST                   /*  256 */
+#endif
+#ifdef SSL_R_MISSING_KEY_SHARE
+            || n == SSL_R_MISSING_KEY_SHARE                          /*  258 */
+#endif
             || n == SSL_R_UNSUPPORTED_PROTOCOL                       /*  258 */
 #ifdef SSL_R_NO_SHARED_GROUP
             || n == SSL_R_NO_SHARED_GROUP                            /*  266 */
 #endif
             || n == SSL_R_WRONG_VERSION_NUMBER                       /*  267 */
+#ifdef SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA
+            || n == SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA                /*  270 */
+#endif
+            || n == SSL_R_BAD_LENGTH                                 /*  271 */
             || n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC        /*  281 */
 #ifdef SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY
             || n == SSL_R_APPLICATION_DATA_AFTER_CLOSE_NOTIFY        /*  291 */
@@ -3457,6 +3505,18 @@ ngx_ssl_connection_error(ngx_connection_
 #ifdef SSL_R_APPLICATION_DATA_ON_SHUTDOWN
             || n == SSL_R_APPLICATION_DATA_ON_SHUTDOWN               /*  291 */
 #endif
+#ifdef SSL_R_BAD_LEGACY_VERSION
+            || n == SSL_R_BAD_LEGACY_VERSION                         /*  292 */
+#endif
+#ifdef SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA
+            || n == SSL_R_MIXED_HANDSHAKE_AND_NON_HANDSHAKE_DATA     /*  293 */
+#endif
+#ifdef SSL_R_RECORD_TOO_SMALL
+            || n == SSL_R_RECORD_TOO_SMALL                           /*  298 */
+#endif
+#ifdef SSL_R_SSL3_SESSION_ID_TOO_LONG
+            || n == SSL_R_SSL3_SESSION_ID_TOO_LONG                   /*  300 */
+#endif
 #ifdef SSL_R_BAD_ECPOINT
             || n == SSL_R_BAD_ECPOINT                                /*  306 */
 #endif
@@ -3474,12 +3534,21 @@ ngx_ssl_connection_error(ngx_connection_
 #ifdef SSL_R_INAPPROPRIATE_FALLBACK
             || n == SSL_R_INAPPROPRIATE_FALLBACK                     /*  373 */
 #endif
+#ifdef SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS
+            || n == SSL_R_NO_SHARED_SIGNATURE_ALGORITHMS             /*  376 */
+#endif
+#ifdef SSL_R_NO_SHARED_SIGATURE_ALGORITHMS
+            || n == SSL_R_NO_SHARED_SIGATURE_ALGORITHMS              /*  376 */
+#endif
 #ifdef SSL_R_CERT_CB_ERROR
             || n == SSL_R_CERT_CB_ERROR                              /*  377 */
 #endif
 #ifdef SSL_R_VERSION_TOO_LOW
             || n == SSL_R_VERSION_TOO_LOW                            /*  396 */
 #endif
+#ifdef SSL_R_TOO_MANY_WARN_ALERTS
+            || n == SSL_R_TOO_MANY_WARN_ALERTS                       /*  409 */
+#endif
 #ifdef SSL_R_BAD_RECORD_TYPE
             || n == SSL_R_BAD_RECORD_TYPE                            /*  443 */
 #endif
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -232,9 +232,10 @@ ngx_http_flv_handler(ngx_http_request_t 
     b->file_pos = start;
     b->file_last = of.size;
 
-    b->in_file = b->file_last ? 1: 0;
+    b->in_file = b->file_last ? 1 : 0;
     b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->in_file) ? 0 : 1;
 
     b->file->fd = of.fd;
     b->file->name = path;
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -4473,8 +4473,9 @@ ngx_http_grpc_merge_loc_conf(ngx_conf_t 
                               prev->upstream.ssl_session_reuse, 1);
 
     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
-                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                                  |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
                              "DEFAULT");
--- a/src/http/modules/ngx_http_gzip_filter_module.c
+++ b/src/http/modules/ngx_http_gzip_filter_module.c
@@ -57,6 +57,7 @@ typedef struct {
     unsigned             nomem:1;
     unsigned             buffering:1;
     unsigned             zlib_ng:1;
+    unsigned             state_allocated:1;
 
     size_t               zin;
     size_t               zout;
@@ -514,9 +515,10 @@ ngx_http_gzip_filter_memory(ngx_http_req
     } else {
         /*
          * Another zlib variant, https://github.com/zlib-ng/zlib-ng.
-         * It forces window bits to 13 for fast compression level,
-         * uses 16-byte padding in one of window-sized buffers, and
-         * uses 128K hash.
+         * It used to force window bits to 13 for fast compression level,
+         * uses (64 + sizeof(void*)) additional space on all allocations
+         * for alignment, 16-byte padding in one of window-sized buffers,
+         * and 128K hash.
          */
 
         if (conf->level == 1) {
@@ -524,7 +526,8 @@ ngx_http_gzip_filter_memory(ngx_http_req
         }
 
         ctx->allocated = 8192 + 16 + (1 << (wbits + 2))
-                         + 131072 + (1 << (memlevel + 8));
+                         + 131072 + (1 << (memlevel + 8))
+                         + 4 * (64 + sizeof(void*));
         ctx->zlib_ng = 1;
     }
 }
@@ -926,13 +929,16 @@ ngx_http_gzip_filter_alloc(void *opaque,
 
     alloc = items * size;
 
-    if (items == 1 && alloc % 512 != 0 && alloc < 8192) {
-
+    if (items == 1 && alloc % 512 != 0 && alloc < 8192
+        && !ctx->state_allocated)
+    {
         /*
          * The zlib deflate_state allocation, it takes about 6K,
          * we allocate 8K.  Other allocations are divisible by 512.
          */
 
+        ctx->state_allocated = 1;
+
         alloc = 8192;
     }
 
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -247,6 +247,8 @@ ngx_http_gzip_static_handler(ngx_http_re
     ngx_str_set(&h->value, "gzip");
     r->headers_out.content_encoding = h;
 
+    r->allow_ranges = 1;
+
     /* we need to allocate all before the header would be sent */
 
     b = ngx_calloc_buf(r->pool);
@@ -271,6 +273,7 @@ ngx_http_gzip_static_handler(ngx_http_re
     b->in_file = b->file_last ? 1 : 0;
     b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->in_file) ? 0 : 1;
 
     b->file->fd = of.fd;
     b->file->name = path;
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -714,6 +714,7 @@ ngx_http_mp4_handler(ngx_http_request_t 
     b->in_file = b->file_last ? 1 : 0;
     b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->in_file) ? 0 : 1;
 
     b->file->fd = of.fd;
     b->file->name = path;
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -3734,8 +3734,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t
                               prev->upstream.ssl_session_reuse, 1);
 
     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
-                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                                  |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
                              "DEFAULT");
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -670,8 +670,9 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
     ngx_conf_merge_value(conf->reject_handshake, prev->reject_handshake, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
-                         (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                          |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                         (NGX_CONF_BITMASK_SET
+                          |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                          |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
                          NGX_SSL_BUFSIZE);
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -238,10 +238,6 @@ ngx_http_static_handler(ngx_http_request
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
     }
 
-    if (r != r->main && of.size == 0) {
-        return ngx_http_send_header(r);
-    }
-
     r->allow_ranges = 1;
 
     /* we need to allocate all before the header would be sent */
@@ -265,9 +261,10 @@ ngx_http_static_handler(ngx_http_request
     b->file_pos = 0;
     b->file_last = of.size;
 
-    b->in_file = b->file_last ? 1: 0;
-    b->last_buf = (r == r->main) ? 1: 0;
+    b->in_file = b->file_last ? 1 : 0;
+    b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->in_file) ? 0 : 1;
 
     b->file->fd = of.fd;
     b->file->name = path;
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1875,8 +1875,9 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t
                               prev->upstream.ssl_session_reuse, 1);
 
     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
-                                 (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                                  |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                                 (NGX_CONF_BITMASK_SET
+                                  |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                                  |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers,
                              "DEFAULT");
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -1130,7 +1130,7 @@ ngx_http_create_locations_tree(ngx_conf_
     node->auto_redirect = (u_char) ((lq->exact && lq->exact->auto_redirect)
                            || (lq->inclusive && lq->inclusive->auto_redirect));
 
-    node->len = (u_char) len;
+    node->len = (u_short) len;
     ngx_memcpy(node->name, &lq->name->data[prefix], len);
 
     ngx_queue_split(locations, q, &tail);
@@ -1232,7 +1232,8 @@ static ngx_int_t
 ngx_http_add_addresses(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
     ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
 {
-    ngx_uint_t             i, default_server, proxy_protocol;
+    ngx_uint_t             i, default_server, proxy_protocol,
+                           protocols, protocols_prev;
     ngx_http_conf_addr_t  *addr;
 #if (NGX_HTTP_SSL)
     ngx_uint_t             ssl;
@@ -1272,12 +1273,18 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
         default_server = addr[i].opt.default_server;
 
         proxy_protocol = lsopt->proxy_protocol || addr[i].opt.proxy_protocol;
+        protocols = lsopt->proxy_protocol;
+        protocols_prev = addr[i].opt.proxy_protocol;
 
 #if (NGX_HTTP_SSL)
         ssl = lsopt->ssl || addr[i].opt.ssl;
+        protocols |= lsopt->ssl << 1;
+        protocols_prev |= addr[i].opt.ssl << 1;
 #endif
 #if (NGX_HTTP_V2)
         http2 = lsopt->http2 || addr[i].opt.http2;
+        protocols |= lsopt->http2 << 2;
+        protocols_prev |= addr[i].opt.http2 << 2;
 #endif
 #if (NGX_HTTP_V3)
         http3 = lsopt->http3 || addr[i].opt.http3;
@@ -1311,6 +1318,57 @@ ngx_http_add_addresses(ngx_conf_t *cf, n
             addr[i].default_server = cscf;
         }
 
+        /* check for conflicting protocol options */
+
+        if ((protocols | protocols_prev) != protocols_prev) {
+
+            /* options added */
+
+            if ((addr[i].opt.set && !lsopt->set)
+                || addr[i].protocols_changed
+                || (protocols | protocols_prev) != protocols)
+            {
+                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                                   "protocol options redefined for %V",
+                                   &addr[i].opt.addr_text);
+            }
+
+            addr[i].protocols = protocols_prev;
+            addr[i].protocols_set = 1;
+            addr[i].protocols_changed = 1;
+
+        } else if ((protocols_prev | protocols) != protocols) {
+
+            /* options removed */
+
+            if (lsopt->set
+                || (addr[i].protocols_set && protocols != addr[i].protocols))
+            {
+                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                                   "protocol options redefined for %V",
+                                   &addr[i].opt.addr_text);
+            }
+
+            addr[i].protocols = protocols;
+            addr[i].protocols_set = 1;
+            addr[i].protocols_changed = 1;
+
+        } else {
+
+            /* the same options */
+
+            if ((lsopt->set && addr[i].protocols_changed)
+                || (addr[i].protocols_set && protocols != addr[i].protocols))
+            {
+                ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
+                                   "protocol options redefined for %V",
+                                   &addr[i].opt.addr_text);
+            }
+
+            addr[i].protocols = protocols;
+            addr[i].protocols_set = 1;
+        }
+
         addr[i].opt.default_server = default_server;
         addr[i].opt.proxy_protocol = proxy_protocol;
 #if (NGX_HTTP_SSL)
@@ -1371,6 +1429,9 @@ ngx_http_add_address(ngx_conf_t *cf, ngx
     }
 
     addr->opt = *lsopt;
+    addr->protocols = 0;
+    addr->protocols_set = 0;
+    addr->protocols_changed = 0;
     addr->hash.buckets = NULL;
     addr->hash.size = 0;
     addr->wc_head = NULL;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1803,10 +1803,6 @@ ngx_http_send_response(ngx_http_request_
         }
     }
 
-    if (r != r->main && val.len == 0) {
-        return ngx_http_send_header(r);
-    }
-
     b = ngx_calloc_buf(r->pool);
     if (b == NULL) {
         return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -1817,6 +1813,7 @@ ngx_http_send_response(ngx_http_request_
     b->memory = val.len ? 1 : 0;
     b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->memory) ? 0 : 1;
 
     out.buf = b;
     out.next = NULL;
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -280,6 +280,10 @@ typedef struct {
 typedef struct {
     ngx_http_listen_opt_t      opt;
 
+    unsigned                   protocols:3;
+    unsigned                   protocols_set:1;
+    unsigned                   protocols_changed:1;
+
     ngx_hash_t                 hash;
     ngx_hash_wildcard_t       *wc_head;
     ngx_hash_wildcard_t       *wc_tail;
@@ -469,8 +473,8 @@ struct ngx_http_location_tree_node_s {
     ngx_http_core_loc_conf_t        *exact;
     ngx_http_core_loc_conf_t        *inclusive;
 
+    u_short                          len;
     u_char                           auto_redirect;
-    u_char                           len;
     u_char                           name[1];
 };
 
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -1575,10 +1575,6 @@ ngx_http_cache_send(ngx_http_request_t *
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http file cache send: %s", c->file.name.data);
 
-    if (r != r->main && c->length - c->body_start == 0) {
-        return ngx_http_send_header(r);
-    }
-
     /* we need to allocate all before the header would be sent */
 
     b = ngx_calloc_buf(r->pool);
@@ -1600,9 +1596,10 @@ ngx_http_cache_send(ngx_http_request_t *
     b->file_pos = c->body_start;
     b->file_last = c->length;
 
-    b->in_file = (c->length - c->body_start) ? 1: 0;
-    b->last_buf = (r == r->main) ? 1: 0;
+    b->in_file = (c->length - c->body_start) ? 1 : 0;
+    b->last_buf = (r == r->main) ? 1 : 0;
     b->last_in_chain = 1;
+    b->sync = (b->last_buf || b->in_file) ? 0 : 1;
 
     b->file->fd = c->file.fd;
     b->file->name = c->file.name;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2770,7 +2770,8 @@ ngx_http_finalize_connection(ngx_http_re
         || (clcf->lingering_close == NGX_HTTP_LINGERING_ON
             && (r->lingering_close
                 || r->header_in->pos < r->header_in->last
-                || r->connection->read->ready)))
+                || r->connection->read->ready
+                || r->connection->pipeline)))
     {
         ngx_http_set_lingering_close(r->connection);
         return;
@@ -3154,6 +3155,7 @@ ngx_http_set_keepalive(ngx_http_request_
 
         c->sent = 0;
         c->destroyed = 0;
+        c->pipeline = 1;
 
         if (rev->timer_set) {
             ngx_del_timer(rev);
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -1730,6 +1730,7 @@ ngx_http_v2_state_process_header(ngx_htt
     size_t                      len;
     ngx_int_t                   rc;
     ngx_table_elt_t            *h;
+    ngx_connection_t           *fc;
     ngx_http_header_t          *hh;
     ngx_http_request_t         *r;
     ngx_http_v2_header_t       *header;
@@ -1789,17 +1790,11 @@ ngx_http_v2_state_process_header(ngx_htt
     }
 
     r = h2c->state.stream->request;
+    fc = r->connection;
 
     /* TODO Optimization: validate headers while parsing. */
     if (ngx_http_v2_validate_header(r, header) != NGX_OK) {
-        if (ngx_http_v2_terminate_stream(h2c, h2c->state.stream,
-                                         NGX_HTTP_V2_PROTOCOL_ERROR)
-            == NGX_ERROR)
-        {
-            return ngx_http_v2_connection_error(h2c,
-                                                NGX_HTTP_V2_INTERNAL_ERROR);
-        }
-
+        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
         goto error;
     }
 
@@ -1886,6 +1881,8 @@ error:
 
     h2c->state.stream = NULL;
 
+    ngx_http_run_posted_requests(fc);
+
     return ngx_http_v2_state_header_complete(h2c, pos, end);
 }
 
--- a/src/mail/ngx_mail_proxy_module.c
+++ b/src/mail/ngx_mail_proxy_module.c
@@ -327,7 +327,9 @@ ngx_mail_proxy_pop3_handler(ngx_event_t 
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
 
-        if (s->buffer->pos < s->buffer->last) {
+        if (s->buffer->pos < s->buffer->last
+            || s->connection->read->ready)
+        {
             ngx_post_event(c->write, &ngx_posted_events);
         }
 
@@ -486,7 +488,9 @@ ngx_mail_proxy_imap_handler(ngx_event_t 
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
 
-        if (s->buffer->pos < s->buffer->last) {
+        if (s->buffer->pos < s->buffer->last
+            || s->connection->read->ready)
+        {
             ngx_post_event(c->write, &ngx_posted_events);
         }
 
@@ -821,7 +825,9 @@ ngx_mail_proxy_smtp_handler(ngx_event_t 
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
 
-        if (s->buffer->pos < s->buffer->last) {
+        if (s->buffer->pos < s->buffer->last
+            || s->connection->read->ready)
+        {
             ngx_post_event(c->write, &ngx_posted_events);
         }
 
--- a/src/mail/ngx_mail_ssl_module.c
+++ b/src/mail/ngx_mail_ssl_module.c
@@ -360,8 +360,9 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, 
                          prev->prefer_server_ciphers, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
-                         (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                          |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                         (NGX_CONF_BITMASK_SET
+                          |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                          |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);
--- a/src/os/win32/ngx_files.c
+++ b/src/os/win32/ngx_files.c
@@ -10,10 +10,15 @@
 
 
 #define NGX_UTF16_BUFLEN  256
+#define NGX_UTF8_BUFLEN   512
 
-static ngx_int_t ngx_win32_check_filename(u_char *name, u_short *u,
-    size_t len);
-static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len);
+static ngx_int_t ngx_win32_check_filename(u_short *u, size_t len,
+    ngx_uint_t dirname);
+static u_short *ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len,
+    size_t reserved);
+static u_char *ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len,
+    size_t *allocated);
+uint32_t ngx_utf16_decode(u_short **u, size_t n);
 
 
 /* FILE_FLAG_BACKUP_SEMANTICS allows to obtain a handle to a directory */
@@ -28,7 +33,7 @@ ngx_open_file(u_char *name, u_long mode,
     u_short     utf16[NGX_UTF16_BUFLEN];
 
     len = NGX_UTF16_BUFLEN;
-    u = ngx_utf8_to_utf16(utf16, name, &len);
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
 
     if (u == NULL) {
         return INVALID_HANDLE_VALUE;
@@ -37,7 +42,7 @@ ngx_open_file(u_char *name, u_long mode,
     fd = INVALID_HANDLE_VALUE;
 
     if (create == NGX_FILE_OPEN
-        && ngx_win32_check_filename(name, u, len) != NGX_OK)
+        && ngx_win32_check_filename(u, len, 0) != NGX_OK)
     {
         goto failed;
     }
@@ -58,6 +63,41 @@ failed:
 }
 
 
+ngx_fd_t
+ngx_open_tempfile(u_char *name, ngx_uint_t persistent, ngx_uint_t access)
+{
+    size_t      len;
+    u_short    *u;
+    ngx_fd_t    fd;
+    ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return INVALID_HANDLE_VALUE;
+    }
+
+    fd = CreateFileW(u,
+                     GENERIC_READ|GENERIC_WRITE,
+                     FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+                     NULL,
+                     CREATE_NEW,
+                     persistent ? 0:
+                         FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,
+                     NULL);
+
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
+    }
+
+    return fd;
+}
+
+
 ssize_t
 ngx_read_file(ngx_file_t *file, u_char *buf, size_t size, off_t offset)
 {
@@ -202,6 +242,97 @@ ngx_write_console(ngx_fd_t fd, void *buf
 }
 
 
+ngx_int_t
+ngx_delete_file(u_char *name)
+{
+    long        rc;
+    size_t      len;
+    u_short    *u;
+    ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return NGX_FILE_ERROR;
+    }
+
+    rc = NGX_FILE_ERROR;
+
+    if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
+        goto failed;
+    }
+
+    rc = DeleteFileW(u);
+
+failed:
+
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
+    }
+
+    return rc;
+}
+
+
+ngx_int_t
+ngx_rename_file(u_char *from, u_char *to)
+{
+    long        rc;
+    size_t      len;
+    u_short    *fu, *tu;
+    ngx_err_t   err;
+    u_short     utf16f[NGX_UTF16_BUFLEN];
+    u_short     utf16t[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    fu = ngx_utf8_to_utf16(utf16f, from, &len, 0);
+
+    if (fu == NULL) {
+        return NGX_FILE_ERROR;
+    }
+
+    rc = NGX_FILE_ERROR;
+    tu = NULL;
+
+    if (ngx_win32_check_filename(fu, len, 0) != NGX_OK) {
+        goto failed;
+    }
+
+    len = NGX_UTF16_BUFLEN;
+    tu = ngx_utf8_to_utf16(utf16t, to, &len, 0);
+
+    if (tu == NULL) {
+        goto failed;
+    }
+
+    if (ngx_win32_check_filename(tu, len, 1) != NGX_OK) {
+        goto failed;
+    }
+
+    rc = MoveFileW(fu, tu);
+
+failed:
+
+    if (fu != utf16f) {
+        err = ngx_errno;
+        ngx_free(fu);
+        ngx_set_errno(err);
+    }
+
+    if (tu && tu != utf16t) {
+        err = ngx_errno;
+        ngx_free(tu);
+        ngx_set_errno(err);
+    }
+
+    return rc;
+}
+
+
 ngx_err_t
 ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log)
 {
@@ -227,28 +358,36 @@ ngx_win32_rename_file(ngx_str_t *from, n
 
         ngx_sprintf(name + to->len, ".%0muA.DELETE%Z", num);
 
-        if (MoveFile((const char *) to->data, (const char *) name) != 0) {
+        if (ngx_rename_file(to->data, name) != NGX_FILE_ERROR) {
             break;
         }
 
-        collision = 1;
+        err = ngx_errno;
 
-        ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
+        if (err == NGX_EEXIST || err == NGX_EEXIST_FILE) {
+            collision = 1;
+            continue;
+        }
+
+        ngx_log_error(NGX_LOG_CRIT, log, err,
                       "MoveFile() \"%s\" to \"%s\" failed", to->data, name);
+        goto failed;
     }
 
-    if (MoveFile((const char *) from->data, (const char *) to->data) == 0) {
+    if (ngx_rename_file(from->data, to->data) == NGX_FILE_ERROR) {
         err = ngx_errno;
 
     } else {
         err = 0;
     }
 
-    if (DeleteFile((const char *) name) == 0) {
+    if (ngx_delete_file(name) == NGX_FILE_ERROR) {
         ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                       "DeleteFile() \"%s\" failed", name);
     }
 
+failed:
+
     /* mutex_unlock() */
 
     ngx_free(name);
@@ -269,7 +408,7 @@ ngx_file_info(u_char *file, ngx_file_inf
 
     len = NGX_UTF16_BUFLEN;
 
-    u = ngx_utf8_to_utf16(utf16, file, &len);
+    u = ngx_utf8_to_utf16(utf16, file, &len, 0);
 
     if (u == NULL) {
         return NGX_FILE_ERROR;
@@ -277,7 +416,7 @@ ngx_file_info(u_char *file, ngx_file_inf
 
     rc = NGX_FILE_ERROR;
 
-    if (ngx_win32_check_filename(file, u, len) != NGX_OK) {
+    if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
         goto failed;
     }
 
@@ -424,52 +563,88 @@ ngx_realpath(u_char *path, u_char *resol
 }
 
 
+size_t
+ngx_getcwd(u_char *buf, size_t size)
+{
+    u_char   *p;
+    size_t    n;
+    u_short   utf16[NGX_MAX_PATH];
+
+    n = GetCurrentDirectoryW(NGX_MAX_PATH, utf16);
+
+    if (n == 0) {
+        return 0;
+    }
+
+    if (n > NGX_MAX_PATH) {
+        ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+
+    p = ngx_utf16_to_utf8(buf, utf16, &size, NULL);
+
+    if (p == NULL) {
+        return 0;
+    }
+
+    if (p != buf) {
+        ngx_free(p);
+        ngx_set_errno(ERROR_INSUFFICIENT_BUFFER);
+        return 0;
+    }
+
+    return size - 1;
+}
+
+
 ngx_int_t
 ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir)
 {
-    u_char     *pattern, *p;
+    size_t      len;
+    u_short    *u, *p;
     ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
 
-    pattern = malloc(name->len + 3);
-    if (pattern == NULL) {
+    len = NGX_UTF16_BUFLEN - 2;
+    u = ngx_utf8_to_utf16(utf16, name->data, &len, 2);
+
+    if (u == NULL) {
         return NGX_ERROR;
     }
 
-    p = ngx_cpymem(pattern, name->data, name->len);
+    if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
+        goto failed;
+    }
+
+    p = &u[len - 1];
 
     *p++ = '/';
     *p++ = '*';
     *p = '\0';
 
-    dir->dir = FindFirstFile((const char *) pattern, &dir->finddata);
+    dir->dir = FindFirstFileW(u, &dir->finddata);
 
     if (dir->dir == INVALID_HANDLE_VALUE) {
-        err = ngx_errno;
-        ngx_free(pattern);
-        ngx_set_errno(err);
-        return NGX_ERROR;
+        goto failed;
     }
 
-    ngx_free(pattern);
+    if (u != utf16) {
+        ngx_free(u);
+    }
 
     dir->valid_info = 1;
     dir->ready = 1;
+    dir->name = NULL;
+    dir->allocated = 0;
 
     return NGX_OK;
-}
 
+failed:
 
-ngx_int_t
-ngx_read_dir(ngx_dir_t *dir)
-{
-    if (dir->ready) {
-        dir->ready = 0;
-        return NGX_OK;
-    }
-
-    if (FindNextFile(dir->dir, &dir->finddata) != 0) {
-        dir->type = 1;
-        return NGX_OK;
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
     }
 
     return NGX_ERROR;
@@ -477,8 +652,57 @@ ngx_read_dir(ngx_dir_t *dir)
 
 
 ngx_int_t
+ngx_read_dir(ngx_dir_t *dir)
+{
+    u_char  *name;
+    size_t   len, allocated;
+
+    if (dir->ready) {
+        dir->ready = 0;
+        goto convert;
+    }
+
+    if (FindNextFileW(dir->dir, &dir->finddata) != 0) {
+        dir->type = 1;
+        goto convert;
+    }
+
+    return NGX_ERROR;
+
+convert:
+
+    name = dir->name;
+    len = dir->allocated;
+
+    name = ngx_utf16_to_utf8(name, dir->finddata.cFileName, &len, &allocated);
+
+    if (name == NULL) {
+        return NGX_ERROR;
+    }
+
+    if (name != dir->name) {
+
+        if (dir->name) {
+            ngx_free(dir->name);
+        }
+
+        dir->name = name;
+        dir->allocated = allocated;
+    }
+
+    dir->namelen = len - 1;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_close_dir(ngx_dir_t *dir)
 {
+    if (dir->name) {
+        ngx_free(dir->name);
+    }
+
     if (FindClose(dir->dir) == 0) {
         return NGX_ERROR;
     }
@@ -488,18 +712,103 @@ ngx_close_dir(ngx_dir_t *dir)
 
 
 ngx_int_t
+ngx_create_dir(u_char *name, ngx_uint_t access)
+{
+    long        rc;
+    size_t      len;
+    u_short    *u;
+    ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return NGX_FILE_ERROR;
+    }
+
+    rc = NGX_FILE_ERROR;
+
+    if (ngx_win32_check_filename(u, len, 1) != NGX_OK) {
+        goto failed;
+    }
+
+    rc = CreateDirectoryW(u, NULL);
+
+failed:
+
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
+    }
+
+    return rc;
+}
+
+
+ngx_int_t
+ngx_delete_dir(u_char *name)
+{
+    long        rc;
+    size_t      len;
+    u_short    *u;
+    ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return NGX_FILE_ERROR;
+    }
+
+    rc = NGX_FILE_ERROR;
+
+    if (ngx_win32_check_filename(u, len, 0) != NGX_OK) {
+        goto failed;
+    }
+
+    rc = RemoveDirectoryW(u);
+
+failed:
+
+    if (u != utf16) {
+        err = ngx_errno;
+        ngx_free(u);
+        ngx_set_errno(err);
+    }
+
+    return rc;
+}
+
+
+ngx_int_t
 ngx_open_glob(ngx_glob_t *gl)
 {
     u_char     *p;
     size_t      len;
+    u_short    *u;
     ngx_err_t   err;
+    u_short     utf16[NGX_UTF16_BUFLEN];
 
-    gl->dir = FindFirstFile((const char *) gl->pattern, &gl->finddata);
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, gl->pattern, &len, 0);
+
+    if (u == NULL) {
+        return NGX_ERROR;
+    }
+
+    gl->dir = FindFirstFileW(u, &gl->finddata);
 
     if (gl->dir == INVALID_HANDLE_VALUE) {
 
         err = ngx_errno;
 
+        if (u != utf16) {
+            ngx_free(u);
+        }
+
         if ((err == ERROR_FILE_NOT_FOUND || err == ERROR_PATH_NOT_FOUND)
              && gl->test)
         {
@@ -507,6 +816,8 @@ ngx_open_glob(ngx_glob_t *gl)
             return NGX_OK;
         }
 
+        ngx_set_errno(err);
+
         return NGX_ERROR;
     }
 
@@ -516,18 +827,10 @@ ngx_open_glob(ngx_glob_t *gl)
         }
     }
 
-    len = ngx_strlen(gl->finddata.cFileName);
-    gl->name.len = gl->last + len;
-
-    gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
-    if (gl->name.data == NULL) {
-        return NGX_ERROR;
+    if (u != utf16) {
+        ngx_free(u);
     }
 
-    ngx_memcpy(gl->name.data, gl->pattern, gl->last);
-    ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName,
-                len + 1);
-
     gl->ready = 1;
 
     return NGX_OK;
@@ -537,40 +840,25 @@ ngx_open_glob(ngx_glob_t *gl)
 ngx_int_t
 ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name)
 {
-    size_t     len;
-    ngx_err_t  err;
+    u_char     *p;
+    size_t      len;
+    ngx_err_t   err;
+    u_char      utf8[NGX_UTF8_BUFLEN];
 
     if (gl->no_match) {
         return NGX_DONE;
     }
 
     if (gl->ready) {
-        *name = gl->name;
-
         gl->ready = 0;
-        return NGX_OK;
+        goto convert;
     }
 
     ngx_free(gl->name.data);
     gl->name.data = NULL;
 
-    if (FindNextFile(gl->dir, &gl->finddata) != 0) {
-
-        len = ngx_strlen(gl->finddata.cFileName);
-        gl->name.len = gl->last + len;
-
-        gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
-        if (gl->name.data == NULL) {
-            return NGX_ERROR;
-        }
-
-        ngx_memcpy(gl->name.data, gl->pattern, gl->last);
-        ngx_cpystrn(gl->name.data + gl->last, (u_char *) gl->finddata.cFileName,
-                    len + 1);
-
-        *name = gl->name;
-
-        return NGX_OK;
+    if (FindNextFileW(gl->dir, &gl->finddata) != 0) {
+        goto convert;
     }
 
     err = ngx_errno;
@@ -583,6 +871,43 @@ ngx_read_glob(ngx_glob_t *gl, ngx_str_t 
                   "FindNextFile(%s) failed", gl->pattern);
 
     return NGX_ERROR;
+
+convert:
+
+    len = NGX_UTF8_BUFLEN;
+    p = ngx_utf16_to_utf8(utf8, gl->finddata.cFileName, &len, NULL);
+
+    if (p == NULL) {
+        return NGX_ERROR;
+    }
+
+    gl->name.len = gl->last + len - 1;
+
+    gl->name.data = ngx_alloc(gl->name.len + 1, gl->log);
+    if (gl->name.data == NULL) {
+        goto failed;
+    }
+
+    ngx_memcpy(gl->name.data, gl->pattern, gl->last);
+    ngx_cpystrn(gl->name.data + gl->last, p, len);
+
+    if (p != utf8) {
+        ngx_free(p);
+    }
+
+    *name = gl->name;
+
+    return NGX_OK;
+
+failed:
+
+    if (p != utf8) {
+        err = ngx_errno;
+        ngx_free(p);
+        ngx_set_errno(err);
+    }
+
+    return NGX_ERROR;
 }
 
 
@@ -642,18 +967,31 @@ ngx_directio_off(ngx_fd_t fd)
 size_t
 ngx_fs_bsize(u_char *name)
 {
-    u_char  root[4];
-    u_long  sc, bs, nfree, ncl;
+    u_long    sc, bs, nfree, ncl;
+    size_t    len;
+    u_short  *u;
+    u_short   utf16[NGX_UTF16_BUFLEN];
 
-    if (name[2] == ':') {
-        ngx_cpystrn(root, name, 4);
-        name = root;
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return 512;
     }
 
-    if (GetDiskFreeSpace((const char *) name, &sc, &bs, &nfree, &ncl) == 0) {
+    if (GetDiskFreeSpaceW(u, &sc, &bs, &nfree, &ncl) == 0) {
+
+        if (u != utf16) {
+            ngx_free(u);
+        }
+
         return 512;
     }
 
+    if (u != utf16) {
+        ngx_free(u);
+    }
+
     return sc * bs;
 }
 
@@ -661,22 +999,40 @@ ngx_fs_bsize(u_char *name)
 off_t
 ngx_fs_available(u_char *name)
 {
-    ULARGE_INTEGER  navail;
+    size_t           len;
+    u_short         *u;
+    ULARGE_INTEGER   navail;
+    u_short          utf16[NGX_UTF16_BUFLEN];
+
+    len = NGX_UTF16_BUFLEN;
+    u = ngx_utf8_to_utf16(utf16, name, &len, 0);
+
+    if (u == NULL) {
+        return NGX_MAX_OFF_T_VALUE;
+    }
 
-    if (GetDiskFreeSpaceEx((const char *) name, &navail, NULL, NULL) == 0) {
+    if (GetDiskFreeSpaceExW(u, &navail, NULL, NULL) == 0) {
+
+        if (u != utf16) {
+            ngx_free(u);
+        }
+
         return NGX_MAX_OFF_T_VALUE;
     }
 
+    if (u != utf16) {
+        ngx_free(u);
+    }
+
     return (off_t) navail.QuadPart;
 }
 
 
 static ngx_int_t
-ngx_win32_check_filename(u_char *name, u_short *u, size_t len)
+ngx_win32_check_filename(u_short *u, size_t len, ngx_uint_t dirname)
 {
-    u_char     *p, ch;
     u_long      n;
-    u_short    *lu;
+    u_short    *lu, *p, *slash, ch;
     ngx_err_t   err;
     enum {
         sw_start = 0,
@@ -689,9 +1045,14 @@ ngx_win32_check_filename(u_char *name, u
     /* check for NTFS streams (":"), trailing dots and spaces */
 
     lu = NULL;
+    slash = NULL;
     state = sw_start;
 
-    for (p = name; *p; p++) {
+#if (NGX_SUPPRESS_WARN)
+    ch = 0;
+#endif
+
+    for (p = u; *p; p++) {
         ch = *p;
 
         switch (state) {
@@ -705,6 +1066,7 @@ ngx_win32_check_filename(u_char *name, u
 
             if (ch == '/' || ch == '\\') {
                 state = sw_after_slash;
+                slash = p;
             }
 
             break;
@@ -723,6 +1085,7 @@ ngx_win32_check_filename(u_char *name, u
 
             if (ch == '/' || ch == '\\') {
                 state = sw_after_slash;
+                slash = p;
                 break;
             }
 
@@ -750,6 +1113,7 @@ ngx_win32_check_filename(u_char *name, u
 
             if (ch == '/' || ch == '\\') {
                 state = sw_after_slash;
+                slash = p;
                 break;
             }
 
@@ -778,6 +1142,12 @@ ngx_win32_check_filename(u_char *name, u
         goto invalid;
     }
 
+    if (dirname && slash) {
+        ch = *slash;
+        *slash = '\0';
+        len = slash - u + 1;
+    }
+
     /* check if long name match */
 
     lu = malloc(len * 2);
@@ -788,6 +1158,11 @@ ngx_win32_check_filename(u_char *name, u
     n = GetLongPathNameW(u, lu, len);
 
     if (n == 0) {
+
+        if (dirname && slash && ngx_errno == NGX_ENOENT) {
+            ngx_set_errno(NGX_ENOPATH);
+        }
+
         goto failed;
     }
 
@@ -795,6 +1170,10 @@ ngx_win32_check_filename(u_char *name, u
         goto invalid;
     }
 
+    if (dirname && slash) {
+        *slash = ch;
+    }
+
     ngx_free(lu);
 
     return NGX_OK;
@@ -805,6 +1184,10 @@ invalid:
 
 failed:
 
+    if (dirname && slash) {
+        *slash = ch;
+    }
+
     if (lu) {
         err = ngx_errno;
         ngx_free(lu);
@@ -816,7 +1199,7 @@ failed:
 
 
 static u_short *
-ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len)
+ngx_utf8_to_utf16(u_short *utf16, u_char *utf8, size_t *len, size_t reserved)
 {
     u_char    *p;
     u_short   *u, *last;
@@ -865,7 +1248,7 @@ ngx_utf8_to_utf16(u_short *utf16, u_char
 
     /* the given buffer is not enough, allocate a new one */
 
-    u = malloc(((p - utf8) + ngx_strlen(p) + 1) * sizeof(u_short));
+    u = malloc(((p - utf8) + ngx_strlen(p) + 1 + reserved) * sizeof(u_short));
     if (u == NULL) {
         return NULL;
     }
@@ -910,3 +1293,167 @@ ngx_utf8_to_utf16(u_short *utf16, u_char
 
     /* unreachable */
 }
+
+
+static u_char *
+ngx_utf16_to_utf8(u_char *utf8, u_short *utf16, size_t *len, size_t *allocated)
+{
+    u_char    *p, *last;
+    u_short   *u, *j;
+    uint32_t   n;
+
+    u = utf16;
+    p = utf8;
+    last = utf8 + *len;
+
+    while (p < last) {
+
+        if (*u < 0x80) {
+            *p++ = (u_char) *u;
+
+            if (*u == 0) {
+                *len = p - utf8;
+                return utf8;
+            }
+
+            u++;
+
+            continue;
+        }
+
+        if (p >= last - 4) {
+            *len = p - utf8;
+            break;
+        }
+
+        n = ngx_utf16_decode(&u, 2);
+
+        if (n > 0x10ffff) {
+            ngx_set_errno(NGX_EILSEQ);
+            return NULL;
+        }
+
+        if (n >= 0x10000) {
+            *p++ = (u_char) (0xf0 + (n >> 18));
+            *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f));
+            *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
+            *p++ = (u_char) (0x80 + (n & 0x3f));
+            continue;
+        }
+
+        if (n >= 0x0800) {
+            *p++ = (u_char) (0xe0 + (n >> 12));
+            *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
+            *p++ = (u_char) (0x80 + (n & 0x3f));
+            continue;
+        }
+
+        *p++ = (u_char) (0xc0 + (n >> 6));
+        *p++ = (u_char) (0x80 + (n & 0x3f));
+    }
+
+    /* the given buffer is not enough, allocate a new one */
+
+    for (j = u; *j; j++) { /* void */ }
+
+    p = malloc((j - utf16) * 4 + 1);
+    if (p == NULL) {
+        return NULL;
+    }
+
+    if (allocated) {
+        *allocated = (j - utf16) * 4 + 1;
+    }
+
+    ngx_memcpy(p, utf8, *len);
+
+    utf8 = p;
+    p += *len;
+
+    for ( ;; ) {
+
+        if (*u < 0x80) {
+            *p++ = (u_char) *u;
+
+            if (*u == 0) {
+                *len = p - utf8;
+                return utf8;
+            }
+
+            u++;
+
+            continue;
+        }
+
+        n = ngx_utf16_decode(&u, 2);
+
+        if (n > 0x10ffff) {
+            ngx_free(utf8);
+            ngx_set_errno(NGX_EILSEQ);
+            return NULL;
+        }
+
+        if (n >= 0x10000) {
+            *p++ = (u_char) (0xf0 + (n >> 18));
+            *p++ = (u_char) (0x80 + ((n >> 12) & 0x3f));
+            *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
+            *p++ = (u_char) (0x80 + (n & 0x3f));
+            continue;
+        }
+
+        if (n >= 0x0800) {
+            *p++ = (u_char) (0xe0 + (n >> 12));
+            *p++ = (u_char) (0x80 + ((n >> 6) & 0x3f));
+            *p++ = (u_char) (0x80 + (n & 0x3f));
+            continue;
+        }
+
+        *p++ = (u_char) (0xc0 + (n >> 6));
+        *p++ = (u_char) (0x80 + (n & 0x3f));
+    }
+
+    /* unreachable */
+}
+
+
+/*
+ * ngx_utf16_decode() decodes one or two UTF-16 code units
+ * the return values:
+ *    0x80 - 0x10ffff         valid character
+ *    0x110000 - 0xfffffffd   invalid sequence
+ *    0xfffffffe              incomplete sequence
+ *    0xffffffff              error
+ */
+
+uint32_t
+ngx_utf16_decode(u_short **u, size_t n)
+{
+    uint32_t  k, m;
+
+    k = **u;
+
+    if (k < 0xd800 || k > 0xdfff) {
+        (*u)++;
+        return k;
+    }
+
+    if (k > 0xdbff) {
+        (*u)++;
+        return 0xffffffff;
+    }
+
+    if (n < 2) {
+        return 0xfffffffe;
+    }
+
+    (*u)++;
+
+    m = *(*u)++;
+
+    if (m < 0xdc00 || m > 0xdfff) {
+        return 0xffffffff;
+
+    }
+
+    return 0x10000 + ((k - 0xd800) << 10) + (m - 0xdc00);
+}
--- a/src/os/win32/ngx_files.h
+++ b/src/os/win32/ngx_files.h
@@ -30,7 +30,11 @@ typedef struct {
 
 typedef struct {
     HANDLE                          dir;
-    WIN32_FIND_DATA                 finddata;
+    WIN32_FIND_DATAW                finddata;
+
+    u_char                         *name;
+    size_t                          namelen;
+    size_t                          allocated;
 
     unsigned                        valid_info:1;
     unsigned                        type:1;
@@ -40,7 +44,7 @@ typedef struct {
 
 typedef struct {
     HANDLE                          dir;
-    WIN32_FIND_DATA                 finddata;
+    WIN32_FIND_DATAW                finddata;
 
     unsigned                        ready:1;
     unsigned                        test:1;
@@ -86,16 +90,8 @@ ngx_fd_t ngx_open_file(u_char *name, u_l
 #define NGX_FILE_OWNER_ACCESS       0
 
 
-#define ngx_open_tempfile(name, persistent, access)                          \
-    CreateFile((const char *) name,                                          \
-               GENERIC_READ|GENERIC_WRITE,                                   \
-               FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,           \
-               NULL,                                                         \
-               CREATE_NEW,                                                   \
-               persistent ? 0:                                               \
-                   FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,       \
-               NULL);
-
+ngx_fd_t ngx_open_tempfile(u_char *name, ngx_uint_t persistent,
+    ngx_uint_t access);
 #define ngx_open_tempfile_n         "CreateFile()"
 
 
@@ -119,11 +115,11 @@ ssize_t ngx_write_console(ngx_fd_t fd, v
 #define NGX_LINEFEED                CRLF
 
 
-#define ngx_delete_file(name)       DeleteFile((const char *) name)
+ngx_int_t ngx_delete_file(u_char *name);
 #define ngx_delete_file_n           "DeleteFile()"
 
 
-#define ngx_rename_file(o, n)       MoveFile((const char *) o, (const char *) n)
+ngx_int_t ngx_rename_file(u_char *from, u_char *to);
 #define ngx_rename_file_n           "MoveFile()"
 ngx_err_t ngx_win32_rename_file(ngx_str_t *from, ngx_str_t *to, ngx_log_t *log);
 
@@ -174,8 +170,12 @@ void ngx_close_file_mapping(ngx_file_map
 
 u_char *ngx_realpath(u_char *path, u_char *resolved);
 #define ngx_realpath_n              ""
-#define ngx_getcwd(buf, size)       GetCurrentDirectory(size, (char *) buf)
+
+
+size_t ngx_getcwd(u_char *buf, size_t size);
 #define ngx_getcwd_n                "GetCurrentDirectory()"
+
+
 #define ngx_path_separator(c)       ((c) == '/' || (c) == '\\')
 
 #define NGX_HAVE_MAX_PATH           1
@@ -194,19 +194,19 @@ ngx_int_t ngx_close_dir(ngx_dir_t *dir);
 #define ngx_close_dir_n             "FindClose()"
 
 
-#define ngx_create_dir(name, access) CreateDirectory((const char *) name, NULL)
+ngx_int_t ngx_create_dir(u_char *name, ngx_uint_t access);
 #define ngx_create_dir_n            "CreateDirectory()"
 
 
-#define ngx_delete_dir(name)        RemoveDirectory((const char *) name)
+ngx_int_t ngx_delete_dir(u_char *name);
 #define ngx_delete_dir_n            "RemoveDirectory()"
 
 
 #define ngx_dir_access(a)           (a)
 
 
-#define ngx_de_name(dir)            ((u_char *) (dir)->finddata.cFileName)
-#define ngx_de_namelen(dir)         ngx_strlen((dir)->finddata.cFileName)
+#define ngx_de_name(dir)            (dir)->name
+#define ngx_de_namelen(dir)         (dir)->namelen
 
 ngx_int_t ngx_de_info(u_char *name, ngx_dir_t *dir);
 #define ngx_de_info_n               "dummy()"
--- a/src/stream/ngx_stream_proxy_module.c
+++ b/src/stream/ngx_stream_proxy_module.c
@@ -2178,8 +2178,9 @@ ngx_stream_proxy_merge_srv_conf(ngx_conf
                               prev->ssl_session_reuse, 1);
 
     ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols,
-                              (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                               |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                              (NGX_CONF_BITMASK_SET
+                               |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                               |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, "DEFAULT");
 
--- a/src/stream/ngx_stream_ssl_module.c
+++ b/src/stream/ngx_stream_ssl_module.c
@@ -707,8 +707,9 @@ ngx_stream_ssl_merge_conf(ngx_conf_t *cf
                          prev->prefer_server_ciphers, 0);
 
     ngx_conf_merge_bitmask_value(conf->protocols, prev->protocols,
-                         (NGX_CONF_BITMASK_SET|NGX_SSL_TLSv1
-                          |NGX_SSL_TLSv1_1|NGX_SSL_TLSv1_2));
+                         (NGX_CONF_BITMASK_SET
+                          |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1
+                          |NGX_SSL_TLSv1_2|NGX_SSL_TLSv1_3));
 
     ngx_conf_merge_uint_value(conf->verify, prev->verify, 0);
     ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1);