From 3728f9d233022851506d79b5be0df51d0e1c9984 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Fri, 9 Nov 2018 11:15:05 +0200
Subject: [PATCH 001/334] Release 1.14.1-1~bpo9+1
---
debian/changelog | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index d08388f..58cc07d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+nginx (1.14.1-1~bpo9+1) stretch-backports; urgency=medium
+
+ * Rebuild for stretch-backports.
+
+ -- Christos Trochalakis Fri, 09 Nov 2018 11:14:54 +0200
+
nginx (1.14.1-1) unstable; urgency=medium
[ Kartik Mistry ]
From fd3bbc2f43a9fda3e781db2292fdfcaee1b29461 Mon Sep 17 00:00:00 2001
From: Olaf van der Spek
Date: Fri, 23 Nov 2018 13:34:13 +0100
Subject: [PATCH 002/334] Reference PHP 7.3 (Closes: 913250)
---
debian/conf/sites-available/default | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/conf/sites-available/default b/debian/conf/sites-available/default
index c841ceb..f5c5e1b 100644
--- a/debian/conf/sites-available/default
+++ b/debian/conf/sites-available/default
@@ -57,7 +57,7 @@ server {
# include snippets/fastcgi-php.conf;
#
# # With php-fpm (or other unix sockets):
- # fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
+ # fastcgi_pass unix:/run/php/php7.3-fpm.sock;
# # With php-cgi (or other tcp sockets):
# fastcgi_pass 127.0.0.1:9000;
#}
From 0b00911581718724d5fd0f03320f4eec5846e62e Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Tue, 20 Nov 2018 12:33:53 +0200
Subject: [PATCH 003/334] Adjust fastcgi_split_path_info snippet to handle the
`/example.php/` case
We switched to regexp suggest in Nginx docs found at
https://www.nginx.com/resources/wiki/start/topics/examples/phpfcgi/
Closes: #911398
---
debian/conf/snippets/fastcgi-php.conf | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/conf/snippets/fastcgi-php.conf b/debian/conf/snippets/fastcgi-php.conf
index 8f8e4a2..467a9e7 100644
--- a/debian/conf/snippets/fastcgi-php.conf
+++ b/debian/conf/snippets/fastcgi-php.conf
@@ -1,5 +1,5 @@
# regex to split $uri to $fastcgi_script_name and $fastcgi_path
-fastcgi_split_path_info ^(.+\.php)(/.+)$;
+fastcgi_split_path_info ^(.+?\.php)(/.*)$;
# Check that the PHP script exists before passing it
try_files $fastcgi_script_name =404;
From 6fac1fb9f0453cbf6539515ba78181f99de159c1 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Tue, 4 Dec 2018 17:22:42 +0200
Subject: [PATCH 004/334] New upstream version 1.14.2
---
CHANGES | 33 +++++
CHANGES.ru | 34 +++++
src/core/nginx.h | 4 +-
src/event/ngx_event_accept.c | 12 ++
src/event/ngx_event_openssl.c | 30 ++++-
src/event/ngx_event_openssl.h | 4 +
src/http/modules/ngx_http_fastcgi_module.c | 6 +-
src/http/modules/ngx_http_grpc_module.c | 142 ++++++++++++++-------
src/http/modules/ngx_http_mp4_module.c | 9 +-
src/http/modules/ngx_http_proxy_module.c | 3 +-
src/http/modules/ngx_http_scgi_module.c | 6 +-
src/http/modules/ngx_http_uwsgi_module.c | 6 +-
src/http/ngx_http_request.c | 2 +-
src/http/ngx_http_script.c | 13 +-
src/http/ngx_http_upstream.c | 15 ++-
src/os/unix/ngx_user.c | 4 -
src/stream/ngx_stream_script.c | 13 +-
17 files changed, 263 insertions(+), 73 deletions(-)
diff --git a/CHANGES b/CHANGES
index 590c0f4..597c270 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,37 @@
+Changes with nginx 1.14.2 04 Dec 2018
+
+ *) Bugfix: nginx could not be built by gcc 8.1.
+
+ *) Bugfix: nginx could not be built on Fedora 28 Linux.
+
+ *) Bugfix: in handling of client addresses when using unix domain listen
+ sockets to work with datagrams on Linux.
+
+ *) Change: the logging level of the "http request", "https proxy
+ request", "unsupported protocol", "version too low", "no suitable key
+ share", and "no suitable signature algorithm" SSL errors has been
+ lowered from "crit" to "info".
+
+ *) Bugfix: when using OpenSSL 1.1.0 or newer it was not possible to
+ switch off "ssl_prefer_server_ciphers" in a virtual server if it was
+ switched on in the default server.
+
+ *) Bugfix: nginx could not be built with LibreSSL 2.8.0.
+
+ *) Bugfix: if nginx was built with OpenSSL 1.1.0 and used with OpenSSL
+ 1.1.1, the TLS 1.3 protocol was always enabled.
+
+ *) Bugfix: sending a disk-buffered request body to a gRPC backend might
+ fail.
+
+ *) Bugfix: connections with some gRPC backends might not be cached when
+ using the "keepalive" directive.
+
+ *) Bugfix: a segmentation fault might occur in a worker process if the
+ ngx_http_mp4_module was used on 32-bit platforms.
+
+
Changes with nginx 1.14.1 06 Nov 2018
*) Security: when using HTTP/2 a client might cause excessive memory
diff --git a/CHANGES.ru b/CHANGES.ru
index 32bb931..8c260fe 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,38 @@
+Изменения в nginx 1.14.2 04.12.2018
+
+ *) Исправление: nginx не собирался gcc 8.1.
+
+ *) Исправление: nginx не собирался на Fedora 28 Linux.
+
+ *) Исправление: в обработке адресов клиентов при использовании unix
+ domain listen-сокетов для работы с датаграммами на Linux.
+
+ *) Изменение: уровень логгирования ошибок SSL "http request", "https
+ proxy request", "unsupported protocol", "version too low", "no
+ suitable key share" и "no suitable signature algorithm" понижен с
+ уровня crit до info.
+
+ *) Исправление: при использовании OpenSSL 1.1.0 и новее директиву
+ ssl_prefer_server_ciphers нельзя было выключить в виртуальном
+ сервере, если она была включена в сервере по умолчанию.
+
+ *) Исправление: nginx не собирался с LibreSSL 2.8.0.
+
+ *) Исправление: если nginx был собран с OpenSSL 1.1.0, а использовался с
+ OpenSSL 1.1.1, протокол TLS 1.3 всегда был разрешён.
+
+ *) Исправление: при отправке сохранённого на диск тела запроса на
+ gRPC-бэкенд могли возникать ошибки.
+
+ *) Исправление: соединения к некоторым gRPC-бэкендам могли не
+ кэшироваться при использовании директивы keepalive.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовался модуль ngx_http_mp4_module на 32-битных
+ платформах.
+
+
Изменения в nginx 1.14.1 06.11.2018
*) Безопасность: при использовании HTTP/2 клиент мог вызвать чрезмерное
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 4f67659..4fc92ac 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -9,8 +9,8 @@
#define _NGINX_H_INCLUDED_
-#define nginx_version 1014001
-#define NGINX_VERSION "1.14.1"
+#define nginx_version 1014002
+#define NGINX_VERSION "1.14.2"
#define NGINX_VER "nginx/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c
index 7756370..7e9f742 100644
--- a/src/event/ngx_event_accept.c
+++ b/src/event/ngx_event_accept.c
@@ -448,6 +448,18 @@ ngx_event_recvmsg(ngx_event_t *ev)
c->socklen = sizeof(ngx_sockaddr_t);
}
+ if (c->socklen == 0) {
+
+ /*
+ * on Linux recvmsg() returns zero msg_namelen
+ * when receiving packets from unbound AF_UNIX sockets
+ */
+
+ c->socklen = sizeof(struct sockaddr);
+ ngx_memzero(&sa, sizeof(struct sockaddr));
+ sa.sockaddr.sa_family = ls->sockaddr->sa_family;
+ }
+
#if (NGX_STAT_STUB)
(void) ngx_atomic_fetch_add(ngx_stat_active, 1);
#endif
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 88a6dbe..c4b51b5 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -296,7 +296,7 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
SSL_CTX_set_options(ssl->ctx, SSL_OP_SINGLE_DH_USE);
-#ifdef SSL_CTRL_CLEAR_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x009080dfL
/* only in 0.9.8m+ */
SSL_CTX_clear_options(ssl->ctx,
SSL_OP_NO_SSLv2|SSL_OP_NO_SSLv3|SSL_OP_NO_TLSv1);
@@ -330,6 +330,16 @@ ngx_ssl_create(ngx_ssl_t *ssl, ngx_uint_t protocols, void *data)
}
#endif
+#ifdef SSL_CTX_set_min_proto_version
+ SSL_CTX_set_min_proto_version(ssl->ctx, 0);
+ SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_2_VERSION);
+#endif
+
+#ifdef TLS1_3_VERSION
+ SSL_CTX_set_min_proto_version(ssl->ctx, 0);
+ SSL_CTX_set_max_proto_version(ssl->ctx, TLS1_3_VERSION);
+#endif
+
#ifdef SSL_OP_NO_COMPRESSION
SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_COMPRESSION);
#endif
@@ -2059,10 +2069,18 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
/* 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_NO_SUITABLE_SIGNATURE_ALGORITHM
+ || n == SSL_R_NO_SUITABLE_SIGNATURE_ALGORITHM /* 118 */
+#endif
|| n == SSL_R_BLOCK_CIPHER_PAD_IS_WRONG /* 129 */
|| n == SSL_R_DIGEST_CHECK_FAILED /* 149 */
|| n == SSL_R_ERROR_IN_RECEIVED_CIPHER_LIST /* 151 */
|| n == SSL_R_EXCESSIVE_MESSAGE_SIZE /* 152 */
+ || n == SSL_R_HTTPS_PROXY_REQUEST /* 155 */
+ || n == SSL_R_HTTP_REQUEST /* 156 */
|| n == SSL_R_LENGTH_MISMATCH /* 159 */
#ifdef SSL_R_NO_CIPHERS_PASSED
|| n == SSL_R_NO_CIPHERS_PASSED /* 182 */
@@ -2078,6 +2096,13 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
|| n == SSL_R_UNEXPECTED_RECORD /* 245 */
|| n == SSL_R_UNKNOWN_ALERT_TYPE /* 246 */
|| n == SSL_R_UNKNOWN_PROTOCOL /* 252 */
+#ifdef SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS
+ || n == SSL_R_NO_COMMON_SIGNATURE_ALGORITHMS /* 253 */
+#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 */
|| n == SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC /* 281 */
#ifdef SSL_R_RENEGOTIATE_EXT_TOO_LONG
@@ -2093,6 +2118,9 @@ ngx_ssl_connection_error(ngx_connection_t *c, int sslerr, ngx_err_t err,
#endif
#ifdef SSL_R_INAPPROPRIATE_FALLBACK
|| n == SSL_R_INAPPROPRIATE_FALLBACK /* 373 */
+#endif
+#ifdef SSL_R_VERSION_TOO_LOW
+ || n == SSL_R_VERSION_TOO_LOW /* 396 */
#endif
|| n == 1000 /* SSL_R_SSLV3_ALERT_CLOSE_NOTIFY */
#ifdef SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE
diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h
index 623d851..05d3291 100644
--- a/src/event/ngx_event_openssl.h
+++ b/src/event/ngx_event_openssl.h
@@ -36,8 +36,12 @@
#if (defined LIBRESSL_VERSION_NUMBER && OPENSSL_VERSION_NUMBER == 0x20000000L)
#undef OPENSSL_VERSION_NUMBER
+#if (LIBRESSL_VERSION_NUMBER >= 0x2080000fL)
+#define OPENSSL_VERSION_NUMBER 0x1010000fL
+#else
#define OPENSSL_VERSION_NUMBER 0x1000107fL
#endif
+#endif
#if (OPENSSL_VERSION_NUMBER >= 0x10100001L)
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index bc43f53..3eec1b7 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -3264,7 +3264,8 @@ ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
copy = ngx_array_push_n(params->lengths,
@@ -3273,7 +3274,8 @@ ngx_http_fastcgi_init_params(ngx_conf_t *cf, ngx_http_fastcgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].skip_empty;
diff --git a/src/http/modules/ngx_http_grpc_module.c b/src/http/modules/ngx_http_grpc_module.c
index 758f89e..62b33fd 100644
--- a/src/http/modules/ngx_http_grpc_module.c
+++ b/src/http/modules/ngx_http_grpc_module.c
@@ -112,8 +112,10 @@ typedef struct {
unsigned header_sent:1;
unsigned output_closed:1;
+ unsigned output_blocked:1;
unsigned parsing_headers:1;
unsigned end_stream:1;
+ unsigned done:1;
unsigned status:1;
ngx_http_request_t *request;
@@ -1075,8 +1077,10 @@ ngx_http_grpc_reinit_request(ngx_http_request_t *r)
ctx->state = 0;
ctx->header_sent = 0;
ctx->output_closed = 0;
+ ctx->output_blocked = 0;
ctx->parsing_headers = 0;
ctx->end_stream = 0;
+ ctx->done = 0;
ctx->status = 0;
ctx->connection = NULL;
@@ -1096,6 +1100,7 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
ngx_int_t rc;
ngx_uint_t next, last;
ngx_chain_t *cl, *out, **ll;
+ ngx_http_upstream_t *u;
ngx_http_grpc_ctx_t *ctx;
ngx_http_grpc_frame_t *f;
@@ -1410,6 +1415,36 @@ ngx_http_grpc_body_output_filter(void *data, ngx_chain_t *in)
rc = NGX_AGAIN;
}
+ if (rc == NGX_AGAIN) {
+ ctx->output_blocked = 1;
+
+ } else {
+ ctx->output_blocked = 0;
+ }
+
+ if (ctx->done) {
+
+ /*
+ * We have already got the response and were sending some additional
+ * control frames. Even if there is still something unsent, stop
+ * here anyway.
+ */
+
+ u = r->upstream;
+ u->length = 0;
+
+ if (ctx->in == NULL
+ && ctx->out == NULL
+ && ctx->output_closed
+ && !ctx->output_blocked
+ && ctx->state == ngx_http_grpc_st_start)
+ {
+ u->keepalive = 1;
+ }
+
+ ngx_post_event(u->peer.connection->read, &ngx_posted_events);
+ }
+
return rc;
}
@@ -1752,6 +1787,7 @@ ngx_http_grpc_process_header(ngx_http_request_t *r)
if (ctx->in == NULL
&& ctx->out == NULL
&& ctx->output_closed
+ && !ctx->output_blocked
&& b->last == b->pos)
{
u->keepalive = 1;
@@ -1835,6 +1871,34 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
rc = ngx_http_grpc_parse_frame(r, ctx, b);
if (rc == NGX_AGAIN) {
+
+ if (ctx->done) {
+
+ /*
+ * We have finished parsing the response and the
+ * remaining control frames. If there are unsent
+ * control frames, post a write event to send them.
+ */
+
+ if (ctx->out) {
+ ngx_post_event(u->peer.connection->write,
+ &ngx_posted_events);
+ return NGX_AGAIN;
+ }
+
+ u->length = 0;
+
+ if (ctx->in == NULL
+ && ctx->output_closed
+ && !ctx->output_blocked
+ && ctx->state == ngx_http_grpc_st_start)
+ {
+ u->keepalive = 1;
+ }
+
+ break;
+ }
+
return NGX_AGAIN;
}
@@ -1901,6 +1965,13 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR;
}
+ if (ctx->stream_id && ctx->done) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "upstream sent frame for closed stream %ui",
+ ctx->stream_id);
+ return NGX_ERROR;
+ }
+
ctx->padding = 0;
}
@@ -1917,17 +1988,7 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
ctx->state = ngx_http_grpc_st_start;
if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- break;
+ ctx->done = 1;
}
continue;
@@ -2097,17 +2158,8 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
"grpc trailer done");
if (ctx->end_stream) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- return NGX_OK;
+ ctx->done = 1;
+ break;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
@@ -2124,6 +2176,10 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
return NGX_ERROR;
}
+ if (rc == NGX_HTTP_PARSE_HEADER_DONE) {
+ continue;
+ }
+
/* rc == NGX_AGAIN */
if (ctx->rest == 0) {
@@ -2240,17 +2296,7 @@ ngx_http_grpc_filter(void *data, ssize_t bytes)
ctx->state = ngx_http_grpc_st_start;
if (ctx->flags & NGX_HTTP_V2_END_STREAM_FLAG) {
- u->length = 0;
-
- if (ctx->in == NULL
- && ctx->out == NULL
- && ctx->output_closed
- && b->last == b->pos)
- {
- u->keepalive = 1;
- }
-
- break;
+ ctx->done = 1;
}
}
@@ -3883,6 +3929,7 @@ ngx_http_grpc_send_window_update(ngx_http_request_t *r,
static ngx_chain_t *
ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
{
+ u_char *start;
ngx_buf_t *b;
ngx_chain_t *cl;
@@ -3892,29 +3939,33 @@ ngx_http_grpc_get_buf(ngx_http_request_t *r, ngx_http_grpc_ctx_t *ctx)
}
b = cl->buf;
+ start = b->start;
- b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
- b->temporary = 1;
- b->flush = 1;
-
- if (b->start == NULL) {
+ if (start == NULL) {
/*
* each buffer is large enough to hold two window update
* frames in a row
*/
- b->start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8);
- if (b->start == NULL) {
+ start = ngx_palloc(r->pool, 2 * sizeof(ngx_http_grpc_frame_t) + 8);
+ if (start == NULL) {
return NULL;
}
- b->pos = b->start;
- b->last = b->start;
-
- b->end = b->start + 2 * sizeof(ngx_http_grpc_frame_t) + 8;
}
+ ngx_memzero(b, sizeof(ngx_buf_t));
+
+ b->start = start;
+ b->pos = start;
+ b->last = start;
+ b->end = start + 2 * sizeof(ngx_http_grpc_frame_t) + 8;
+
+ b->tag = (ngx_buf_tag_t) &ngx_http_grpc_body_output_filter;
+ b->temporary = 1;
+ b->flush = 1;
+
return cl;
}
@@ -4404,7 +4455,8 @@ ngx_http_grpc_init_headers(ngx_conf_t *cf, ngx_http_grpc_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
size = (sizeof(ngx_http_script_copy_code_t)
diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c
index 2a6fafa..618bf78 100644
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -169,7 +169,14 @@ typedef struct {
#define ngx_mp4_atom_next(mp4, n) \
- mp4->buffer_pos += (size_t) n; \
+ \
+ if (n > (size_t) (mp4->buffer_end - mp4->buffer_pos)) { \
+ mp4->buffer_pos = mp4->buffer_end; \
+ \
+ } else { \
+ mp4->buffer_pos += (size_t) n; \
+ } \
+ \
mp4->offset += n
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index c9ad638..e7f829d 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -3493,7 +3493,8 @@ ngx_http_proxy_init_headers(ngx_conf_t *cf, ngx_http_proxy_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
size = (sizeof(ngx_http_script_copy_code_t)
diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c
index 3fb227b..9bd45bd 100644
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -1724,7 +1724,8 @@ ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].key.len + 1;
copy = ngx_array_push_n(params->lengths,
@@ -1733,7 +1734,8 @@ ngx_http_scgi_init_params(ngx_conf_t *cf, ngx_http_scgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].skip_empty;
diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c
index 124da4d..238bcf8 100644
--- a/src/http/modules/ngx_http_uwsgi_module.c
+++ b/src/http/modules/ngx_http_uwsgi_module.c
@@ -1987,7 +1987,8 @@ ngx_http_uwsgi_init_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].key.len;
copy = ngx_array_push_n(params->lengths,
@@ -1996,7 +1997,8 @@ ngx_http_uwsgi_init_params(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *conf,
return NGX_ERROR;
}
- copy->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ copy->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
copy->len = src[i].skip_empty;
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 2db7a62..c88c271 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -923,7 +923,7 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg)
SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx));
-#ifdef SSL_CTRL_CLEAR_OPTIONS
+#if OPENSSL_VERSION_NUMBER >= 0x009080dfL
/* only in 0.9.8m+ */
SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) &
~SSL_CTX_get_options(sscf->ssl.ctx));
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index 96f3ec6..1a87735 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -695,7 +695,8 @@ ngx_http_script_add_copy_code(ngx_http_script_compile_t *sc, ngx_str_t *value,
return NGX_ERROR;
}
- code->code = (ngx_http_script_code_pt) ngx_http_script_copy_len_code;
+ code->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_len_code;
code->len = len;
size = (sizeof(ngx_http_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
@@ -784,7 +785,8 @@ ngx_http_script_add_var_code(ngx_http_script_compile_t *sc, ngx_str_t *name)
return NGX_ERROR;
}
- code->code = (ngx_http_script_code_pt) ngx_http_script_copy_var_len_code;
+ code->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_var_len_code;
code->index = (uintptr_t) index;
code = ngx_http_script_add_code(*sc->values,
@@ -1178,8 +1180,8 @@ ngx_http_script_add_capture_code(ngx_http_script_compile_t *sc, ngx_uint_t n)
return NGX_ERROR;
}
- code->code = (ngx_http_script_code_pt)
- ngx_http_script_copy_capture_len_code;
+ code->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_copy_capture_len_code;
code->n = 2 * n;
@@ -1293,7 +1295,8 @@ ngx_http_script_add_full_name_code(ngx_http_script_compile_t *sc)
return NGX_ERROR;
}
- code->code = (ngx_http_script_code_pt) ngx_http_script_full_name_len_code;
+ code->code = (ngx_http_script_code_pt) (void *)
+ ngx_http_script_full_name_len_code;
code->conf_prefix = sc->conf_prefix;
code = ngx_http_script_add_code(*sc->values,
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 8fc3042..0760dc2 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2008,6 +2008,18 @@ ngx_http_upstream_send_request(ngx_http_request_t *r, ngx_http_upstream_t *u,
return;
}
+ if (c->write->ready && c->tcp_nopush == NGX_TCP_NOPUSH_SET) {
+ if (ngx_tcp_push(c->fd) == -1) {
+ ngx_log_error(NGX_LOG_CRIT, c->log, ngx_socket_errno,
+ ngx_tcp_push_n " failed");
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
+ c->tcp_nopush = NGX_TCP_NOPUSH_UNSET;
+ }
+
return;
}
@@ -2901,7 +2913,8 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
}
if (r->request_body && r->request_body->temp_file
- && r == r->main && !r->preserve_body)
+ && r == r->main && !r->preserve_body
+ && !u->conf->preserve_output)
{
ngx_pool_run_cleanup_file(r->pool, r->request_body->temp_file->file.fd);
r->request_body->temp_file->file.fd = NGX_INVALID_FILE;
diff --git a/src/os/unix/ngx_user.c b/src/os/unix/ngx_user.c
index 7ebe2b5..b3d81d0 100644
--- a/src/os/unix/ngx_user.c
+++ b/src/os/unix/ngx_user.c
@@ -21,10 +21,6 @@ ngx_libc_crypt(ngx_pool_t *pool, u_char *key, u_char *salt, u_char **encrypted)
struct crypt_data cd;
cd.initialized = 0;
-#ifdef __GLIBC__
- /* work around the glibc bug */
- cd.current_salt[0] = ~salt[0];
-#endif
value = crypt_r((char *) key, (char *) salt, &cd);
diff --git a/src/stream/ngx_stream_script.c b/src/stream/ngx_stream_script.c
index aa555ca..b00e708 100644
--- a/src/stream/ngx_stream_script.c
+++ b/src/stream/ngx_stream_script.c
@@ -587,7 +587,8 @@ ngx_stream_script_add_copy_code(ngx_stream_script_compile_t *sc,
return NGX_ERROR;
}
- code->code = (ngx_stream_script_code_pt) ngx_stream_script_copy_len_code;
+ code->code = (ngx_stream_script_code_pt) (void *)
+ ngx_stream_script_copy_len_code;
code->len = len;
size = (sizeof(ngx_stream_script_copy_code_t) + len + sizeof(uintptr_t) - 1)
@@ -677,8 +678,8 @@ ngx_stream_script_add_var_code(ngx_stream_script_compile_t *sc, ngx_str_t *name)
return NGX_ERROR;
}
- code->code = (ngx_stream_script_code_pt)
- ngx_stream_script_copy_var_len_code;
+ code->code = (ngx_stream_script_code_pt) (void *)
+ ngx_stream_script_copy_var_len_code;
code->index = (uintptr_t) index;
code = ngx_stream_script_add_code(*sc->values,
@@ -767,8 +768,8 @@ ngx_stream_script_add_capture_code(ngx_stream_script_compile_t *sc,
return NGX_ERROR;
}
- code->code = (ngx_stream_script_code_pt)
- ngx_stream_script_copy_capture_len_code;
+ code->code = (ngx_stream_script_code_pt) (void *)
+ ngx_stream_script_copy_capture_len_code;
code->n = 2 * n;
@@ -859,7 +860,7 @@ ngx_stream_script_add_full_name_code(ngx_stream_script_compile_t *sc)
return NGX_ERROR;
}
- code->code = (ngx_stream_script_code_pt)
+ code->code = (ngx_stream_script_code_pt) (void *)
ngx_stream_script_full_name_len_code;
code->conf_prefix = sc->conf_prefix;
From 1f43924c7179cd31368a34caa6a4c14764b32097 Mon Sep 17 00:00:00 2001
From: Kartik Mistry
Date: Thu, 6 Dec 2018 20:03:49 +0530
Subject: [PATCH 005/334] Added Turkish translation (Closes: #915728)
---
debian/changelog | 9 ++++++++
debian/po/tr.po | 57 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 66 insertions(+)
create mode 100644 debian/po/tr.po
diff --git a/debian/changelog b/debian/changelog
index d08388f..b2c56d9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+nginx (1.14.1-2) UNRELEASED; urgency=low
+
+ [ Kartik Mistry ]
+ * po/tr.po:
+ + Added Turkish translation. Thanks Atila KOÇ
+ (Closes: #915728)
+
+ -- Kartik Mistry Thu, 06 Dec 2018 20:01:00 +0530
+
nginx (1.14.1-1) unstable; urgency=medium
[ Kartik Mistry ]
diff --git a/debian/po/tr.po b/debian/po/tr.po
new file mode 100644
index 0000000..3e9d40b
--- /dev/null
+++ b/debian/po/tr.po
@@ -0,0 +1,57 @@
+# nginx turkish debconf translations
+# This file is distributed under the same license as the nginx package.
+# Atila KOÇ , 2018.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: nginx\n"
+"Report-Msgid-Bugs-To: nginx@packages.debian.org\n"
+"POT-Creation-Date: 2018-11-08 18:08+0300\n"
+"PO-Revision-Date: 2018-11-28 14:50+0300\n"
+"Last-Translator: Atila KOÇ \n"
+"Language-Team: none\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.11\n"
+"Language: tr\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#. Type: note
+#. Description
+#: ../nginx-common.templates:1001
+msgid "Possible insecure nginx log files"
+msgstr "Güvenliği sağlanmamış nginx günlük dosyaları olabilir"
+
+#. Type: note
+#. Description
+#: ../nginx-common.templates:1001
+msgid ""
+"The following log files under /var/log/nginx directory are symlinks owned by "
+"www-data:"
+msgstr ""
+"/var/log/nginx dizini altında bulunan aşağıdaki günlük dosyaları sahibi www-"
+"data olan sembolik bağlantılardır:"
+
+#. Type: note
+#. Description
+#: ../nginx-common.templates:1001
+msgid "${logfiles}"
+msgstr "${logfiles}"
+
+#. Type: note
+#. Description
+#: ../nginx-common.templates:1001
+msgid ""
+"Since nginx 1.4.4-4 /var/log/nginx was owned by www-data. As a result www-"
+"data could symlink log files to sensitive locations, which in turn could "
+"lead to privilege escalation attacks. Although /var/log/nginx permissions "
+"are now fixed it is possible that such insecure links already exist. So, "
+"please make sure to check the above locations."
+msgstr ""
+"nginx'in 1.4.4-4 ve sonraki sürümlerinde /var/log/nginx dizininin sahibi www-"
+"data idi. Bu nedenle www-data hassas konumlardaki sistem günlüklerine erişen "
+"sembolik bağlantılara sahip olabiliyor ve bu durum ayrıcalık kazanma yolu "
+"ile yapılabilecek saldırılara olanak sağlayabiliyordu. Artık /var/log/nginx "
+"dizininin erişim hakları düzeltilmiş olsa da güvenliği sağlanmamış "
+"bağlantılar kalmış olabilir. Lütfen yukarıdaki konumları gözden geçiriniz."
From 969f3934b102e0fab9ea0b9cc52e2e81689fa254 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 13 Dec 2018 10:05:52 +0200
Subject: [PATCH 006/334] Release 1.14.2-1
---
debian/changelog | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index d08388f..504aabe 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+nginx (1.14.2-1) unstable; urgency=medium
+
+ [ Olaf van der Spek ]
+ * Reference PHP 7.3 (Closes: 913250)
+
+ [ Christos Trochalakis ]
+ * Adjust fastcgi_split_path_info snippet to handle the `/example.php/` case
+ (Closes: #911398)
+
+ -- Christos Trochalakis Thu, 13 Dec 2018 10:05:37 +0200
+
nginx (1.14.1-1) unstable; urgency=medium
[ Kartik Mistry ]
From ff8b896b2bee270864cf2421e46e8dc551e3eaac Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 27 Dec 2018 12:45:01 +0200
Subject: [PATCH 007/334] http-dav-ext: Upgrade to 3.0.0
Closes: #851651
---
debian/modules/control | 2 +-
debian/modules/http-dav-ext/LICENSE | 2 +-
debian/modules/http-dav-ext/README.rst | 185 +-
debian/modules/http-dav-ext/config | 23 +-
.../http-dav-ext/ngx_http_dav_ext_module.c | 2732 ++++++++++++-----
debian/modules/http-dav-ext/t/dav_ext.t | 141 +
6 files changed, 2364 insertions(+), 721 deletions(-)
create mode 100644 debian/modules/http-dav-ext/t/dav_ext.t
diff --git a/debian/modules/control b/debian/modules/control
index ec627be..a5d65a8 100644
--- a/debian/modules/control
+++ b/debian/modules/control
@@ -51,7 +51,7 @@ Patch:
Module: http-dav-ext
Homepage: https://github.com/arut/nginx-dav-ext-module
-Version: 0.1.0
+Version: 3.0.0
Module: http-fancyindex
Homepage: https://github.com/aperezdc/ngx-fancyindex
diff --git a/debian/modules/http-dav-ext/LICENSE b/debian/modules/http-dav-ext/LICENSE
index 7be3135..c68a7d4 100644
--- a/debian/modules/http-dav-ext/LICENSE
+++ b/debian/modules/http-dav-ext/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2012-2017, Roman Arutyunyan
+Copyright (C) 2012-2018 Roman Arutyunyan
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/debian/modules/http-dav-ext/README.rst b/debian/modules/http-dav-ext/README.rst
index 91c10e3..092056e 100644
--- a/debian/modules/http-dav-ext/README.rst
+++ b/debian/modules/http-dav-ext/README.rst
@@ -2,40 +2,187 @@
nginx-dav-ext-module
********************
-NGINX WebDAV missing commands support (PROPFIND & OPTIONS)
+nginx_ WebDAV_ PROPFIND,OPTIONS,LOCK,UNLOCK support.
-Copyright |copy| 2012-2017 Arutyunyan Roman (arutyunyan.roman@gmail.com)
+.. contents::
-.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN
-For full WebDAV support in NGINX you need to enable the standard NGINX
-WebDAV module (providing partial WebDAV implementation) as well as
-this module for missing methods:
+About
+=====
+
+The standard ngx_http_dav_module_ provides partial WebDAV_ implementation and
+only supports GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE methods.
+
+For full WebDAV_ support in nginx_ you need to enable the standard
+ngx_http_dav_module_ as well as this module for the missing methods.
+
+
+Build
+=====
+
+Building nginx_ with the module:
.. code-block:: bash
- $ ./configure --with-http_dav_module --add-module=/path/to/this-module
+ # static module
+ $ ./configure --with-http_dav_module --add-module=/path/to/nginx-dav-ext-module
-The module can be built dynamically:
+ # dynamic module
+ $ ./configure --with-http_dav_module --add-dynamic-module=/path/to/nginx-dav-ext-module
-.. code-block:: bash
+Trying to compile nginx_ with this module but without ngx_http_dav_module_ will
+result in compilation error.
- $ ./configure --with-http_dav_module --add-dynamic-module=/path/to/this-module
Requirements
============
-``libexpat-dev``
+- nginx_ version >= 1.13.4
+- ``libxml2`` + ``libxslt``
+
+The ``libxslt`` library is technically redundant and is only required since this
+combination is supported by nginx_ for the xslt module.
+Using builtin nginx mechanisms for linking against third-party libraries
+brings certain compatibility benefits.
+However this redundancy can be easily eliminated in the ``config`` file.
-Example config
-==============
+Testing
+=======
-.. code-block::
+The module tests require standard nginx-tests_ and Perl ``HTTP::DAV`` library.
- location / {
- dav_methods PUT DELETE MKCOL COPY MOVE;
- dav_ext_methods PROPFIND OPTIONS;
+.. code-block:: bash
- root /var/root/;
- }
+ $ export PERL5LIB=/path/to/nginx-tests/lib
+ $ export TEST_NGINX_BINARY=/path/to/nginx
+ $ prove t
+
+
+Locking
+=======
+
+- Only the exclusive write locks are supported, which is the only type of locks
+ described in the WebDAV_ specification.
+
+- All currently held locks are kept in a list.
+ Checking if an object is constrained by a lock requires O(n) operations.
+ A huge number of simultaneously held locks may degrade performance.
+ Thus it is not recommended to have a large lock timeout which would increase
+ the number of locks.
+
+
+Directives
+==========
+
+dav_ext_methods
+---------------
+
+========== ====
+*Syntax:* ``dav_ext_methods [PROPFIND] [OPTIONS] [LOCK] [UNLOCK]``
+*Context:* http, server, location
+========== ====
+
+Enables support for the specified WebDAV methods in the current scope.
+
+dav_ext_lock_zone
+-----------------
+
+========== ====
+*Syntax:* ``dav_ext_lock_zone zone=NAME:SIZE [timeout=TIMEOUT]``
+*Context:* http
+========== ====
+
+Defines a shared zone for WebDAV locks with specified NAME and SIZE.
+Also, defines a lock expiration TIMEOUT.
+Default lock timeout value is 1 minute.
+
+
+dav_ext_lock
+------------
+
+========== ====
+*Syntax:* ``dav_ext_lock zone=NAME``
+*Context:* http, server, location
+========== ====
+
+Enables WebDAV locking in the specified scope.
+Locks are stored in the shared zone specified by NAME.
+This zone must be defined with the ``dav_ext_lock_zone`` directive.
+
+Note that even though this directive enables locking capabilities in the
+current scope, HTTP methods LOCK and UNLOCK should also be explicitly specified
+in the ``dav_ext_methods``.
+
+
+Example 1
+=========
+
+Simple lockless example::
+
+ location / {
+ root /data/www;
+
+ dav_methods PUT DELETE MKCOL COPY MOVE;
+ dav_ext_methods PROPFIND OPTIONS;
+ }
+
+
+Example 2
+=========
+
+WebDAV with locking::
+
+ http {
+ dav_ext_lock_zone zone=foo:10m;
+
+ ...
+
+ server {
+ ...
+
+ location / {
+ root /data/www;
+
+ dav_methods PUT DELETE MKCOL COPY MOVE;
+ dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
+ dav_ext_lock zone=foo;
+ }
+ }
+ }
+
+
+Example 3
+=========
+
+WebDAV with locking which works with MacOS client::
+
+ http {
+ dav_ext_lock_zone zone=foo:10m;
+
+ ...
+
+ server {
+ ...
+
+ location / {
+ root /data/www;
+
+ # enable creating directories without trailing slash
+ set $x $uri$request_method;
+ if ($x ~ [^/]MKCOL$) {
+ rewrite ^(.*)$ $1/;
+ }
+
+ dav_methods PUT DELETE MKCOL COPY MOVE;
+ dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
+ dav_ext_lock zone=foo;
+ }
+ }
+ }
+
+.. _ngx_http_dav_module: http://nginx.org/en/docs/http/ngx_http_dav_module.html
+.. _nginx-tests: http://hg.nginx.org/nginx-tests
+.. _nginx: http://nginx.org
+.. _WebDAV: https://tools.ietf.org/html/rfc4918
+.. _`RFC4918 If Header`: https://tools.ietf.org/html/rfc4918#section-10.4
diff --git a/debian/modules/http-dav-ext/config b/debian/modules/http-dav-ext/config
index 372620b..91ae1b3 100644
--- a/debian/modules/http-dav-ext/config
+++ b/debian/modules/http-dav-ext/config
@@ -1,16 +1,17 @@
ngx_addon_name=ngx_http_dav_ext_module
-if [ -f auto/module ] ; then
+ngx_module_type=HTTP
+ngx_module_name=ngx_http_dav_ext_module
- ngx_module_type=HTTP
- ngx_module_name=ngx_http_dav_ext_module
- ngx_module_libs=-lexpat
- ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c"
+# nginx has robust builtin support for linking against
+# libxml2+libxslt. This is definitelty the right way to go if
+# building nginx with the xslt module, in which case libxslt will
+# be linked anyway. In other cases libxslt is just redundant.
+# If that's a big deal, libxml2 can be linked directly:
+# ngx_module_libs=-lxml2
- . auto/module
+ngx_module_libs=LIBXSLT
-else
- HTTP_MODULES="$HTTP_MODULES ngx_http_dav_ext_module"
- NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_dav_ext_module.c"
- CORE_LIBS="$CORE_LIBS -lexpat"
-fi
+ngx_module_srcs="$ngx_addon_dir/ngx_http_dav_ext_module.c"
+
+. auto/module
diff --git a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c
index ae75fc3..0d6d067 100644
--- a/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c
+++ b/debian/modules/http-dav-ext/ngx_http_dav_ext_module.c
@@ -1,827 +1,2181 @@
-/******************************************************************************
- Copyright (c) 2012-2017, Roman Arutyunyan (arutyunyan.roman@gmail.com)
- All rights reserved.
-
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
-
- 1. Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
-
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
- SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
- IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
- OF SUCH DAMAGE.
- *******************************************************************************/
/*
-
- NGINX missing WebDAV commands support
-
- *PROPFIND & OPTIONS*
-
+ * Copyright (C) Roman Arutyunyan
*/
+
#include
#include
#include
+#include
-#include
-#include
-#include
-#include
+#define NGX_HTTP_DAV_EXT_OFF 2
+
+#define NGX_HTTP_DAV_EXT_PREALLOCATE 50
+
+#define NGX_HTTP_DAV_EXT_NODE_PROPFIND 0x01
+#define NGX_HTTP_DAV_EXT_NODE_PROP 0x02
+#define NGX_HTTP_DAV_EXT_NODE_PROPNAME 0x04
+#define NGX_HTTP_DAV_EXT_NODE_ALLPROP 0x08
+
+#define NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME 0x01
+#define NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH 0x02
+#define NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED 0x04
+#define NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE 0x08
+#define NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY 0x10
+#define NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK 0x20
+
+#define NGX_HTTP_DAV_EXT_PROP_ALL 0x7f
+#define NGX_HTTP_DAV_EXT_PROP_NAMES 0x80
-#define NGX_HTTP_DAV_EXT_OFF 2
typedef struct {
+ ngx_str_t uri;
+ ngx_str_t name;
+ time_t mtime;
+ off_t size;
- ngx_uint_t methods;
+ time_t lock_expire;
+ ngx_str_t lock_root;
+ uint32_t lock_token;
+ unsigned dir:1;
+ unsigned lock_supported:1;
+ unsigned lock_infinite:1;
+} ngx_http_dav_ext_entry_t;
+
+
+typedef struct {
+ ngx_uint_t nodes;
+ ngx_uint_t props;
+} ngx_http_dav_ext_xml_ctx_t;
+
+
+typedef struct {
+ ngx_uint_t methods;
+ ngx_shm_zone_t *shm_zone;
} ngx_http_dav_ext_loc_conf_t;
+
+typedef struct {
+ ngx_queue_t queue;
+ uint32_t token;
+ time_t expire;
+ ngx_uint_t infinite; /* unsigned infinite:1; */
+ size_t len;
+ u_char data[1];
+} ngx_http_dav_ext_node_t;
+
+
+typedef struct {
+ ngx_queue_t queue;
+} ngx_http_dav_ext_lock_sh_t;
+
+
+typedef struct {
+ time_t timeout;
+ ngx_slab_pool_t *shpool;
+ ngx_http_dav_ext_lock_sh_t *sh;
+} ngx_http_dav_ext_lock_t;
+
+
+static ngx_int_t ngx_http_dav_ext_precontent_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_dav_ext_strip_uri(ngx_http_request_t *r,
+ ngx_str_t *uri);
+static ngx_int_t ngx_http_dav_ext_verify_lock(ngx_http_request_t *r,
+ ngx_str_t *uri, ngx_uint_t delete_lock);
+static ngx_http_dav_ext_node_t *ngx_http_dav_ext_lock_lookup(
+ ngx_http_request_t *r, ngx_http_dav_ext_lock_t *lock, ngx_str_t *uri,
+ ngx_int_t depth);
+
+static ngx_int_t ngx_http_dav_ext_content_handler(ngx_http_request_t *r);
+static void ngx_http_dav_ext_propfind_handler(ngx_http_request_t *r);
+static void ngx_http_dav_ext_propfind_xml_start(void *data,
+ const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri,
+ int nb_namespaces, const xmlChar **namespaces, int nb_attributes,
+ int nb_defaulted, const xmlChar **attributes);
+static void ngx_http_dav_ext_propfind_xml_end(void *data,
+ const xmlChar *localname, const xmlChar *prefix, const xmlChar *uri);
+static ngx_int_t ngx_http_dav_ext_propfind(ngx_http_request_t *r,
+ ngx_uint_t props);
+static ngx_int_t ngx_http_dav_ext_set_locks(ngx_http_request_t *r,
+ ngx_http_dav_ext_entry_t *entry);
+static ngx_int_t ngx_http_dav_ext_propfind_response(ngx_http_request_t *r,
+ ngx_array_t *entries, ngx_uint_t props);
+static ngx_int_t ngx_http_dav_ext_lock_handler(ngx_http_request_t *r);
+static ngx_int_t ngx_http_dav_ext_lock_response(ngx_http_request_t *r,
+ ngx_uint_t status, time_t timeout, ngx_uint_t depth, uint32_t token);
+static ngx_int_t ngx_http_dav_ext_unlock_handler(ngx_http_request_t *r);
+
+static ngx_int_t ngx_http_dav_ext_depth(ngx_http_request_t *r,
+ ngx_int_t default_depth);
+static uint32_t ngx_http_dav_ext_lock_token(ngx_http_request_t *r);
+static uint32_t ngx_http_dav_ext_if(ngx_http_request_t *r, ngx_str_t *uri);
+static uintptr_t ngx_http_dav_ext_format_propfind(ngx_http_request_t *r,
+ u_char *dst, ngx_http_dav_ext_entry_t *entry, ngx_uint_t props);
+static uintptr_t ngx_http_dav_ext_format_lockdiscovery(ngx_http_request_t *r,
+ u_char *dst, ngx_http_dav_ext_entry_t *entry);
+static uintptr_t ngx_http_dav_ext_format_token(u_char *dst, uint32_t token,
+ ngx_uint_t brackets);
+
+static ngx_int_t ngx_http_dav_ext_init_zone(ngx_shm_zone_t *shm_zone,
+ void *data);
+static void *ngx_http_dav_ext_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_dav_ext_merge_loc_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+static char *ngx_http_dav_ext_lock_zone(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
+static char *ngx_http_dav_ext_lock(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static ngx_int_t ngx_http_dav_ext_init(ngx_conf_t *cf);
-static void * ngx_http_dav_ext_create_loc_conf(ngx_conf_t *cf);
-static char * ngx_http_dav_ext_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
+
static ngx_conf_bitmask_t ngx_http_dav_ext_methods_mask[] = {
-
- { ngx_string("off"), NGX_HTTP_DAV_EXT_OFF },
- { ngx_string("propfind"), NGX_HTTP_PROPFIND },
- { ngx_string("options"), NGX_HTTP_OPTIONS },
- { ngx_null_string, 0 }
-
+ { ngx_string("off"), NGX_HTTP_DAV_EXT_OFF },
+ { ngx_string("propfind"), NGX_HTTP_PROPFIND },
+ { ngx_string("options"), NGX_HTTP_OPTIONS },
+ { ngx_string("lock"), NGX_HTTP_LOCK },
+ { ngx_string("unlock"), NGX_HTTP_UNLOCK },
+ { ngx_null_string, 0 }
};
+
static ngx_command_t ngx_http_dav_ext_commands[] = {
- { ngx_string("dav_ext_methods"),
- NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
- ngx_conf_set_bitmask_slot,
- NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_dav_ext_loc_conf_t, methods),
- &ngx_http_dav_ext_methods_mask },
+ { ngx_string("dav_ext_methods"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_dav_ext_loc_conf_t, methods),
+ &ngx_http_dav_ext_methods_mask },
- ngx_null_command
+ { ngx_string("dav_ext_lock_zone"),
+ NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12,
+ ngx_http_dav_ext_lock_zone,
+ 0,
+ 0,
+ NULL },
+
+ { ngx_string("dav_ext_lock"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_http_dav_ext_lock,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
};
+
static ngx_http_module_t ngx_http_dav_ext_module_ctx = {
- NULL, /* preconfiguration */
- ngx_http_dav_ext_init, /* postconfiguration */
+ NULL, /* preconfiguration */
+ ngx_http_dav_ext_init, /* postconfiguration */
- NULL, /* create main configuration */
- NULL, /* init main configuration */
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
- NULL, /* create server configuration */
- NULL, /* merge server configuration */
+ NULL, /* create server configuration */
+ NULL, /* merge server configuration */
- ngx_http_dav_ext_create_loc_conf, /* create location configuration */
- ngx_http_dav_ext_merge_loc_conf, /* merge location configuration */
+ ngx_http_dav_ext_create_loc_conf, /* create location configuration */
+ ngx_http_dav_ext_merge_loc_conf, /* merge location configuration */
};
ngx_module_t ngx_http_dav_ext_module = {
- NGX_MODULE_V1,
- &ngx_http_dav_ext_module_ctx, /* module context */
- ngx_http_dav_ext_commands, /* module directives */
- NGX_HTTP_MODULE, /* module type */
- NULL, /* init master */
- NULL, /* init module */
- NULL, /* init process */
- NULL, /* init thread */
- NULL, /* exit thread */
- NULL, /* exit process */
- NULL, /* exit master */
- NGX_MODULE_V1_PADDING
+ NGX_MODULE_V1,
+ &ngx_http_dav_ext_module_ctx, /* module context */
+ ngx_http_dav_ext_commands, /* module directives */
+ NGX_HTTP_MODULE, /* module type */
+ NULL, /* init master */
+ NULL, /* init module */
+ NULL, /* init process */
+ NULL, /* init thread */
+ NULL, /* exit thread */
+ NULL, /* exit process */
+ NULL, /* exit master */
+ NGX_MODULE_V1_PADDING
};
-#define NGX_HTTP_DAV_EXT_NODE_propfind 0x001
-#define NGX_HTTP_DAV_EXT_NODE_prop 0x002
-#define NGX_HTTP_DAV_EXT_NODE_propname 0x004
-#define NGX_HTTP_DAV_EXT_NODE_allprop 0x008
-
-#define NGX_HTTP_DAV_EXT_PROP_creationdate 0x001
-#define NGX_HTTP_DAV_EXT_PROP_displayname 0x002
-#define NGX_HTTP_DAV_EXT_PROP_getcontentlanguage 0x004
-#define NGX_HTTP_DAV_EXT_PROP_getcontentlength 0x008
-#define NGX_HTTP_DAV_EXT_PROP_getcontenttype 0x010
-#define NGX_HTTP_DAV_EXT_PROP_getetag 0x020
-#define NGX_HTTP_DAV_EXT_PROP_getlastmodified 0x040
-#define NGX_HTTP_DAV_EXT_PROP_lockdiscovery 0x080
-#define NGX_HTTP_DAV_EXT_PROP_resourcetype 0x100
-#define NGX_HTTP_DAV_EXT_PROP_source 0x200
-#define NGX_HTTP_DAV_EXT_PROP_supportedlock 0x400
-
-#define NGX_HTTP_DAV_EXT_PROPFIND_SELECTED 1
-#define NGX_HTTP_DAV_EXT_PROPFIND_NAMES 2
-#define NGX_HTTP_DAV_EXT_PROPFIND_ALL 3
-
-typedef struct {
-
- ngx_uint_t nodes;
-
- ngx_uint_t props;
-
- ngx_uint_t propfind;
-
-} ngx_http_dav_ext_ctx_t;
-
-static int ngx_http_dav_ext_xmlcmp(const char *xname, const char *sname) {
-
- const char *c;
-
- c = strrchr(xname, ':');
-
- return strcmp(c ? c + 1 : xname, sname);
-}
-
-static void ngx_http_dav_ext_start_xml_elt(void *user_data,
- const XML_Char *name, const XML_Char **atts)
-{
- ngx_http_dav_ext_ctx_t *ctx = user_data;
-
-#define NGX_HTTP_DAV_EXT_SET_NODE(nm) \
- if (!ngx_http_dav_ext_xmlcmp(name, #nm)) \
- ctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_##nm
-
- NGX_HTTP_DAV_EXT_SET_NODE(propfind);
- NGX_HTTP_DAV_EXT_SET_NODE(prop);
- NGX_HTTP_DAV_EXT_SET_NODE(propname);
- NGX_HTTP_DAV_EXT_SET_NODE(allprop);
-
-}
-
-static void ngx_http_dav_ext_end_xml_elt(void *user_data, const XML_Char *name)
-{
- ngx_http_dav_ext_ctx_t *ctx = user_data;
-
- if (ctx->nodes & NGX_HTTP_DAV_EXT_NODE_propfind) {
-
- if (ctx->nodes & NGX_HTTP_DAV_EXT_NODE_prop) {
-
- ctx->propfind = NGX_HTTP_DAV_EXT_PROPFIND_SELECTED;
-
-#define NGX_HTTP_DAV_EXT_SET_PROP(nm) \
- if (!ngx_http_dav_ext_xmlcmp(name, #nm)) \
- ctx->props |= NGX_HTTP_DAV_EXT_PROP_##nm
-
- NGX_HTTP_DAV_EXT_SET_PROP(creationdate);
- NGX_HTTP_DAV_EXT_SET_PROP(displayname);
- NGX_HTTP_DAV_EXT_SET_PROP(getcontentlanguage);
- NGX_HTTP_DAV_EXT_SET_PROP(getcontentlength);
- NGX_HTTP_DAV_EXT_SET_PROP(getcontenttype);
- NGX_HTTP_DAV_EXT_SET_PROP(getetag);
- NGX_HTTP_DAV_EXT_SET_PROP(getlastmodified);
- NGX_HTTP_DAV_EXT_SET_PROP(lockdiscovery);
- NGX_HTTP_DAV_EXT_SET_PROP(resourcetype);
- NGX_HTTP_DAV_EXT_SET_PROP(source);
- NGX_HTTP_DAV_EXT_SET_PROP(supportedlock);
-
- }
-
- if (ctx->nodes & NGX_HTTP_DAV_EXT_NODE_propname) {
-
- ctx->propfind = NGX_HTTP_DAV_EXT_PROPFIND_NAMES;
-
- }
-
- if (ctx->nodes & NGX_HTTP_DAV_EXT_NODE_allprop) {
-
- ctx->propfind = NGX_HTTP_DAV_EXT_PROPFIND_ALL;
-
- }
-
- }
-
- ngx_http_dav_ext_start_xml_elt(user_data, name, NULL);
-}
-
-#define NGX_HTTP_DAV_EXT_COPY 0x01
-#define NGX_HTTP_DAV_EXT_ESCAPE 0x02
-
-static void
-ngx_http_dav_ext_output(ngx_http_request_t *r, ngx_chain_t **ll,
- ngx_int_t flags, u_char *data, ngx_uint_t len)
-{
- ngx_chain_t *cl;
- ngx_buf_t *b;
-
- if (!len) {
- return;
- }
-
- if (flags & NGX_HTTP_DAV_EXT_ESCAPE) {
-
- b = ngx_create_temp_buf(r->pool, len + ngx_escape_html(NULL, data, len));
- b->last = (u_char*)ngx_escape_html(b->pos, data, len);
-
- } else if (flags & NGX_HTTP_DAV_EXT_COPY) {
-
- b = ngx_create_temp_buf(r->pool, len);
- b->last = ngx_cpymem(b->pos, data, len);
-
- } else {
-
- b = ngx_calloc_buf(r->pool);
- b->memory = 1;
- b->pos = data;
- b->start = data;
- b->last = b->pos + len;
- b->end = b->last;
- }
-
- cl = ngx_alloc_chain_link(r->pool);
- cl->buf = b;
- cl->next = NULL;
-
- if (*ll != NULL) {
- cl->next = (*ll)->next;
- (*ll)->next = cl;
- *ll = cl;
- } else {
- *ll = cl;
- cl->next = cl;
- }
-}
-
-static void
-ngx_http_dav_ext_flush(ngx_http_request_t *r, ngx_chain_t **ll)
-{
- ngx_chain_t *cl;
-
- cl = (*ll)->next;
- (*ll)->next = NULL;
- ngx_http_output_filter(r, cl);
- *ll = NULL;
-}
-
-/* output shortcuts
-
- NB: these shortcuts assume 2 variables exist in current context:
- r - request ptr
- ll - chain ptr ptr
-
- output chains are buffered in circular list & flushed on demand
-*/
-
-/* output buffer copy */
-#define NGX_HTTP_DAV_EXT_OUTCB(data, len) \
- ngx_http_dav_ext_output(r, ll, NGX_HTTP_DAV_EXT_COPY, (data), (len))
-
-/* output string (no copy) */
-#define NGX_HTTP_DAV_EXT_OUTS(s) \
- ngx_http_dav_ext_output(r, ll, 0, (s)->data, (s)->len)
-
-/* output escaped string */
-#define NGX_HTTP_DAV_EXT_OUTES(s) \
- ngx_http_dav_ext_output(r, ll, NGX_HTTP_DAV_EXT_ESCAPE, (s)->data, (s)->len)
-
-/* output literal */
-#define NGX_HTTP_DAV_EXT_OUTL(s) \
- ngx_http_dav_ext_output(r, ll, 0, (u_char*)(s), sizeof(s) - 1)
static ngx_int_t
-ngx_http_dav_ext_send_propfind_atts(ngx_http_request_t *r,
- char *path, ngx_str_t *uri, ngx_chain_t **ll, ngx_uint_t props)
+ngx_http_dav_ext_precontent_handler(ngx_http_request_t *r)
{
- struct stat st;
- struct tm stm;
- u_char buf[256];
- ngx_str_t name;
+ ngx_str_t uri;
+ ngx_int_t rc;
+ ngx_uint_t delete_lock;
+ ngx_table_elt_t *dest;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
- if (stat(path, &st)) {
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
- "dav_ext stat failed on '%s'", path);
+ if (dlcf->shm_zone == NULL) {
+ return NGX_DECLINED;
+ }
- return NGX_HTTP_NOT_FOUND;
- }
+ if (r->method & (NGX_HTTP_PUT|NGX_HTTP_DELETE|NGX_HTTP_MKCOL|NGX_HTTP_MOVE))
+ {
+ delete_lock = (r->method & (NGX_HTTP_DELETE|NGX_HTTP_MOVE)) ? 1 : 0;
- if (props & NGX_HTTP_DAV_EXT_PROP_creationdate) {
+ rc = ngx_http_dav_ext_verify_lock(r, &r->uri, delete_lock);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
- /* output file ctime (attr change time) as creation time */
- if (gmtime_r(&st.st_ctime, &stm) == NULL)
- return NGX_ERROR;
+ if (r->method & (NGX_HTTP_MOVE|NGX_HTTP_COPY)) {
+ dest = r->headers_in.destination;
+ if (dest == NULL) {
+ return NGX_DECLINED;
+ }
- /* ISO 8601 time format
- 2012-02-20T16:15:00Z */
- NGX_HTTP_DAV_EXT_OUTCB(buf, strftime((char*)buf, sizeof(buf),
- ""
- "%Y-%m-%dT%TZ"
- "\n",
+ uri.data = dest->value.data;
+ uri.len = dest->value.len;
- &stm));
- }
+ if (ngx_http_dav_ext_strip_uri(r, &uri) != NGX_OK) {
+ return NGX_DECLINED;
+ }
- if (props & NGX_HTTP_DAV_EXT_PROP_displayname) {
- NGX_HTTP_DAV_EXT_OUTL(
- ""
- );
+ rc = ngx_http_dav_ext_verify_lock(r, &uri, 0);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
- if (uri->len) {
-
- for(name.data = uri->data + uri->len;
- name.data >= uri->data + 1 && name.data[-1] != '/';
- --name.data);
-
- name.len = uri->data + uri->len - name.data;
-
- NGX_HTTP_DAV_EXT_OUTES(&name);
- }
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_getcontentlanguage) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_getcontentlength) {
- NGX_HTTP_DAV_EXT_OUTCB(buf, ngx_snprintf(buf, sizeof(buf),
- ""
- "%O"
- "\n",
-
- st.st_size) - buf);
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_getcontenttype) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_getetag) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_getlastmodified) {
-
- if (gmtime_r(&st.st_mtime, &stm) == NULL)
- return NGX_ERROR;
-
- /* RFC 2822 time format */
- NGX_HTTP_DAV_EXT_OUTCB(buf, strftime((char*)buf, sizeof(buf),
- ""
- "%a, %d %b %Y %T GMT"
- "\n",
-
- &stm));
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_lockdiscovery) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_resourcetype) {
- if (S_ISDIR(st.st_mode)) {
- NGX_HTTP_DAV_EXT_OUTL(
- ""
- ""
- "\n"
- );
- } else {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_source) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- if (props & NGX_HTTP_DAV_EXT_PROP_supportedlock) {
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
- }
-
- return NGX_OK;
-}
-
-static ngx_int_t
-ngx_http_dav_ext_send_propfind_item(ngx_http_request_t *r,
- char *path, ngx_str_t *uri)
-{
- ngx_http_dav_ext_ctx_t *ctx;
- ngx_chain_t *l = NULL, **ll = &l;
- u_char vbuf[8];
- ngx_str_t status_line = ngx_string("200 OK");
-
- ctx = ngx_http_get_module_ctx(r, ngx_http_dav_ext_module);
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- ""
- );
-
- NGX_HTTP_DAV_EXT_OUTES(uri);
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- "\n"
- "\n"
- );
-
- if (ctx->propfind == NGX_HTTP_DAV_EXT_PROPFIND_NAMES) {
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- "\n"
- );
-
- } else {
-
- switch (ngx_http_dav_ext_send_propfind_atts(r, path, uri, ll,
- ctx->propfind == NGX_HTTP_DAV_EXT_PROPFIND_SELECTED ?
- ctx->props : (ngx_uint_t)-1))
- {
- case NGX_HTTP_NOT_FOUND:
- ngx_str_set(&status_line, "404 Not Found");
- break;
-
- case NGX_OK:
- case NGX_HTTP_OK:
- break;
-
- default:
- ngx_str_set(&status_line, "500 Internal Server Error");
- }
- }
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- "HTTP/"
- );
-
- NGX_HTTP_DAV_EXT_OUTCB(vbuf, ngx_snprintf(vbuf, sizeof(vbuf), "%d.%d ",
- r->http_major, r->http_minor) - vbuf);
-
- NGX_HTTP_DAV_EXT_OUTS(&status_line);
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- "\n"
- "\n"
-
- );
-
- ngx_http_dav_ext_flush(r, ll);
-
- return NGX_OK;
+ return NGX_DECLINED;
}
-/* path returned by this function is terminated
- with a hidden (out-of-len) null */
-static void ngx_http_dav_ext_make_child(ngx_pool_t *pool, ngx_str_t *parent,
- u_char *child, size_t chlen, ngx_str_t *path)
-{
- u_char *s;
-
- path->data = ngx_palloc(pool, parent->len + 2 + chlen);
- s = path->data;
- s = ngx_cpymem(s, parent->data, parent->len);
- if (parent->len > 0 && s[-1] != '/')
- *s++ = '/';
- s = ngx_cpymem(s, child, chlen);
- path->len = s - path->data;
- *s = 0;
-}
-
-#define DAV_EXT_INFINITY (-1)
static ngx_int_t
-ngx_http_dav_ext_send_propfind(ngx_http_request_t *r)
+ngx_http_dav_ext_strip_uri(ngx_http_request_t *r, ngx_str_t *uri)
{
- size_t root;
- ngx_str_t path, spath, ruri, suri;
- ngx_chain_t *l = NULL, **ll = &l;
- DIR *dir;
- int depth;
- struct dirent *de;
- size_t len, uc_len;
- ngx_http_variable_value_t vv;
- ngx_str_t depth_name = ngx_string("depth");
- u_char *p, *uc;
+ u_char *p, *last, *host;
+ size_t len;
- if (ngx_http_variable_unknown_header(&vv, &depth_name,
- &r->headers_in.headers.part, 0) != NGX_OK)
- {
- return NGX_ERROR;
- }
+ if (uri->data[0] == '/') {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext strip uri:\"%V\" unchanged", uri);
+ return NGX_OK;
+ }
- if (!vv.not_found) {
- if (vv.len == sizeof("infinity") -1
- && !ngx_strncasecmp(vv.data, (u_char*)"infinity", vv.len))
- {
- depth = DAV_EXT_INFINITY;
- } else {
- depth = ngx_atoi(vv.data, vv.len);
- }
+ len = r->headers_in.server.len;
- } else {
- depth = DAV_EXT_INFINITY;
- }
+ if (len == 0) {
+ goto failed;
+ }
- p = ngx_http_map_uri_to_path(r, &path, &root, 0);
+#if (NGX_HTTP_SSL)
- if (p == NULL || !path.len) {
+ if (r->connection->ssl) {
+ if (ngx_strncmp(uri->data, "https://", sizeof("https://") - 1) != 0) {
+ goto failed;
+ }
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "dav_ext error mapping uri to path");
+ host = uri->data + sizeof("https://") - 1;
- return NGX_ERROR;
- }
+ } else
+#endif
+ {
+ if (ngx_strncmp(uri->data, "http://", sizeof("http://") - 1) != 0) {
+ goto failed;
+ }
- path.len = p - path.data;
- *p = 0;
+ host = uri->data + sizeof("http://") - 1;
+ }
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "http propfind path: \"%V\"", &path);
+ if (ngx_strncmp(host, r->headers_in.server.data, len) != 0) {
+ goto failed;
+ }
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- "\n"
- );
+ last = uri->data + uri->len;
- ngx_http_dav_ext_flush(r, ll);
-/*
- ruri.data = ngx_palloc(r->pool, r->uri.len + 2 * ngx_escape_uri(NULL,
- r->uri.data, r->uri.len, NGX_ESCAPE_URI));
- if (ruri.data == NULL) {
- return NGX_ERROR;
- }
+ for (p = host + len; p != last; p++) {
+ if (*p == '/') {
+ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext strip uri \"%V\" \"%*s\"",
+ uri, last - p, p);
- ruri.len = (u_char *) ngx_escape_uri(ruri.data, r->uri.data, r->uri.len,
- NGX_ESCAPE_URI) - ruri.data;
-*/
- ruri = r->unparsed_uri;
+ uri->data = p;
+ uri->len = last - p;
- ngx_http_dav_ext_send_propfind_item(r, (char*)path.data, &ruri);
+ return NGX_OK;
+ }
+ }
- if (depth) {
+failed:
- /* treat infinite depth as 1 for performance reasons */
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext strip uri \"%V\" failed", uri);
- if ((dir = opendir((char*)path.data))) {
-
- while((de = readdir(dir))) {
-
- if (!strcmp(de->d_name, ".")
- || !strcmp(de->d_name, ".."))
- {
- continue;
- }
-
- len = strlen(de->d_name);
-
- ngx_http_dav_ext_make_child(r->pool, &path,
- (u_char*)de->d_name, len, &spath);
-
- /* escape uri component */
-
- uc = ngx_palloc(r->pool, len + 2 * ngx_escape_uri(NULL,
- (u_char *) de->d_name, len, NGX_ESCAPE_URI_COMPONENT));
- if (uc == NULL) {
- return NGX_ERROR;
- }
-
- uc_len = (u_char*)ngx_escape_uri(uc, (u_char *) de->d_name, len,
- NGX_ESCAPE_URI_COMPONENT) - uc;
-
- ngx_http_dav_ext_make_child(r->pool, &ruri, uc, uc_len, &suri);
-
- ngx_http_dav_ext_send_propfind_item(r, (char*)spath.data, &suri);
-
- }
-
- closedir(dir);
- }
-
- }
-
- NGX_HTTP_DAV_EXT_OUTL(
- "\n"
- );
-
- if (*ll && (*ll)->buf) {
- (*ll)->buf->last_buf = 1;
- }
-
- ngx_http_dav_ext_flush(r, ll);
-
- return NGX_OK;
+ return NGX_DECLINED;
}
+
+static ngx_int_t
+ngx_http_dav_ext_verify_lock(ngx_http_request_t *r, ngx_str_t *uri,
+ ngx_uint_t delete_lock)
+{
+ uint32_t token;
+ ngx_http_dav_ext_node_t *node;
+ ngx_http_dav_ext_lock_t *lock;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext verify lock \"%V\"", uri);
+
+ token = ngx_http_dav_ext_if(r, uri);
+
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+ lock = dlcf->shm_zone->data;
+
+ ngx_shmtx_lock(&lock->shpool->mutex);
+
+ node = ngx_http_dav_ext_lock_lookup(r, lock, uri, -1);
+ if (node == NULL) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_OK;
+ }
+
+ if (token == 0) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return 423; /* Locked */
+ }
+
+ if (token != node->token) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_HTTP_PRECONDITION_FAILED;
+ }
+
+ /*
+ * RFC4918:
+ * If a request causes the lock-root of any lock to become an
+ * unmapped URL, then the lock MUST also be deleted by that request.
+ */
+
+ if (delete_lock && node->len == uri->len) {
+ ngx_queue_remove(&node->queue);
+ ngx_slab_free_locked(lock->shpool, node);
+ }
+
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+
+ return NGX_OK;
+}
+
+
+static ngx_http_dav_ext_node_t *
+ngx_http_dav_ext_lock_lookup(ngx_http_request_t *r,
+ ngx_http_dav_ext_lock_t *lock, ngx_str_t *uri, ngx_int_t depth)
+{
+ time_t now;
+ ngx_queue_t *q;
+ ngx_http_dav_ext_node_t *node;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext lock lookup \"%V\"", uri);
+
+ if (uri->len == 0) {
+ return NULL;
+ }
+
+ now = ngx_time();
+
+ while (!ngx_queue_empty(&lock->sh->queue)) {
+ q = ngx_queue_head(&lock->sh->queue);
+ node = (ngx_http_dav_ext_node_t *) q;
+
+ if (node->expire >= now) {
+ break;
+ }
+
+ ngx_queue_remove(q);
+ ngx_slab_free_locked(lock->shpool, node);
+ }
+
+ for (q = ngx_queue_head(&lock->sh->queue);
+ q != ngx_queue_sentinel(&lock->sh->queue);
+ q = ngx_queue_next(q))
+ {
+ node = (ngx_http_dav_ext_node_t *) q;
+
+ if (uri->len >= node->len) {
+ if (ngx_memcmp(uri->data, node->data, node->len)) {
+ continue;
+ }
+
+ if (uri->len > node->len) {
+ if (node->data[node->len - 1] != '/') {
+ continue;
+ }
+
+ if (!node->infinite
+ && ngx_strlchr(uri->data + node->len,
+ uri->data + uri->len - 1, '/'))
+ {
+ continue;
+ }
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext lock found \"%*s\"",
+ node->len, node->data);
+
+ return node;
+ }
+
+ /* uri->len < node->len */
+
+ if (depth >= 0) {
+ if (ngx_memcmp(node->data, uri->data, uri->len)) {
+ continue;
+ }
+
+ if (uri->data[uri->len - 1] != '/') {
+ continue;
+ }
+
+ if (depth == 0
+ && ngx_strlchr(node->data + uri->len,
+ node->data + node->len - 1, '/'))
+ {
+ continue;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext lock found \"%*s\"",
+ node->len, node->data);
+
+ return node;
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext lock not found");
+
+ return NULL;
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_content_handler(ngx_http_request_t *r)
+{
+ ngx_int_t rc;
+ ngx_table_elt_t *h;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
+
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+
+ if (!(r->method & dlcf->methods)) {
+ return NGX_DECLINED;
+ }
+
+ switch (r->method) {
+
+ case NGX_HTTP_PROPFIND:
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind");
+
+ rc = ngx_http_read_client_request_body(r,
+ ngx_http_dav_ext_propfind_handler);
+ if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+ return rc;
+ }
+
+ return NGX_DONE;
+
+ case NGX_HTTP_OPTIONS:
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext options");
+
+ rc = ngx_http_discard_request_body(r);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ h = ngx_list_push(&r->headers_out.headers);
+ if (h == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_str_set(&h->key, "DAV");
+ h->value.len = 1;
+ h->value.data = (u_char *) (dlcf->shm_zone ? "2" : "1");
+ h->hash = 1;
+
+ h = ngx_list_push(&r->headers_out.headers);
+ if (h == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ /* XXX */
+ ngx_str_set(&h->key, "Allow");
+ ngx_str_set(&h->value,
+ "GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS,LOCK,UNLOCK");
+ h->hash = 1;
+
+ r->headers_out.status = NGX_HTTP_OK;
+ r->headers_out.content_length_n = 0;
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ return ngx_http_send_special(r, NGX_HTTP_LAST);
+
+ case NGX_HTTP_LOCK:
+
+ if (dlcf->shm_zone == NULL) {
+ return NGX_HTTP_NOT_ALLOWED;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext lock");
+
+ /*
+ * Body is expected to carry the requested lock type, but
+ * since we only support write/exclusive locks, we ignore it.
+ * Ideally we could throw an error if a lock of another type
+ * is requested, but the amount of work required for that is
+ * not worth it.
+ */
+
+ rc = ngx_http_discard_request_body(r);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ return ngx_http_dav_ext_lock_handler(r);
+
+ case NGX_HTTP_UNLOCK:
+
+ if (dlcf->shm_zone == NULL) {
+ return NGX_HTTP_NOT_ALLOWED;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext unlock");
+
+ rc = ngx_http_discard_request_body(r);
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ return ngx_http_dav_ext_unlock_handler(r);
+ }
+
+ return NGX_DECLINED;
+}
+
+
static void
ngx_http_dav_ext_propfind_handler(ngx_http_request_t *r)
{
- ngx_chain_t *c;
- ngx_buf_t *b;
- XML_Parser parser;
- ngx_uint_t status;
- ngx_http_dav_ext_ctx_t *ctx;
+ off_t len;
+ ngx_buf_t *b;
+ ngx_chain_t *cl;
+ xmlSAXHandler sax;
+ xmlParserCtxtPtr pctx;
+ ngx_http_dav_ext_xml_ctx_t xctx;
- ctx = ngx_http_get_module_ctx(r, ngx_http_dav_ext_module);
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind handler");
- if (ctx == NULL) {
- ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_dav_ext_ctx_t));
- ngx_http_set_ctx(r, ctx, ngx_http_dav_ext_module);
- }
+ ngx_memzero(&xctx, sizeof(ngx_http_dav_ext_xml_ctx_t));
+ ngx_memzero(&sax, sizeof(xmlSAXHandler));
- c = r->request_body->bufs;
+ sax.initialized = XML_SAX2_MAGIC;
+ sax.startElementNs = ngx_http_dav_ext_propfind_xml_start;
+ sax.endElementNs = ngx_http_dav_ext_propfind_xml_end;
- status = NGX_OK;
+ pctx = xmlCreatePushParserCtxt(&sax, &xctx, NULL, 0, NULL);
+ if (pctx == NULL) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xmlCreatePushParserCtxt() failed");
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
- parser = XML_ParserCreate(NULL);
+ len = 0;
- XML_SetUserData(parser, ctx);
+ for (cl = r->request_body->bufs; cl; cl = cl->next) {
+ b = cl->buf;
- XML_SetElementHandler(parser,
- ngx_http_dav_ext_start_xml_elt,
- ngx_http_dav_ext_end_xml_elt);
+ if (b->in_file) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "PROPFIND client body is in file, "
+ "you may want to increase client_body_buffer_size");
+ xmlFreeParserCtxt(pctx);
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
- for(; c != NULL && c->buf != NULL && !c->buf->last_buf; c = c->next) {
+ if (ngx_buf_special(b)) {
+ continue;
+ }
- b = c ->buf;
+ len += b->last - b->pos;
- if (!XML_Parse(parser, (const char*)b->pos, b->last - b->pos, b->last_buf)) {
+ if (xmlParseChunk(pctx, (const char *) b->pos, b->last - b->pos,
+ b->last_buf))
+ {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "xmlParseChunk() failed");
+ xmlFreeParserCtxt(pctx);
+ ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
+ return;
+ }
+ }
- ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
- "dav_ext propfind XML error");
+ xmlFreeParserCtxt(pctx);
- status = NGX_ERROR;
+ if (len == 0) {
- break;
- }
+ /*
+ * For easier debugging treat bodiless requests
+ * as if they expect all properties.
+ */
- }
-
- XML_ParserFree(parser);
-
- if (status == NGX_OK) {
-
- r->headers_out.status = 207;
-
- ngx_str_set(&r->headers_out.status_line, "207 Multi-Status");
-
- ngx_http_send_header(r);
-
- ngx_http_finalize_request(r, ngx_http_dav_ext_send_propfind(r));
-
- } else {
-
- r->headers_out.status = NGX_HTTP_INTERNAL_SERVER_ERROR;
-
- r->header_only = 1;
-
- r->headers_out.content_length_n = 0;
-
- ngx_http_finalize_request(r, ngx_http_send_header(r));
-
- }
+ xctx.props = NGX_HTTP_DAV_EXT_PROP_ALL;
+ }
+ ngx_http_finalize_request(r, ngx_http_dav_ext_propfind(r, xctx.props));
}
+
+static void
+ngx_http_dav_ext_propfind_xml_start(void *data, const xmlChar *localname,
+ const xmlChar *prefix, const xmlChar *uri, int nb_namespaces,
+ const xmlChar **namespaces, int nb_attributes, int nb_defaulted,
+ const xmlChar **attributes)
+{
+ ngx_http_dav_ext_xml_ctx_t *xctx = data;
+
+ if (ngx_strcmp(localname, "propfind") == 0) {
+ xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROPFIND;
+ }
+
+ if (ngx_strcmp(localname, "prop") == 0) {
+ xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROP;
+ }
+
+ if (ngx_strcmp(localname, "propname") == 0) {
+ xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_PROPNAME;
+ }
+
+ if (ngx_strcmp(localname, "allprop") == 0) {
+ xctx->nodes ^= NGX_HTTP_DAV_EXT_NODE_ALLPROP;
+ }
+}
+
+
+static void
+ngx_http_dav_ext_propfind_xml_end(void *data, const xmlChar *localname,
+ const xmlChar *prefix, const xmlChar *uri)
+{
+ ngx_http_dav_ext_xml_ctx_t *xctx = data;
+
+ if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROPFIND) {
+
+ if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROP) {
+ if (ngx_strcmp(localname, "displayname") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME;
+ }
+
+ if (ngx_strcmp(localname, "getcontentlength") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH;
+ }
+
+ if (ngx_strcmp(localname, "getlastmodified") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED;
+ }
+
+ if (ngx_strcmp(localname, "resourcetype") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE;
+ }
+
+ if (ngx_strcmp(localname, "lockdiscovery") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY;
+ }
+
+ if (ngx_strcmp(localname, "supportedlock") == 0) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK;
+ }
+ }
+
+ if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_PROPNAME) {
+ xctx->props |= NGX_HTTP_DAV_EXT_PROP_NAMES;
+ }
+
+ if (xctx->nodes & NGX_HTTP_DAV_EXT_NODE_ALLPROP) {
+ xctx->props = NGX_HTTP_DAV_EXT_PROP_ALL;
+ }
+ }
+
+ ngx_http_dav_ext_propfind_xml_start(data, localname, prefix, uri,
+ 0, NULL, 0, 0, NULL);
+}
+
+
static ngx_int_t
-ngx_http_dav_ext_handler(ngx_http_request_t *r)
+ngx_http_dav_ext_propfind(ngx_http_request_t *r, ngx_uint_t props)
{
- ngx_int_t rc;
- ngx_table_elt_t *h;
- ngx_http_dav_ext_loc_conf_t *delcf;
-
- delcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+ size_t root, allocated;
+ u_char *p, *last, *filename;
+ ngx_int_t rc;
+ ngx_err_t err;
+ ngx_str_t path, name;
+ ngx_dir_t dir;
+ ngx_uint_t depth;
+ ngx_array_t entries;
+ ngx_file_info_t fi;
+ ngx_http_dav_ext_entry_t *entry;
- if (!(r->method & delcf->methods)) {
- return NGX_DECLINED;
- }
+ if (ngx_array_init(&entries, r->pool, 40, sizeof(ngx_http_dav_ext_entry_t))
+ != NGX_OK)
+ {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- switch (r->method) {
+ rc = ngx_http_dav_ext_depth(r, 0);
- case NGX_HTTP_PROPFIND:
+ if (rc == NGX_ERROR) {
+ return NGX_HTTP_BAD_REQUEST;
+ }
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "dav_ext propfind");
+ if (rc == NGX_MAX_INT_T_VALUE) {
- rc = ngx_http_read_client_request_body(r,
- ngx_http_dav_ext_propfind_handler);
+ /*
+ * RFC4918:
+ * 403 Forbidden - A server MAY reject PROPFIND requests on
+ * collections with depth header of "Infinity", in which case
+ * it SHOULD use this error with the precondition code
+ * 'propfind-finite-depth' inside the error body.
+ */
- if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
- return rc;
- }
+ return NGX_HTTP_FORBIDDEN;
+ }
- return NGX_DONE;
+ depth = rc;
- case NGX_HTTP_OPTIONS:
+ last = ngx_http_map_uri_to_path(r, &path, &root,
+ NGX_HTTP_DAV_EXT_PREALLOCATE);
+ if (last == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
- "dav_ext options");
+ allocated = path.len;
+ path.len = last - path.data;
- h = ngx_list_push(&r->headers_out.headers);
+ if (path.len > 1 && path.data[path.len - 1] == '/') {
+ path.len--;
- if (h == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ } else {
+ last++;
+ }
- ngx_str_set(&h->key, "DAV");
- ngx_str_set(&h->value, "1");
- h->hash = 1;
+ path.data[path.len] = '\0';
- h = ngx_list_push(&r->headers_out.headers);
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind path: \"%s\"", path.data);
- if (h == NULL) {
- return NGX_HTTP_INTERNAL_SERVER_ERROR;
- }
+ if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
+ return NGX_HTTP_NOT_FOUND;
+ }
- /* FIXME: it looks so ugly because I cannot access nginx dav module */
- ngx_str_set(&h->key, "Allow");
- ngx_str_set(&h->value, "GET,HEAD,PUT,DELETE,MKCOL,COPY,MOVE,PROPFIND,OPTIONS");
- h->hash = 1;
+ if (r->uri.len < 2) {
+ name = r->uri;
- r->headers_out.status = NGX_HTTP_OK;
- r->header_only = 1;
- r->headers_out.content_length_n = 0;
+ } else {
+ name.data = &r->uri.data[r->uri.len - 1];
+ name.len = (name.data[0] == '/') ? 0 : 1;
- ngx_http_send_header(r);
+ while (name.data != r->uri.data) {
+ p = name.data - 1;
+ if (*p == '/') {
+ break;
+ }
- return NGX_OK;
+ name.data--;
+ name.len++;
+ }
+ }
- }
+ entry = ngx_array_push(&entries);
+ if (entry == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
- return NGX_DECLINED;
+ ngx_memzero(entry, sizeof(ngx_http_dav_ext_entry_t));
+
+ entry->uri = r->uri;
+ entry->name = name;
+ entry->dir = ngx_is_dir(&fi);
+ entry->mtime = ngx_file_mtime(&fi);
+ entry->size = ngx_file_size(&fi);
+
+ if (ngx_http_dav_ext_set_locks(r, entry) != NGX_OK) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind name:\"%V\", uri:\"%V\"",
+ &entry->name, &entry->uri);
+
+ if (depth == 0 || !entry->dir) {
+ return ngx_http_dav_ext_propfind_response(r, &entries, props);
+ }
+
+ if (ngx_open_dir(&path, &dir) == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_open_dir_n " \"%s\" failed", path.data);
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ rc = NGX_OK;
+
+ filename = path.data;
+ filename[path.len] = '/';
+
+ for ( ;; ) {
+ ngx_set_errno(0);
+
+ if (ngx_read_dir(&dir) == NGX_ERROR) {
+ err = ngx_errno;
+
+ if (err != NGX_ENOMOREFILES) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+ ngx_read_dir_n " \"%V\" failed", &path);
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ break;
+ }
+
+ name.len = ngx_de_namelen(&dir);
+ name.data = ngx_de_name(&dir);
+
+ if (name.data[0] == '.') {
+ continue;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind child path: \"%s\"", name.data);
+
+ entry = ngx_array_push(&entries);
+ if (entry == NULL) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ ngx_memzero(entry, sizeof(ngx_http_dav_ext_entry_t));
+
+ if (!dir.valid_info) {
+
+ if (path.len + 1 + name.len + 1 > allocated) {
+ allocated = path.len + 1 + name.len + 1
+ + NGX_HTTP_DAV_EXT_PREALLOCATE;
+
+ filename = ngx_pnalloc(r->pool, allocated);
+ if (filename == NULL) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ last = ngx_cpystrn(filename, path.data, path.len + 1);
+ *last++ = '/';
+ }
+
+ ngx_cpystrn(last, name.data, name.len + 1);
+
+ if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_de_info_n " \"%s\" failed", filename);
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+ }
+
+ p = ngx_pnalloc(r->pool, name.len);
+ if (p == NULL) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ ngx_memcpy(p, name.data, name.len);
+ entry->name.data = p;
+ entry->name.len = name.len;
+
+ p = ngx_pnalloc(r->pool, r->uri.len + 1 + name.len + 1);
+ if (p == NULL) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ entry->uri.data = p;
+
+ p = ngx_cpymem(p, r->uri.data, r->uri.len);
+ if (r->uri.len && r->uri.data[r->uri.len - 1] != '/') {
+ *p++ = '/';
+ }
+
+ p = ngx_cpymem(p, name.data, name.len);
+ if (ngx_de_is_dir(&dir)) {
+ *p++ = '/';
+ }
+
+ entry->uri.len = p - entry->uri.data;
+ entry->dir = ngx_de_is_dir(&dir);
+ entry->mtime = ngx_de_mtime(&dir);
+ entry->size = ngx_de_size(&dir);
+
+ if (ngx_http_dav_ext_set_locks(r, entry) != NGX_OK) {
+ rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
+ break;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext propfind child name:\"%V\", uri:\"%V\"",
+ &entry->name, &entry->uri);
+ }
+
+ if (ngx_close_dir(&dir) == NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_dir_n " \"%V\" failed", &path);
+ }
+
+ if (rc != NGX_OK) {
+ return rc;
+ }
+
+ return ngx_http_dav_ext_propfind_response(r, &entries, props);
}
+
+static ngx_int_t
+ngx_http_dav_ext_set_locks(ngx_http_request_t *r,
+ ngx_http_dav_ext_entry_t *entry)
+{
+ ngx_http_dav_ext_node_t *node;
+ ngx_http_dav_ext_lock_t *lock;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
+
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+
+ if (dlcf->shm_zone == NULL) {
+ entry->lock_supported = 0;
+ return NGX_OK;
+ }
+
+ entry->lock_supported = 1;
+
+ lock = dlcf->shm_zone->data;
+
+ ngx_shmtx_lock(&lock->shpool->mutex);
+
+ node = ngx_http_dav_ext_lock_lookup(r, lock, &entry->uri, -1);
+ if (node == NULL) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_OK;
+ }
+
+ entry->lock_infinite = node->infinite ? 1 : 0;
+ entry->lock_expire = node->expire;
+ entry->lock_token = node->token;
+
+ entry->lock_root.data = ngx_pnalloc(r->pool, node->len);
+ if (entry->lock_root.data == NULL) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(entry->lock_root.data, node->data, node->len);
+ entry->lock_root.len = node->len;
+
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_propfind_response(ngx_http_request_t *r, ngx_array_t *entries,
+ ngx_uint_t props)
+{
+ size_t len;
+ u_char *p;
+ uintptr_t escape;
+ ngx_buf_t *b;
+ ngx_int_t rc;
+ ngx_uint_t n;
+ ngx_chain_t cl;
+ ngx_http_dav_ext_entry_t *entry;
+
+ static u_char head[] =
+ "\n"
+ "\n";
+
+ static u_char tail[] =
+ "\n";
+
+ entry = entries->elts;
+
+ for (n = 0; n < entries->nelts; n++) {
+ escape = 2 * ngx_escape_uri(NULL, entry[n].uri.data, entry[n].uri.len,
+ NGX_ESCAPE_URI);
+ if (escape == 0) {
+ continue;
+ }
+
+ p = ngx_pnalloc(r->pool, entry[n].uri.len + escape);
+ if (p == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ entry[n].uri.len = (u_char *) ngx_escape_uri(p, entry[n].uri.data,
+ entry[n].uri.len,
+ NGX_ESCAPE_URI)
+ - p;
+ entry[n].uri.data = p;
+ }
+
+ len = sizeof(head) - 1 + sizeof(tail) - 1;
+
+ for (n = 0; n < entries->nelts; n++) {
+ len += ngx_http_dav_ext_format_propfind(r, NULL, &entry[n], props);
+ }
+
+ b = ngx_create_temp_buf(r->pool, len);
+ if (b == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ b->last = ngx_cpymem(b->last, head, sizeof(head) - 1);
+
+ for (n = 0; n < entries->nelts; n++) {
+ b->last = (u_char *) ngx_http_dav_ext_format_propfind(r, b->last,
+ &entry[n], props);
+ }
+
+ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
+
+ b->last_buf = (r == r->main) ? 1 : 0;
+ b->last_in_chain = 1;
+
+ cl.buf = b;
+ cl.next = NULL;
+
+ r->headers_out.status = 207;
+ ngx_str_set(&r->headers_out.status_line, "207 Multi-Status");
+
+ r->headers_out.content_length_n = b->last - b->pos;
+
+ r->headers_out.content_type_len = sizeof("text/xml") - 1;
+ ngx_str_set(&r->headers_out.content_type, "text/xml");
+ r->headers_out.content_type_lowcase = NULL;
+
+ ngx_str_set(&r->headers_out.charset, "utf-8");
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ return ngx_http_output_filter(r, &cl);
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_lock_handler(ngx_http_request_t *r)
+{
+ u_char *last;
+ size_t n, root;
+ time_t now;
+ uint32_t token, new_token;
+ ngx_fd_t fd;
+ ngx_int_t rc, depth;
+ ngx_str_t path;
+ ngx_uint_t status;
+ ngx_file_info_t fi;
+ ngx_http_dav_ext_lock_t *lock;
+ ngx_http_dav_ext_node_t *node;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
+
+ if (r->uri.len == 0) {
+ return NGX_HTTP_BAD_REQUEST;
+ }
+
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+ lock = dlcf->shm_zone->data;
+
+ /*
+ * RFC4918:
+ * If no Depth header is submitted on a LOCK request, then the request
+ * MUST act as if a "Depth:infinity" had been submitted.
+ */
+
+ rc = ngx_http_dav_ext_depth(r, NGX_MAX_INT_T_VALUE);
+
+ if (rc == NGX_ERROR || rc == 1) {
+
+ /*
+ * RFC4918:
+ * Values other than 0 or infinity MUST NOT be used with the Depth
+ * header on a LOCK method.
+ */
+
+ return NGX_HTTP_BAD_REQUEST;
+ }
+
+ depth = rc;
+
+ token = ngx_http_dav_ext_if(r, &r->uri);
+
+ do {
+ new_token = ngx_random();
+ } while (new_token == 0);
+
+ now = ngx_time();
+
+ ngx_shmtx_lock(&lock->shpool->mutex);
+
+ node = ngx_http_dav_ext_lock_lookup(r, lock, &r->uri, depth);
+
+ if (node) {
+ if (token == 0) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return 423; /* Locked */
+ }
+
+ if (node->token != token) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_HTTP_PRECONDITION_FAILED;
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext refresh lock");
+
+ node->expire = now + lock->timeout;
+
+ ngx_queue_remove(&node->queue);
+ ngx_queue_insert_tail(&lock->sh->queue, &node->queue);
+
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+
+ return ngx_http_dav_ext_lock_response(r, NGX_HTTP_OK, lock->timeout,
+ depth, token);
+ }
+
+ n = sizeof(ngx_http_dav_ext_node_t) + r->uri.len - 1;
+
+ node = ngx_slab_alloc_locked(lock->shpool, n);
+ if (node == NULL) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_memzero(node, sizeof(ngx_http_dav_ext_node_t));
+
+ ngx_memcpy(&node->data, r->uri.data, r->uri.len);
+
+ node->len = r->uri.len;
+ node->token = new_token;
+ node->expire = now + lock->timeout;
+ node->infinite = (depth ? 1 : 0);
+
+ ngx_queue_insert_tail(&lock->sh->queue, &node->queue);
+
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext add lock");
+
+ last = ngx_http_map_uri_to_path(r, &path, &root, 0);
+ if (last == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ *last = '\0';
+
+ status = NGX_HTTP_OK;
+
+ if (ngx_file_info(path.data, &fi) == NGX_FILE_ERROR) {
+
+ /*
+ * RFC4918:
+ * A successful lock request to an unmapped URL MUST result in the
+ * creation of a locked (non-collection) resource with empty content.
+ */
+
+ fd = ngx_open_file(path.data, NGX_FILE_RDONLY, NGX_FILE_CREATE_OR_OPEN,
+ NGX_FILE_DEFAULT_ACCESS);
+
+ if (fd == NGX_INVALID_FILE) {
+
+ /*
+ * RFC4918:
+ * 409 (Conflict) - A resource cannot be created at the destination
+ * until one or more intermediate collections have been created.
+ * The server MUST NOT create those intermediate collections
+ * automatically.
+ */
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, ngx_errno,
+ ngx_open_file_n " \"%s\" failed", path.data);
+ return NGX_HTTP_CONFLICT;
+ }
+
+ if (ngx_close_file(fd) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno,
+ ngx_close_file_n " \"%s\" failed", path.data);
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ status = NGX_HTTP_CREATED;
+ }
+
+ return ngx_http_dav_ext_lock_response(r, status, lock->timeout, depth,
+ new_token);
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_lock_response(ngx_http_request_t *r, ngx_uint_t status,
+ time_t timeout, ngx_uint_t depth, uint32_t token)
+{
+ size_t len;
+ time_t now;
+ u_char *p;
+ ngx_int_t rc;
+ ngx_buf_t *b;
+ ngx_chain_t cl;
+ ngx_table_elt_t *h;
+ ngx_http_dav_ext_entry_t entry;
+
+ static u_char head[] =
+ "\n"
+ "\n";
+
+ static u_char tail[] =
+ "\n";
+
+ now = ngx_time();
+
+ ngx_memzero(&entry, sizeof(ngx_http_dav_ext_entry_t));
+
+ entry.lock_expire = now + timeout;
+ entry.lock_root = r->uri;
+ entry.lock_infinite = depth ? 1 : 0;
+ entry.lock_token = token;
+
+ len = sizeof(head) - 1
+ + ngx_http_dav_ext_format_lockdiscovery(r, NULL, &entry)
+ + sizeof(tail) - 1;
+
+ b = ngx_create_temp_buf(r->pool, len);
+ if (b == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ b->last = ngx_cpymem(b->last, head, sizeof(head) - 1);
+ b->last = (u_char *) ngx_http_dav_ext_format_lockdiscovery(r, b->last,
+ &entry);
+ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1);
+
+ b->last_buf = (r == r->main) ? 1 : 0;
+ b->last_in_chain = 1;
+
+ cl.buf = b;
+ cl.next = NULL;
+
+ r->headers_out.status = status;
+ r->headers_out.content_length_n = b->last - b->pos;
+
+ r->headers_out.content_type_len = sizeof("text/xml") - 1;
+ ngx_str_set(&r->headers_out.content_type, "text/xml");
+ r->headers_out.content_type_lowcase = NULL;
+
+ ngx_str_set(&r->headers_out.charset, "utf-8");
+
+ h = ngx_list_push(&r->headers_out.headers);
+ if (h == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ ngx_str_set(&h->key, "Lock-Token");
+
+ p = ngx_pnalloc(r->pool, ngx_http_dav_ext_format_token(NULL, token, 1));
+ if (p == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ h->value.data = p;
+ h->value.len = (u_char *) ngx_http_dav_ext_format_token(p, token, 1) - p;
+ h->hash = 1;
+
+ rc = ngx_http_send_header(r);
+
+ if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+ return rc;
+ }
+
+ return ngx_http_output_filter(r, &cl);
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_unlock_handler(ngx_http_request_t *r)
+{
+ uint32_t token;
+ ngx_http_dav_ext_lock_t *lock;
+ ngx_http_dav_ext_node_t *node;
+ ngx_http_dav_ext_loc_conf_t *dlcf;
+
+ token = ngx_http_dav_ext_lock_token(r);
+
+ dlcf = ngx_http_get_module_loc_conf(r, ngx_http_dav_ext_module);
+ lock = dlcf->shm_zone->data;
+
+ ngx_shmtx_lock(&lock->shpool->mutex);
+
+ node = ngx_http_dav_ext_lock_lookup(r, lock, &r->uri, -1);
+
+ if (node == NULL || node->token != token) {
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+ return NGX_HTTP_NO_CONTENT;
+ }
+
+ ngx_queue_remove(&node->queue);
+ ngx_slab_free_locked(lock->shpool, node);
+
+ ngx_shmtx_unlock(&lock->shpool->mutex);
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext delete lock");
+
+ return NGX_HTTP_NO_CONTENT;
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_depth(ngx_http_request_t *r, ngx_int_t default_depth)
+{
+ ngx_table_elt_t *depth;
+
+ depth = r->headers_in.depth;
+
+ if (depth == NULL) {
+ return default_depth;
+ }
+
+ if (depth->value.len == 1) {
+
+ if (depth->value.data[0] == '0') {
+ return 0;
+ }
+
+ if (depth->value.data[0] == '1') {
+ return 1;
+ }
+
+ } else {
+
+ if (depth->value.len == sizeof("infinity") - 1
+ && ngx_strcmp(depth->value.data, "infinity") == 0)
+ {
+ return NGX_MAX_INT_T_VALUE;
+ }
+ }
+
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "client sent invalid \"Depth\" header: \"%V\"",
+ &depth->value);
+
+ return NGX_ERROR;
+}
+
+
+static uint32_t
+ngx_http_dav_ext_lock_token(ngx_http_request_t *r)
+{
+ u_char *p, ch;
+ uint32_t token;
+ ngx_uint_t i, n;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+
+ static u_char name[] = "lock-token";
+
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ for (n = 0; n < sizeof(name) - 1 && n < header[i].key.len; n++) {
+ ch = header[i].key.data[n];
+
+ if (ch >= 'A' && ch <= 'Z') {
+ ch |= 0x20;
+ }
+
+ if (name[n] != ch) {
+ break;
+ }
+ }
+
+ if (n == sizeof(name) - 1 && n == header[i].key.len) {
+ p = header[i].value.data;
+
+ if (ngx_strncmp(p, "= '0' && ch <= '9') {
+ token = token * 16 + (ch - '0');
+ continue;
+ }
+
+ ch = (u_char) (ch | 0x20);
+
+ if (ch >= 'a' && ch <= 'f') {
+ token = token * 16 + (ch - 'a' + 10);
+ continue;
+ }
+
+ return 0;
+ }
+
+ if (*p != '>') {
+ return 0;
+ }
+
+ return token;
+ }
+ }
+
+ return 0;
+}
+
+
+static uint32_t
+ngx_http_dav_ext_if(ngx_http_request_t *r, ngx_str_t *uri)
+{
+ u_char *p, ch;
+ uint32_t token;
+ ngx_str_t tag;
+ ngx_uint_t i, n;
+ ngx_list_part_t *part;
+ ngx_table_elt_t *header;
+
+ static u_char name[] = "if";
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if \"%V\"", uri);
+
+ part = &r->headers_in.headers.part;
+ header = part->elts;
+
+ for (i = 0; /* void */ ; i++) {
+
+ if (i >= part->nelts) {
+ if (part->next == NULL) {
+ break;
+ }
+
+ part = part->next;
+ header = part->elts;
+ i = 0;
+ }
+
+ for (n = 0; n < sizeof(name) - 1 && n < header[i].key.len; n++) {
+ ch = header[i].key.data[n];
+
+ if (ch >= 'A' && ch <= 'Z') {
+ ch |= 0x20;
+ }
+
+ if (name[n] != ch) {
+ break;
+ }
+ }
+
+ if (n == sizeof(name) - 1 && n == header[i].key.len) {
+ p = header[i].value.data;
+ tag = r->uri;
+
+ while (*p != '\0') {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if list \"%s\"", p);
+
+ while (*p == ' ') { p++; }
+
+ if (*p == '<') {
+ tag.data = ++p;
+
+ while (*p != '\0' && *p != '>') { p++; }
+
+ if (*p == '\0') {
+ break;
+ }
+
+ tag.len = p++ - tag.data;
+
+ (void) ngx_http_dav_ext_strip_uri(r, &tag);
+
+ while (*p == ' ') { p++; }
+ }
+
+ if (*p != '(') {
+ break;
+ }
+
+ p++;
+
+ if (tag.len == 0
+ || tag.len > uri->len
+ || (tag.len < uri->len && tag.data[tag.len - 1] != '/')
+ || ngx_memcmp(tag.data, uri->data, tag.len))
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if tag mismatch \"%V\"", &tag);
+
+ while (*p != '\0' && *p != ')') { p++; }
+
+ if (*p == ')') {
+ p++;
+ }
+
+ continue;
+ }
+
+ while (*p != '\0') {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if condition \"%s\"", p);
+
+ while (*p == ' ') { p++; }
+
+ if (ngx_strncmp(p, "Not", 3) == 0) {
+ p += 3;
+ while (*p == ' ') { p++; }
+ goto next;
+ }
+
+ if (*p == '[') {
+ p++;
+ while (*p != '\0' && *p != ']') { p++; }
+ goto next;
+ }
+
+ if (ngx_strncmp(p, "= '0' && ch <= '9') {
+ token = token * 16 + (ch - '0');
+ continue;
+ }
+
+ ch = (u_char) (ch | 0x20);
+
+ if (ch >= 'a' && ch <= 'f') {
+ token = token * 16 + (ch - 'a' + 10);
+ continue;
+ }
+
+ goto next;
+ }
+
+ if (*p != '>') {
+ goto next;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if token: %uxD", token);
+
+ return token;
+
+ next:
+
+ while (*p != '\0' && *p != ' ' && *p != ')') { p++; }
+
+ if (*p == ')') {
+ p++;
+ break;
+ }
+ }
+ }
+
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http dav_ext if header mismatch");
+ }
+ }
+
+ return 0;
+}
+
+
+static uintptr_t
+ngx_http_dav_ext_format_propfind(ngx_http_request_t *r, u_char *dst,
+ ngx_http_dav_ext_entry_t *entry, ngx_uint_t props)
+{
+ size_t len;
+
+ static u_char head[] =
+ "\n"
+ "";
+
+ /* uri */
+
+ static u_char prop[] =
+ "\n"
+ "\n"
+ "\n";
+
+ /* properties */
+
+ static u_char tail[] =
+ "\n"
+ "HTTP/1.1 200 OK\n"
+ "\n"
+ "\n";
+
+ static u_char names[] =
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n";
+
+ static u_char supportedlock[] =
+ "\n"
+ "\n"
+ "\n"
+ "\n";
+
+ if (dst == NULL) {
+ len = sizeof(head) - 1
+ + sizeof(prop) - 1
+ + sizeof(tail) - 1;
+
+ len += entry->uri.len + ngx_escape_html(NULL, entry->uri.data,
+ entry->uri.len);
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_NAMES) {
+ len += sizeof(names) - 1;
+
+ } else {
+ len += sizeof(""
+ "\n"
+
+ ""
+ "\n"
+
+ ""
+ "Mon, 28 Sep 1970 06:00:00 GMT"
+ "\n"
+
+ ""
+ ""
+ "\n"
+
+ "\n"
+ "\n") - 1;
+
+ /* displayname */
+ len += entry->name.len
+ + ngx_escape_html(NULL, entry->name.data, entry->name.len);
+
+ /* getcontentlength */
+ len += NGX_OFF_T_LEN;
+
+ /* lockdiscovery */
+ len += ngx_http_dav_ext_format_lockdiscovery(r, NULL, entry);
+
+ /* supportedlock */
+ if (entry->lock_supported) {
+ len += sizeof(supportedlock) - 1;
+ }
+ }
+
+ return len;
+ }
+
+ dst = ngx_cpymem(dst, head, sizeof(head) - 1);
+ dst = (u_char *) ngx_escape_html(dst, entry->uri.data, entry->uri.len);
+ dst = ngx_cpymem(dst, prop, sizeof(prop) - 1);
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_NAMES) {
+ dst = ngx_cpymem(dst, names, sizeof(names) - 1);
+
+ } else {
+ if (props & NGX_HTTP_DAV_EXT_PROP_DISPLAYNAME) {
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+ dst = (u_char *) ngx_escape_html(dst, entry->name.data,
+ entry->name.len);
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+ }
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_GETCONTENTLENGTH) {
+ if (!entry->dir) {
+ dst = ngx_sprintf(dst, "%O"
+ "\n", entry->size);
+ }
+ }
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_GETLASTMODIFIED) {
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+ dst = ngx_http_time(dst, entry->mtime);
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+ }
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_RESOURCETYPE) {
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+
+ if (entry->dir) {
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+ }
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+ }
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_LOCKDISCOVERY) {
+ dst = (u_char *) ngx_http_dav_ext_format_lockdiscovery(r, dst,
+ entry);
+ }
+
+ if (props & NGX_HTTP_DAV_EXT_PROP_SUPPORTEDLOCK) {
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ if (entry->lock_supported) {
+ dst = ngx_cpymem(dst, supportedlock, sizeof(supportedlock) - 1);
+ }
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+ }
+ }
+
+ dst = ngx_cpymem(dst, tail, sizeof(tail) - 1);
+
+ return (uintptr_t) dst;
+}
+
+
+static uintptr_t
+ngx_http_dav_ext_format_lockdiscovery(ngx_http_request_t *r, u_char *dst,
+ ngx_http_dav_ext_entry_t *entry)
+{
+ size_t len;
+ time_t now;
+
+ if (dst == NULL) {
+ if (entry->lock_token == 0) {
+ return sizeof("\n") - 1;
+ }
+
+ len = sizeof("\n"
+ "\n"
+ "\n"
+ "\n"
+ "infinity\n"
+ "Second-\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n") - 1;
+
+ /* timeout */
+ len += NGX_TIME_T_LEN;
+
+ /* token */
+ len += ngx_http_dav_ext_format_token(NULL, entry->lock_token, 0);
+
+ /* lockroot */
+ len += entry->lock_root.len + ngx_escape_html(NULL,
+ entry->lock_root.data,
+ entry->lock_root.len);
+ return len;
+ }
+
+ if (entry->lock_token == 0) {
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+ return (uintptr_t) dst;
+ }
+
+ now = ngx_time();
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_sprintf(dst, "%s\n",
+ entry->lock_infinite ? "infinity" : "0");
+
+ dst = ngx_sprintf(dst, "Second-%T\n",
+ entry->lock_expire - now);
+
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+ dst = (u_char *) ngx_http_dav_ext_format_token(dst, entry->lock_token, 0);
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "",
+ sizeof("") - 1);
+ dst = (u_char *) ngx_escape_html(dst, entry->lock_root.data,
+ entry->lock_root.len);
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ dst = ngx_cpymem(dst, "\n",
+ sizeof("\n") - 1);
+
+ return (uintptr_t) dst;
+}
+
+
+static uintptr_t
+ngx_http_dav_ext_format_token(u_char *dst, uint32_t token, ngx_uint_t brackets)
+{
+ ngx_uint_t n;
+
+ static u_char hex[] = "0123456789abcdef";
+
+ if (dst == NULL) {
+ return sizeof("") - 1 + (brackets ? 2 : 0);
+ }
+
+ if (brackets) {
+ *dst++ = '<';
+ }
+
+ dst = ngx_cpymem(dst, "urn:", 4);
+
+ for (n = 0; n < 4; n++) {
+ *dst++ = hex[token >> 28];
+ *dst++ = hex[(token >> 24) & 0xf];
+ token <<= 8;
+ }
+
+ if (brackets) {
+ *dst++ = '>';
+ }
+
+ return (uintptr_t) dst;
+}
+
+
+static ngx_int_t
+ngx_http_dav_ext_init_zone(ngx_shm_zone_t *shm_zone, void *data)
+{
+ ngx_http_dav_ext_lock_t *olock = data;
+
+ size_t len;
+ ngx_http_dav_ext_lock_t *lock;
+
+ lock = shm_zone->data;
+
+ if (olock) {
+ lock->sh = olock->sh;
+ lock->shpool = olock->shpool;
+ return NGX_OK;
+ }
+
+ lock->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
+
+ if (shm_zone->shm.exists) {
+ lock->sh = lock->shpool->data;
+ return NGX_OK;
+ }
+
+ lock->sh = ngx_slab_alloc(lock->shpool, sizeof(ngx_http_dav_ext_lock_sh_t));
+ if (lock->sh == NULL) {
+ return NGX_ERROR;
+ }
+
+ lock->shpool->data = lock->sh;
+
+ ngx_queue_init(&lock->sh->queue);
+
+ len = sizeof(" in dav_ext zone \"\"") + shm_zone->shm.name.len;
+
+ lock->shpool->log_ctx = ngx_slab_alloc(lock->shpool, len);
+ if (lock->shpool->log_ctx == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_sprintf(lock->shpool->log_ctx, " in dav_ext zone \"%V\"%Z",
+ &shm_zone->shm.name);
+
+ return NGX_OK;
+}
+
+
static void *
ngx_http_dav_ext_create_loc_conf(ngx_conf_t *cf)
{
- ngx_http_dav_ext_loc_conf_t *conf;
+ ngx_http_dav_ext_loc_conf_t *conf;
- conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_ext_loc_conf_t));
- if (conf == NULL) {
- return NULL;
- }
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_ext_loc_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
- return conf;
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->shm_zone = NULL;
+ */
+
+ return conf;
}
+
static char *
ngx_http_dav_ext_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
- ngx_http_dav_ext_loc_conf_t *prev = parent;
- ngx_http_dav_ext_loc_conf_t *conf = child;
+ ngx_http_dav_ext_loc_conf_t *prev = parent;
+ ngx_http_dav_ext_loc_conf_t *conf = child;
- ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
- (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_EXT_OFF));
+ ngx_conf_merge_bitmask_value(conf->methods, prev->methods,
+ (NGX_CONF_BITMASK_SET|NGX_HTTP_DAV_EXT_OFF));
- return NGX_CONF_OK;
+ if (conf->shm_zone == NULL) {
+ conf->shm_zone = prev->shm_zone;
+ }
+
+ return NGX_CONF_OK;
}
+
+static char *
+ngx_http_dav_ext_lock_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ u_char *p;
+ time_t timeout;
+ ssize_t size;
+ ngx_str_t *value, name, s;
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+ ngx_http_dav_ext_lock_t *lock;
+
+ value = cf->args->elts;
+
+ name.len = 0;
+ size = 0;
+ timeout = 60;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
+
+ name.data = value[i].data + 5;
+
+ p = (u_char *) ngx_strchr(name.data, ':');
+
+ if (p == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ name.len = p - name.data;
+
+ s.data = p + 1;
+ s.len = value[i].data + value[i].len - s.data;
+
+ size = ngx_parse_size(&s);
+
+ if (size == NGX_ERROR) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid zone size \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (size < (ssize_t) (8 * ngx_pagesize)) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "zone \"%V\" is too small", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ if (ngx_strncmp(value[i].data, "timeout=", 8) == 0) {
+
+ s.len = value[i].len - 8;
+ s.data = value[i].data + 8;
+
+ timeout = ngx_parse_time(&s, 1);
+ if (timeout == (time_t) NGX_ERROR || timeout == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid timeout value \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"zone\" parameter",
+ &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ lock = ngx_pcalloc(cf->pool, sizeof(ngx_http_dav_ext_lock_t));
+ if (lock == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ lock->timeout = timeout;
+
+ shm_zone = ngx_shared_memory_add(cf, &name, size,
+ &ngx_http_dav_ext_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (shm_zone->data) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate zone \"%V\"", &name);
+ return NGX_CONF_ERROR;
+ }
+
+ shm_zone->init = ngx_http_dav_ext_init_zone;
+ shm_zone->data = lock;
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
+ngx_http_dav_ext_lock(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_dav_ext_loc_conf_t *dlcf = conf;
+
+ ngx_str_t *value, s;
+ ngx_uint_t i;
+ ngx_shm_zone_t *shm_zone;
+
+ if (dlcf->shm_zone) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ shm_zone = NULL;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "zone=", 5) == 0) {
+
+ s.len = value[i].len - 5;
+ s.data = value[i].data + 5;
+
+ shm_zone = ngx_shared_memory_add(cf, &s, 0,
+ &ngx_http_dav_ext_module);
+ if (shm_zone == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ continue;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (shm_zone == NULL) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "\"%V\" must have \"zone\" parameter", &cmd->name);
+ return NGX_CONF_ERROR;
+ }
+
+ dlcf->shm_zone = shm_zone;
+
+ return NGX_CONF_OK;
+}
+
+
static ngx_int_t
ngx_http_dav_ext_init(ngx_conf_t *cf)
{
- ngx_http_handler_pt *h;
- ngx_http_core_main_conf_t *cmcf;
+ ngx_http_handler_pt *h;
+ ngx_http_core_main_conf_t *cmcf;
- cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
- h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_PRECONTENT_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
- if (h == NULL) {
- return NGX_ERROR;
- }
+ *h = ngx_http_dav_ext_precontent_handler;
- *h = ngx_http_dav_ext_handler;
+ h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
- return NGX_OK;
+ *h = ngx_http_dav_ext_content_handler;
+
+ return NGX_OK;
}
-
diff --git a/debian/modules/http-dav-ext/t/dav_ext.t b/debian/modules/http-dav-ext/t/dav_ext.t
new file mode 100644
index 0000000..00327e2
--- /dev/null
+++ b/debian/modules/http-dav-ext/t/dav_ext.t
@@ -0,0 +1,141 @@
+#!/usr/bin/perl
+
+# (C) Roman Arutyunyan
+
+# Tests for nginx-dav-ext-module.
+
+###############################################################################
+
+use warnings;
+use strict;
+
+use Test::More;
+
+BEGIN { use FindBin; chdir($FindBin::Bin); }
+
+use lib 'lib';
+use Test::Nginx;
+use HTTP::DAV
+
+###############################################################################
+
+select STDERR; $| = 1;
+select STDOUT; $| = 1;
+
+my $t = Test::Nginx->new()->has(qw/http dav/)->plan(20);
+
+$t->write_file_expand('nginx.conf', <<'EOF');
+
+%%TEST_GLOBALS%%
+
+daemon off;
+
+events {
+}
+
+http {
+ %%TEST_GLOBALS_HTTP%%
+
+ dav_ext_lock_zone zone=foo:10m timeout=10s;
+
+ server {
+ listen 127.0.0.1:8080;
+ server_name localhost;
+
+ location / {
+ dav_methods PUT DELETE MKCOL COPY MOVE;
+ dav_ext_methods PROPFIND OPTIONS LOCK UNLOCK;
+ dav_ext_lock zone=foo;
+ }
+ }
+}
+
+EOF
+
+$t->write_file('foo', 'foo');
+
+$t->run();
+
+###############################################################################
+
+my $url = "http://127.0.0.1:8080";
+
+my $content;
+
+my $d = HTTP::DAV->new();
+$d->open($url);
+
+my $d2 = HTTP::DAV->new();
+$d2->open($url);
+
+#debug:
+#$d->DebugLevel(3);
+#see /tmp/perldav_debug.txt.
+
+my $p = $d->propfind('/', 1);
+is($p->is_collection, 1, 'propfind dir collection');
+is($p->get_property('displayname'), '/', 'propfind dir displayname');
+is($p->get_uri(), 'http://127.0.0.1:8080/', 'propfind dir uri');
+
+$p = $d->propfind('/foo');
+is($p->is_collection, 0, 'propfind file collection');
+is($p->get_property('displayname'), 'foo', 'propfind file displayname');
+is($p->get_uri(), 'http://127.0.0.1:8080/foo', 'propfind file uri');
+is($p->get_property('getcontentlength'), '3', 'propfind file size');
+
+$d->lock('/foo');
+is($d->lock('/foo'), 0, 'prevent double lock');
+
+$d->unlock('/foo');
+is($d->lock('/foo'), 1, 'relock');
+
+$d->lock('/bar');
+$p = $d->propfind('/bar');
+is($p->get_property('displayname'), 'bar', 'lock creates a file');
+
+$d->get('/bar', \$content) or $content = 'none';
+is($content, '', 'lock creates an empty file');
+
+$content = "bar";
+$d->put(\$content, '/bar');
+$d->get('/bar', \$content) or $content = '';
+is($content, 'bar', 'put lock');
+
+$content = "qux";
+$d2->put(\$content, '/bar');
+$d2->get('/bar', \$content) or $content = '';
+isnt($content, 'qux', 'prevent put lock');
+
+$d->mkcol('/d/');
+$d->lock('/d/');
+$d->copy('/bar', '/d/bar');
+$d->get('/d/bar', \$content) or $content = '';
+is($content, 'bar', 'copy lock');
+
+$d2->copy('/bar', '/d/qux');
+$d2->get('/d/qux', \$content) or $content = '';
+isnt($content, 'bar', 'prevent copy lock');
+
+$d2->delete('/d/bar');
+$d2->get('/d/bar', \$content) or $content = '';
+is($content, 'bar', 'prevent delete lock');
+
+$d->delete('/d/bar');
+$d->get('/d/bar', \$content) or $content = '';
+is($content, '', 'delete lock');
+
+$d->mkcol('/d/c/');
+$p = $d->propfind('/d/c/');
+is($p->is_collection, 1, 'mkcol lock');
+
+$d2->mkcol('/d/e/');
+is($d2->propfind('/d/e/'), 0, 'prevent mkcol lock');
+
+$d->unlock('/d/');
+$d->lock('/d/', -depth=>"0");
+$content = 'qux';
+$d2->put(\$content, '/d/c/qux');
+$d2->get('/d/c/qux', \$content) or $content = '';
+is($content, 'qux', 'put to a depth-0-locked subdirectory');
+
+###############################################################################
From 76804da3f86a8768da221624fe4cd1754d49c3bc Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 27 Dec 2018 13:01:09 +0200
Subject: [PATCH 008/334] Use a minimal export of the upstream signing key
Exported with:
$ gpg --finger 0x520A9993A1C052F8
pub rsa2048/0x520A9993A1C052F8 2011-11-27 [SC]
Key fingerprint = B0F4 2533 73F8 F6F5 10D4 2178 520A 9993 A1C0 52F8
uid [ unknown] Maxim Dounin
sub rsa2048/0x57A82F1DD345AB09 2011-11-27 [E]
$ gpg --export --export-options export-minimal --armor '0x520A9993A1C052F8'
---
debian/upstream/signing-key.asc | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/debian/upstream/signing-key.asc b/debian/upstream/signing-key.asc
index 45a8f7c..01a2a5f 100644
--- a/debian/upstream/signing-key.asc
+++ b/debian/upstream/signing-key.asc
@@ -6,12 +6,7 @@ hblmmUBLNgOWgLo3W+FYhl3mz1GFS2Fvid6Tfn02L8CBAj7jxbjL1Qj/OA/WmLLc
m6BMTqI7IBlYW2vyIOIHasISGiAwZfp0ucMeXXvTtt14LGa8qXVcFnJTdwbf03AS
ljhYrQnKnpl3VpDAoQt8C68YCwjaNJW59hKqWB+XeIJ9CW98+EOAxLAFszSyGanp
rCqPd0numj9TIddjcRkTA/ZbmCWK+xjpVBGXABEBAAG0IU1heGltIERvdW5pbiA8
-bWRvdW5pbkBtZG91bmluLnJ1PohGBBARAgAGBQJO01Y/AAoJEOzw6QssFyCDVyQA
-n3qwTZlcZgyyzWu9Cs8gJ0CXREaSAJ92QjGLT9DijTcbB+q9OS/nl16Z/IhGBBAR
-AgAGBQJO02JDAAoJEKk3YTmlJMU+P64AnjCKEXFelSVMtgefJk3+vpyt3QX1AKCH
-9M3MbTWPeDUL+MpULlfdyfvjj4heBBARCAAGBQJRCTwgAAoJEFGFCWhsfl6CzF0B
-AJsQ3DJbtGcZ+0VIcM2a06RRQfBvIHqm1A/1WSYmObLGAP90lxWlNjSugvUUlqTk
-YEEgRTGozgixSyMWGJrNwqgMYokBOAQTAQIAIgUCTtIq7wIbAwYLCQgHAwIGFQgC
+bWRvdW5pbkBtZG91bmluLnJ1PokBOAQTAQIAIgUCTtIq7wIbAwYLCQgHAwIGFQgC
CQoLBBYCAwECHgECF4AACgkQUgqZk6HAUvj+iwf/b4FS6zVzJ5T0v1vcQGD4ZzXe
D5xMC4BJW414wVMU15rfX7aCdtoCYBNiApPxEd7SwiyxWRhRA9bikUq87JEgmnyV
0iYbHZvCvc1jOkx4WR7E45t1Mi29KBoPaFXA9X5adZkYcOQLDxa2Z8m6LGXnlF6N
@@ -30,5 +25,5 @@ s0nkWxnOIidTHSXvBZfDFA4Idwte94Thrzf8Pn8UESudTiqrWoCBXk2UyVsl03gJ
blSJAeJGYPPeo+Yj6m63OWe2+/S2VTgmbPS/RObn0Aeg7yuff0n5+ytEt2KL51gO
QE2uIxTCawHr12PsllPkbqPk/PagIttfEJqn9b0CrqPC3HREePb2aMJ/Ctw/76CO
wn0mtXeIXLCTvBmznXfaMKllsqbsy2nCJ2P2uJjOntw=
-=ISka
+=NeQn
-----END PGP PUBLIC KEY BLOCK-----
From 52307bcf975e40fec93e1d800f3640cb29f5a41f Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 27 Dec 2018 13:09:24 +0200
Subject: [PATCH 009/334] Bump Standards-Version, no changes needed
---
debian/control | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/control b/debian/control
index eb41c42..409dc22 100644
--- a/debian/control
+++ b/debian/control
@@ -20,7 +20,7 @@ Build-Depends: debhelper (>= 10),
po-debconf,
quilt,
zlib1g-dev
-Standards-Version: 4.1.4
+Standards-Version: 4.3.0
Homepage: https://nginx.net
Vcs-Git: https://salsa.debian.org/nginx-team/nginx.git
Vcs-Browser: https://salsa.debian.org/nginx-team/nginx
From 62a54a8ba66ee6cc1b4f8a33dab9a6f27a3fdac4 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 27 Dec 2018 12:50:00 +0200
Subject: [PATCH 010/334] Release 1.14.2-2
---
debian/changelog | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/debian/changelog b/debian/changelog
index 7c48775..be5df64 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,11 +1,14 @@
-nginx (1.14.2-2) UNRELEASED; urgency=low
+nginx (1.14.2-2) unstable; urgency=medium
[ Kartik Mistry ]
* po/tr.po:
+ Added Turkish translation. Thanks Atila KOÇ
(Closes: #915728)
- -- Kartik Mistry Thu, 06 Dec 2018 20:01:00 +0530
+ [ Christos Trochalakis ]
+ * http-dav-ext: Upgrade to 3.0.0 (Closes: #851651)
+
+ -- Christos Trochalakis Thu, 27 Dec 2018 12:49:34 +0200
nginx (1.14.2-1) unstable; urgency=medium
From 214580d479a6ed6f923f6b985b97aa88bad59438 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Thu, 27 Dec 2018 14:44:09 +0200
Subject: [PATCH 011/334] Add missing changelog entries
Those were forgotten during the upload, but let's add them
for completeness.
---
debian/changelog | 2 ++
1 file changed, 2 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index be5df64..93a36f2 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -7,6 +7,8 @@ nginx (1.14.2-2) unstable; urgency=medium
[ Christos Trochalakis ]
* http-dav-ext: Upgrade to 3.0.0 (Closes: #851651)
+ * Use a minimal export of the upstream signing key
+ * Bump Standards-Version, no changes needed
-- Christos Trochalakis Thu, 27 Dec 2018 12:49:34 +0200
From d2bacdb1cf1068437e9ac89e334c4fe130f0107c Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Mon, 19 Aug 2019 11:33:14 +0300
Subject: [PATCH 012/334] Handle CVE-2019-9511 CVE-2019-9513 CVE-2019-9516
Several security issues were identified in nginx HTTP/2
implementation, which might cause excessive memory consumption
and CPU usage (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
The issues affect nginx compiled with the ngx_http_v2_module (not
compiled by default) if the "http2" option of the "listen" directive
is used in a configuration file.
The issues affect nginx 1.9.5 - 1.17.2.
The issues are fixed in nginx 1.17.3, 1.16.1.
Thanks to Jonathan Looney from Netflix for discovering these issues.
---
debian/patches/CVE-2019-9511.patch | 87 ++++++++++++++++++++++++++++++
debian/patches/CVE-2019-9513.patch | 62 +++++++++++++++++++++
debian/patches/CVE-2019-9516.patch | 45 ++++++++++++++++
debian/patches/series | 3 ++
4 files changed, 197 insertions(+)
create mode 100644 debian/patches/CVE-2019-9511.patch
create mode 100644 debian/patches/CVE-2019-9513.patch
create mode 100644 debian/patches/CVE-2019-9516.patch
diff --git a/debian/patches/CVE-2019-9511.patch b/debian/patches/CVE-2019-9511.patch
new file mode 100644
index 0000000..3b48e0c
--- /dev/null
+++ b/debian/patches/CVE-2019-9511.patch
@@ -0,0 +1,87 @@
+From 3f64486e0c15414dc6368139453dcaca338ddf3e Mon Sep 17 00:00:00 2001
+From: Ruslan Ermilov
+Date: Tue, 13 Aug 2019 15:43:36 +0300
+Subject: [PATCH 2/3] HTTP/2: limited number of DATA frames.
+
+Fixed excessive memory growth and CPU usage if stream windows are
+manipulated in a way that results in generating many small DATA frames.
+Fix is to limit the number of simultaneously allocated DATA frames.
+---
+ src/http/v2/ngx_http_v2.c | 2 ++
+ src/http/v2/ngx_http_v2.h | 2 ++
+ src/http/v2/ngx_http_v2_filter_module.c | 22 +++++++++++++++++-----
+ 3 files changed, 21 insertions(+), 5 deletions(-)
+
+diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
+index be2ef82b..1b01f271 100644
+--- a/src/http/v2/ngx_http_v2.c
++++ b/src/http/v2/ngx_http_v2.c
+@@ -4339,6 +4339,8 @@ ngx_http_v2_close_stream(ngx_http_v2_stream_t *stream, ngx_int_t rc)
+ */
+ pool = stream->pool;
+
++ h2c->frames -= stream->frames;
++
+ ngx_http_free_request(stream->request, rc);
+
+ if (pool != h2c->state.pool) {
+diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
+index bec22160..715b7d30 100644
+--- a/src/http/v2/ngx_http_v2.h
++++ b/src/http/v2/ngx_http_v2.h
+@@ -192,6 +192,8 @@ struct ngx_http_v2_stream_s {
+
+ ngx_buf_t *preread;
+
++ ngx_uint_t frames;
++
+ ngx_http_v2_out_frame_t *free_frames;
+ ngx_chain_t *free_frame_headers;
+ ngx_chain_t *free_bufs;
+diff --git a/src/http/v2/ngx_http_v2_filter_module.c b/src/http/v2/ngx_http_v2_filter_module.c
+index 029e8ece..c7ee5536 100644
+--- a/src/http/v2/ngx_http_v2_filter_module.c
++++ b/src/http/v2/ngx_http_v2_filter_module.c
+@@ -1661,22 +1661,34 @@ static ngx_http_v2_out_frame_t *
+ ngx_http_v2_filter_get_data_frame(ngx_http_v2_stream_t *stream,
+ size_t len, ngx_chain_t *first, ngx_chain_t *last)
+ {
+- u_char flags;
+- ngx_buf_t *buf;
+- ngx_chain_t *cl;
+- ngx_http_v2_out_frame_t *frame;
++ u_char flags;
++ ngx_buf_t *buf;
++ ngx_chain_t *cl;
++ ngx_http_v2_out_frame_t *frame;
++ ngx_http_v2_connection_t *h2c;
+
+ frame = stream->free_frames;
++ h2c = stream->connection;
+
+ if (frame) {
+ stream->free_frames = frame->next;
+
+- } else {
++ } else if (h2c->frames < 10000) {
+ frame = ngx_palloc(stream->request->pool,
+ sizeof(ngx_http_v2_out_frame_t));
+ if (frame == NULL) {
+ return NULL;
+ }
++
++ stream->frames++;
++ h2c->frames++;
++
++ } else {
++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
++ "http2 flood detected");
++
++ h2c->connection->error = 1;
++ return NULL;
+ }
+
+ flags = last->buf->last_buf ? NGX_HTTP_V2_END_STREAM_FLAG : 0;
+--
+2.20.1
+
diff --git a/debian/patches/CVE-2019-9513.patch b/debian/patches/CVE-2019-9513.patch
new file mode 100644
index 0000000..edc1c2b
--- /dev/null
+++ b/debian/patches/CVE-2019-9513.patch
@@ -0,0 +1,62 @@
+From bbdc81631b6d322785d8e92788fd400e25a931e6 Mon Sep 17 00:00:00 2001
+From: Ruslan Ermilov
+Date: Tue, 13 Aug 2019 15:43:40 +0300
+Subject: [PATCH 3/3] HTTP/2: limited number of PRIORITY frames.
+
+Fixed excessive CPU usage caused by a peer that continuously shuffles
+priority of streams. Fix is to limit the number of PRIORITY frames.
+---
+ src/http/v2/ngx_http_v2.c | 10 ++++++++++
+ src/http/v2/ngx_http_v2.h | 1 +
+ 2 files changed, 11 insertions(+)
+
+diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
+index 1b01f271..fd6ecb05 100644
+--- a/src/http/v2/ngx_http_v2.c
++++ b/src/http/v2/ngx_http_v2.c
+@@ -275,6 +275,7 @@ ngx_http_v2_init(ngx_event_t *rev)
+ h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);
+
+ h2c->concurrent_pushes = h2scf->concurrent_pushes;
++ h2c->priority_limit = h2scf->concurrent_streams;
+
+ h2c->pool = ngx_create_pool(h2scf->pool_size, h2c->connection->log);
+ if (h2c->pool == NULL) {
+@@ -1806,6 +1807,13 @@ ngx_http_v2_state_priority(ngx_http_v2_connection_t *h2c, u_char *pos,
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
+ }
+
++ if (--h2c->priority_limit == 0) {
++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
++ "client sent too many PRIORITY frames");
++
++ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_ENHANCE_YOUR_CALM);
++ }
++
+ if (end - pos < NGX_HTTP_V2_PRIORITY_SIZE) {
+ return ngx_http_v2_state_save(h2c, pos, end,
+ ngx_http_v2_state_priority);
+@@ -3120,6 +3128,8 @@ ngx_http_v2_create_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t push)
+ h2c->processing++;
+ }
+
++ h2c->priority_limit += h2scf->concurrent_streams;
++
+ return stream;
+ }
+
+diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h
+index 715b7d30..69d55d1c 100644
+--- a/src/http/v2/ngx_http_v2.h
++++ b/src/http/v2/ngx_http_v2.h
+@@ -122,6 +122,7 @@ struct ngx_http_v2_connection_s {
+ ngx_uint_t processing;
+ ngx_uint_t frames;
+ ngx_uint_t idle;
++ ngx_uint_t priority_limit;
+
+ ngx_uint_t pushing;
+ ngx_uint_t concurrent_pushes;
+--
+2.20.1
+
diff --git a/debian/patches/CVE-2019-9516.patch b/debian/patches/CVE-2019-9516.patch
new file mode 100644
index 0000000..0d5ec77
--- /dev/null
+++ b/debian/patches/CVE-2019-9516.patch
@@ -0,0 +1,45 @@
+From 840d8a3e2f126384eb4ee3e5dd7ffe875a5634c5 Mon Sep 17 00:00:00 2001
+From: Sergey Kandaurov
+Date: Tue, 13 Aug 2019 15:43:32 +0300
+Subject: [PATCH 1/3] HTTP/2: reject zero length headers with PROTOCOL_ERROR.
+
+Fixed uncontrolled memory growth if peer sends a stream of
+headers with a 0-length header name and 0-length header value.
+Fix is to reject headers with zero name length.
+---
+ src/http/v2/ngx_http_v2.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
+index 12214e15..be2ef82b 100644
+--- a/src/http/v2/ngx_http_v2.c
++++ b/src/http/v2/ngx_http_v2.c
+@@ -1548,6 +1548,14 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos,
+ header->name.len = h2c->state.field_end - h2c->state.field_start;
+ header->name.data = h2c->state.field_start;
+
++ if (header->name.len == 0) {
++ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
++ "client sent zero header name length");
++
++ return ngx_http_v2_connection_error(h2c,
++ NGX_HTTP_V2_PROTOCOL_ERROR);
++ }
++
+ return ngx_http_v2_state_field_len(h2c, pos, end);
+ }
+
+@@ -3249,10 +3257,6 @@ ngx_http_v2_validate_header(ngx_http_request_t *r, ngx_http_v2_header_t *header)
+ ngx_uint_t i;
+ ngx_http_core_srv_conf_t *cscf;
+
+- if (header->name.len == 0) {
+- return NGX_ERROR;
+- }
+-
+ r->invalid_header = 0;
+
+ cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+--
+2.20.1
+
diff --git a/debian/patches/series b/debian/patches/series
index 5b6b799..dfc20c1 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,5 @@
0002-Make-sure-signature-stays-the-same-in-all-nginx-buil.patch
0003-define_gnu_source-on-other-glibc-based-platforms.patch
+CVE-2019-9516.patch
+CVE-2019-9511.patch
+CVE-2019-9513.patch
From 71e4915c0fcf970abed0d8c66a3cf86870ea0976 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Mon, 19 Aug 2019 11:33:27 +0300
Subject: [PATCH 013/334] Release 1.14.2-3
---
debian/changelog | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 93a36f2..509cc2b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,12 @@
+nginx (1.14.2-3) unstable; urgency=high
+
+ * Backport upstream fixes for 3 CVEs (Closes: #935037)
+ Those fixes affect Nginx HTTP/2 implementation, which might cause
+ excessive memory consumption and CPU usage.
+ (CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
+
+ -- Christos Trochalakis Mon, 19 Aug 2019 11:30:08 +0300
+
nginx (1.14.2-2) unstable; urgency=medium
[ Kartik Mistry ]
From deba07f09f0f530f083263c966e72331911a28a4 Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Sun, 8 Sep 2019 10:33:34 +0300
Subject: [PATCH 014/334] Follow stable 1.16 releases
---
debian/watch | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/debian/watch b/debian/watch
index 42f4680..1aeff3e 100644
--- a/debian/watch
+++ b/debian/watch
@@ -1,3 +1,3 @@
version=3
opts=pgpsigurlmangle=s/$/.asc/ \
-https://nginx.org/download/nginx-(1\.14\.\d+)\.tar\.gz
+https://nginx.org/download/nginx-(1\.16\.\d+)\.tar\.gz
From c717ecb9266f65e0bd1579588710a2782bbb8e1f Mon Sep 17 00:00:00 2001
From: Christos Trochalakis
Date: Sun, 8 Sep 2019 10:36:13 +0300
Subject: [PATCH 015/334] New upstream version 1.16.1
---
CHANGES | 254 +++-
CHANGES.ru | 260 +++-
LICENSE | 4 +-
auto/cc/clang | 3 +-
auto/cc/msvc | 2 +-
auto/lib/google-perftools/conf | 3 +-
auto/lib/libgd/conf | 6 +-
auto/lib/libxslt/conf | 4 +-
auto/make | 2 +-
auto/modules | 21 +
auto/options | 10 +
auto/os/linux | 2 +
auto/os/win32 | 8 +-
auto/sources | 2 +
conf/mime.types | 4 +-
contrib/vim/syntax/nginx.vim | 79 +-
html/50x.html | 2 +-
src/core/nginx.h | 4 +-
src/core/ngx_buf.c | 1 +
src/core/ngx_conf_file.c | 9 +-
src/core/ngx_connection.c | 71 +-
src/core/ngx_connection.h | 7 +-
src/core/ngx_core.h | 1 +
src/core/ngx_cycle.c | 67 +-
src/core/ngx_file.c | 27 +-
src/core/ngx_inet.c | 468 +++---
src/core/ngx_inet.h | 2 +
src/core/ngx_output_chain.c | 64 +-
src/core/ngx_resolver.c | 133 +-
src/core/ngx_slab.c | 3 +-
src/core/ngx_string.c | 10 +-
src/core/ngx_string.h | 2 +
src/core/ngx_syslog.c | 38 +-
src/core/ngx_syslog.h | 1 -
src/core/ngx_times.h | 4 +-
src/event/modules/ngx_eventport_module.c | 2 -
src/event/modules/ngx_poll_module.c | 2 +-
src/event/modules/ngx_win32_poll_module.c | 435 ++++++
src/event/modules/ngx_win32_select_module.c | 17 +-
src/event/ngx_event.c | 40 +
src/event/ngx_event.h | 9 +-
src/event/ngx_event_accept.c | 346 +----
src/event/ngx_event_connect.c | 16 +-
src/event/ngx_event_connect.h | 2 +
src/event/ngx_event_openssl.c | 1267 ++++++++++++++---
src/event/ngx_event_openssl.h | 27 +-
src/event/ngx_event_openssl_stapling.c | 7 +-
src/event/ngx_event_udp.c | 663 +++++++++
src/http/modules/ngx_http_autoindex_module.c | 70 +-
src/http/modules/ngx_http_dav_module.c | 4 +-
src/http/modules/ngx_http_fastcgi_module.c | 13 +-
src/http/modules/ngx_http_geo_module.c | 13 +
src/http/modules/ngx_http_grpc_module.c | 21 +-
src/http/modules/ngx_http_limit_req_module.c | 63 +-
src/http/modules/ngx_http_memcached_module.c | 13 +-
src/http/modules/ngx_http_proxy_module.c | 21 +-
.../modules/ngx_http_random_index_module.c | 2 +-
src/http/modules/ngx_http_rewrite_module.c | 10 +-
src/http/modules/ngx_http_scgi_module.c | 13 +-
src/http/modules/ngx_http_ssl_module.c | 190 ++-
src/http/modules/ngx_http_ssl_module.h | 4 +
.../modules/ngx_http_upstream_hash_module.c | 8 +-
.../ngx_http_upstream_ip_hash_module.c | 8 +-
.../ngx_http_upstream_keepalive_module.c | 41 +-
.../modules/ngx_http_upstream_random_module.c | 502 +++++++
.../modules/ngx_http_userid_filter_module.c | 7 +
src/http/modules/ngx_http_uwsgi_module.c | 31 +-
src/http/ngx_http.c | 38 +-
src/http/ngx_http.h | 4 +
src/http/ngx_http_core_module.c | 87 +-
src/http/ngx_http_core_module.h | 8 +-
src/http/ngx_http_file_cache.c | 44 +-
src/http/ngx_http_parse.c | 5 +
src/http/ngx_http_request.c | 252 +++-
src/http/ngx_http_request.h | 5 +
src/http/ngx_http_script.c | 28 +
src/http/ngx_http_script.h | 2 +
src/http/ngx_http_special_response.c | 68 +-
src/http/ngx_http_upstream.c | 89 +-
src/http/ngx_http_upstream.h | 4 +-
src/http/ngx_http_upstream_round_robin.c | 2 +-
src/http/ngx_http_variables.c | 4 +-
src/http/ngx_http_write_filter_module.c | 40 +-
src/http/v2/ngx_http_v2.c | 96 +-
src/http/v2/ngx_http_v2.h | 3 +
src/http/v2/ngx_http_v2_filter_module.c | 48 +-
src/mail/ngx_mail.c | 42 +-
src/mail/ngx_mail.h | 3 +-
src/mail/ngx_mail_core_module.c | 92 +-
src/mail/ngx_mail_handler.c | 18 +-
src/mail/ngx_mail_ssl_module.c | 96 +-
src/mail/ngx_mail_ssl_module.h | 1 +
src/os/unix/ngx_file_aio_read.c | 2 +-
src/os/unix/ngx_files.h | 3 -
src/os/unix/ngx_freebsd_config.h | 6 +
src/os/unix/ngx_thread.h | 4 +-
src/stream/ngx_stream.c | 46 +-
src/stream/ngx_stream.h | 3 +-
src/stream/ngx_stream_core_module.c | 121 +-
src/stream/ngx_stream_geo_module.c | 13 +
src/stream/ngx_stream_proxy_module.c | 279 +++-
src/stream/ngx_stream_ssl_module.c | 238 +++-
src/stream/ngx_stream_ssl_module.h | 7 +
src/stream/ngx_stream_ssl_preread_module.c | 111 +-
src/stream/ngx_stream_upstream.c | 16 +-
src/stream/ngx_stream_upstream.h | 2 +
src/stream/ngx_stream_upstream_hash_module.c | 8 +-
.../ngx_stream_upstream_random_module.c | 502 +++++++
src/stream/ngx_stream_upstream_round_robin.c | 2 +-
src/stream/ngx_stream_write_filter_module.c | 40 +-
110 files changed, 6258 insertions(+), 1669 deletions(-)
create mode 100644 src/event/modules/ngx_win32_poll_module.c
create mode 100644 src/event/ngx_event_udp.c
create mode 100644 src/http/modules/ngx_http_upstream_random_module.c
create mode 100644 src/stream/ngx_stream_upstream_random_module.c
diff --git a/CHANGES b/CHANGES
index 597c270..8e7382b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,38 +1,99 @@
-Changes with nginx 1.14.2 04 Dec 2018
+Changes with nginx 1.16.1 13 Aug 2019
- *) Bugfix: nginx could not be built by gcc 8.1.
+ *) Security: when using HTTP/2 a client might cause excessive memory
+ consumption and CPU usage (CVE-2019-9511, CVE-2019-9513,
+ CVE-2019-9516).
- *) Bugfix: nginx could not be built on Fedora 28 Linux.
- *) Bugfix: in handling of client addresses when using unix domain listen
- sockets to work with datagrams on Linux.
+Changes with nginx 1.16.0 23 Apr 2019
- *) Change: the logging level of the "http request", "https proxy
- request", "unsupported protocol", "version too low", "no suitable key
- share", and "no suitable signature algorithm" SSL errors has been
- lowered from "crit" to "info".
+ *) 1.16.x stable branch.
- *) Bugfix: when using OpenSSL 1.1.0 or newer it was not possible to
- switch off "ssl_prefer_server_ciphers" in a virtual server if it was
- switched on in the default server.
- *) Bugfix: nginx could not be built with LibreSSL 2.8.0.
+Changes with nginx 1.15.12 16 Apr 2019
- *) Bugfix: if nginx was built with OpenSSL 1.1.0 and used with OpenSSL
- 1.1.1, the TLS 1.3 protocol was always enabled.
+ *) Bugfix: a segmentation fault might occur in a worker process if
+ variables were used in the "ssl_certificate" or "ssl_certificate_key"
+ directives and OCSP stapling was enabled.
- *) Bugfix: sending a disk-buffered request body to a gRPC backend might
- fail.
- *) Bugfix: connections with some gRPC backends might not be cached when
- using the "keepalive" directive.
+Changes with nginx 1.15.11 09 Apr 2019
+
+ *) Bugfix: in the "ssl_stapling_file" directive on Windows.
+
+
+Changes with nginx 1.15.10 26 Mar 2019
+
+ *) Change: when using a hostname in the "listen" directive nginx now
+ creates listening sockets for all addresses the hostname resolves to
+ (previously, only the first address was used).
+
+ *) Feature: port ranges in the "listen" directive.
+
+ *) Feature: loading of SSL certificates and secret keys from variables.
+
+ *) Workaround: the $ssl_server_name variable might be empty when using
+ OpenSSL 1.1.1.
+
+ *) Bugfix: nginx/Windows could not be built with Visual Studio 2015 or
+ newer; the bug had appeared in 1.15.9.
+
+
+Changes with nginx 1.15.9 26 Feb 2019
+
+ *) Feature: variables support in the "ssl_certificate" and
+ "ssl_certificate_key" directives.
+
+ *) Feature: the "poll" method is now available on Windows when using
+ Windows Vista or newer.
+
+ *) Bugfix: if the "select" method was used on Windows and an error
+ occurred while establishing a backend connection, nginx waited for
+ the connection establishment timeout to expire.
+
+ *) Bugfix: the "proxy_upload_rate" and "proxy_download_rate" directives
+ in the stream module worked incorrectly when proxying UDP datagrams.
+
+
+Changes with nginx 1.15.8 25 Dec 2018
+
+ *) Feature: the $upstream_bytes_sent variable.
+ Thanks to Piotr Sikora.
+
+ *) Feature: new directives in vim syntax highlighting scripts.
+ Thanks to Gena Makhomed.
+
+ *) Bugfix: in the "proxy_cache_background_update" directive.
+
+ *) Bugfix: in the "geo" directive when using unix domain listen sockets.
+
+ *) Workaround: the "ignoring stale global SSL error ... bad length"
+ alerts might appear in logs when using the "ssl_early_data" directive
+ with OpenSSL.
+
+ *) Bugfix: in nginx/Windows.
+
+ *) Bugfix: in the ngx_http_autoindex_module on 32-bit platforms.
+
+
+Changes with nginx 1.15.7 27 Nov 2018
+
+ *) Feature: the "proxy_requests" directive in the stream module.
+
+ *) Feature: the "delay" parameter of the "limit_req" directive.
+ Thanks to Vladislav Shabanov and Peter Shchuchkin.
+
+ *) Bugfix: memory leak on errors during reconfiguration.
+
+ *) Bugfix: in the $upstream_response_time, $upstream_connect_time, and
+ $upstream_header_time variables.
*) Bugfix: a segmentation fault might occur in a worker process if the
ngx_http_mp4_module was used on 32-bit platforms.
-Changes with nginx 1.14.1 06 Nov 2018
+Changes with nginx 1.15.6 06 Nov 2018
*) Security: when using HTTP/2 a client might cause excessive memory
consumption (CVE-2018-16843) and CPU usage (CVE-2018-16844).
@@ -41,13 +102,162 @@ Changes with nginx 1.14.1 06 Nov 2018
ngx_http_mp4_module might result in worker process memory disclosure
(CVE-2018-16845).
+ *) Feature: the "proxy_socket_keepalive", "fastcgi_socket_keepalive",
+ "grpc_socket_keepalive", "memcached_socket_keepalive",
+ "scgi_socket_keepalive", and "uwsgi_socket_keepalive" directives.
+
+ *) Bugfix: if nginx was built with OpenSSL 1.1.0 and used with OpenSSL
+ 1.1.1, the TLS 1.3 protocol was always enabled.
+
*) Bugfix: working with gRPC backends might result in excessive memory
consumption.
-Changes with nginx 1.14.0 17 Apr 2018
+Changes with nginx 1.15.5 02 Oct 2018
- *) 1.14.x stable branch.
+ *) Bugfix: a segmentation fault might occur in a worker process when
+ using OpenSSL 1.1.0h or newer; the bug had appeared in 1.15.4.
+
+ *) Bugfix: of minor potential bugs.
+
+
+Changes with nginx 1.15.4 25 Sep 2018
+
+ *) Feature: now the "ssl_early_data" directive can be used with OpenSSL.
+
+ *) Bugfix: in the ngx_http_uwsgi_module.
+ Thanks to Chris Caputo.
+
+ *) Bugfix: connections with some gRPC backends might not be cached when
+ using the "keepalive" directive.
+
+ *) Bugfix: a socket leak might occur when using the "error_page"
+ directive to redirect early request processing errors, notably errors
+ with code 400.
+
+ *) Bugfix: the "return" directive did not change the response code when
+ returning errors if the request was redirected by the "error_page"
+ directive.
+
+ *) Bugfix: standard error pages and responses of the
+ ngx_http_autoindex_module module used the "bgcolor" attribute, and
+ might be displayed incorrectly when using custom color settings in
+ browsers.
+ Thanks to Nova DasSarma.
+
+ *) Change: the logging level of the "no suitable key share" and "no
+ suitable signature algorithm" SSL errors has been lowered from "crit"
+ to "info".
+
+
+Changes with nginx 1.15.3 28 Aug 2018
+
+ *) Feature: now TLSv1.3 can be used with BoringSSL.
+
+ *) Feature: the "ssl_early_data" directive, currently available with
+ BoringSSL.
+
+ *) Feature: the "keepalive_timeout" and "keepalive_requests" directives
+ in the "upstream" block.
+
+ *) Bugfix: the ngx_http_dav_module did not truncate destination file
+ when copying a file over an existing one with the COPY method.
+
+ *) Bugfix: the ngx_http_dav_module used zero access rights on the
+ destination file and did not preserve file modification time when
+ moving a file between different file systems with the MOVE method.
+
+ *) Bugfix: the ngx_http_dav_module used default access rights when
+ copying a file with the COPY method.
+
+ *) Workaround: some clients might not work when using HTTP/2; the bug
+ had appeared in 1.13.5.
+
+ *) Bugfix: nginx could not be built with LibreSSL 2.8.0.
+
+
+Changes with nginx 1.15.2 24 Jul 2018
+
+ *) Feature: the $ssl_preread_protocol variable in the
+ ngx_stream_ssl_preread_module.
+
+ *) Feature: now when using the "reset_timedout_connection" directive
+ nginx will reset connections being closed with the 444 code.
+
+ *) Change: a logging level of the "http request", "https proxy request",
+ "unsupported protocol", and "version too low" SSL errors has been
+ lowered from "crit" to "info".
+
+ *) Bugfix: DNS requests were not resent if initial sending of a request
+ failed.
+
+ *) Bugfix: the "reuseport" parameter of the "listen" directive was
+ ignored if the number of worker processes was specified after the
+ "listen" directive.
+
+ *) Bugfix: when using OpenSSL 1.1.0 or newer it was not possible to
+ switch off "ssl_prefer_server_ciphers" in a virtual server if it was
+ switched on in the default server.
+
+ *) Bugfix: SSL session reuse with upstream servers did not work with the
+ TLS 1.3 protocol.
+
+
+Changes with nginx 1.15.1 03 Jul 2018
+
+ *) Feature: the "random" directive inside the "upstream" block.
+
+ *) Feature: improved performance when using the "hash" and "ip_hash"
+ directives with the "zone" directive.
+
+ *) Feature: the "reuseport" parameter of the "listen" directive now uses
+ SO_REUSEPORT_LB on FreeBSD 12.
+
+ *) Bugfix: HTTP/2 server push did not work if SSL was terminated by a
+ proxy server in front of nginx.
+
+ *) Bugfix: the "tcp_nopush" directive was always used on backend
+ connections.
+
+ *) Bugfix: sending a disk-buffered request body to a gRPC backend might
+ fail.
+
+
+Changes with nginx 1.15.0 05 Jun 2018
+
+ *) Change: the "ssl" directive is deprecated; the "ssl" parameter of the
+ "listen" directive should be used instead.
+
+ *) Change: now nginx detects missing SSL certificates during
+ configuration testing when using the "ssl" parameter of the "listen"
+ directive.
+
+ *) Feature: now the stream module can handle multiple incoming UDP
+ datagrams from a client within a single session.
+
+ *) Bugfix: it was possible to specify an incorrect response code in the
+ "proxy_cache_valid" directive.
+
+ *) Bugfix: nginx could not be built by gcc 8.1.
+
+ *) Bugfix: logging to syslog stopped on local IP address changes.
+
+ *) Bugfix: nginx could not be built by clang with CUDA SDK installed;
+ the bug had appeared in 1.13.8.
+
+ *) Bugfix: "getsockopt(TCP_FASTOPEN) ... failed" messages might appear
+ in logs during binary upgrade when using unix domain listen sockets
+ on FreeBSD.
+
+ *) Bugfix: nginx could not be built on Fedora 28 Linux.
+
+ *) Bugfix: request processing rate might exceed configured rate when
+ using the "limit_req" directive.
+
+ *) Bugfix: in handling of client addresses when using unix domain listen
+ sockets to work with datagrams on Linux.
+
+ *) Bugfix: in memory allocation error handling.
Changes with nginx 1.13.12 10 Apr 2018
diff --git a/CHANGES.ru b/CHANGES.ru
index 8c260fe..5d60f41 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,39 +1,103 @@
-Изменения в nginx 1.14.2 04.12.2018
+Изменения в nginx 1.16.1 13.08.2019
- *) Исправление: nginx не собирался gcc 8.1.
+ *) Безопасность: при использовании HTTP/2 клиент мог вызвать чрезмерное
+ потребление памяти и ресурсов процессора (CVE-2019-9511,
+ CVE-2019-9513, CVE-2019-9516).
- *) Исправление: nginx не собирался на Fedora 28 Linux.
- *) Исправление: в обработке адресов клиентов при использовании unix
- domain listen-сокетов для работы с датаграммами на Linux.
+Изменения в nginx 1.16.0 23.04.2019
- *) Изменение: уровень логгирования ошибок SSL "http request", "https
- proxy request", "unsupported protocol", "version too low", "no
- suitable key share" и "no suitable signature algorithm" понижен с
- уровня crit до info.
+ *) Стабильная ветка 1.16.x.
- *) Исправление: при использовании OpenSSL 1.1.0 и новее директиву
- ssl_prefer_server_ciphers нельзя было выключить в виртуальном
- сервере, если она была включена в сервере по умолчанию.
- *) Исправление: nginx не собирался с LibreSSL 2.8.0.
+Изменения в nginx 1.15.12 16.04.2019
- *) Исправление: если nginx был собран с OpenSSL 1.1.0, а использовался с
- OpenSSL 1.1.1, протокол TLS 1.3 всегда был разрешён.
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если в директивах ssl_certificate или ssl_certificate_key
+ использовались переменные и был включён OCSP stapling.
- *) Исправление: при отправке сохранённого на диск тела запроса на
- gRPC-бэкенд могли возникать ошибки.
- *) Исправление: соединения к некоторым gRPC-бэкендам могли не
- кэшироваться при использовании директивы keepalive.
+Изменения в nginx 1.15.11 09.04.2019
+
+ *) Исправление: в директиве ssl_stapling_file на Windows.
+
+
+Изменения в nginx 1.15.10 26.03.2019
+
+ *) Изменение: теперь при использовании имени хоста в директиве listen
+ nginx создаёт listen-сокеты для всех адресов, соответствующих этому
+ имени (ранее использовался только первый адрес).
+
+ *) Добавление: диапазоны портов в директиве listen.
+
+ *) Добавление: возможность загрузки SSL-сертификатов и секретных ключей
+ из переменных.
+
+ *) Изменение: переменная $ssl_server_name могла быть пустой при
+ использовании OpenSSL 1.1.1.
+
+ *) Исправление: nginx/Windows не собирался с Visual Studio 2015 и новее;
+ ошибка появилась в 1.15.9.
+
+
+Изменения в nginx 1.15.9 26.02.2019
+
+ *) Добавление: директивы ssl_certificate и ssl_certificate_key
+ поддерживают переменные.
+
+ *) Добавление: метод poll теперь доступен на Windows при использовании
+ Windows Vista и новее.
+
+ *) Исправление: если при использовании метода select на Windows
+ происходила ошибка при установлении соединения с бэкендом, nginx
+ ожидал истечения таймаута на установление соединения.
+
+ *) Исправление: директивы proxy_upload_rate и proxy_download_rate в
+ модуле stream работали некорректно при проксировании UDP-пакетов.
+
+
+Изменения в nginx 1.15.8 25.12.2018
+
+ *) Добавление: переменная $upstream_bytes_sent.
+ Спасибо Piotr Sikora.
+
+ *) Добавление: новые директивы в скриптах подсветки синтаксиса для vim.
+ Спасибо Геннадию Махомеду.
+
+ *) Исправление: в директиве proxy_cache_background_update.
+
+ *) Исправление: в директиве geo при использовании unix domain
+ listen-сокетов.
+
+ *) Изменение: при использовании директивы ssl_early_data с OpenSSL в
+ логах могли появляться сообщения "ignoring stale global SSL error ...
+ bad length".
+
+ *) Исправление: в nginx/Windows.
+
+ *) Исправление: в модуле ngx_http_autoindex_module на 32-битных
+ платформах.
+
+
+Изменения в nginx 1.15.7 27.11.2018
+
+ *) Добавление: директива proxy_requests в модуле stream.
+
+ *) Добавление: параметр "delay" директивы "limit_req".
+ Спасибо Владиславу Шабанову и Петру Щучкину.
+
+ *) Исправление: утечки памяти в случае ошибок при переконфигурации.
+
+ *) Исправление: в переменных $upstream_response_time,
+ $upstream_connect_time и $upstream_header_time.
*) Исправление: в рабочем процессе мог произойти segmentation fault,
если использовался модуль ngx_http_mp4_module на 32-битных
платформах.
-Изменения в nginx 1.14.1 06.11.2018
+Изменения в nginx 1.15.6 06.11.2018
*) Безопасность: при использовании HTTP/2 клиент мог вызвать чрезмерное
потреблению памяти (CVE-2018-16843) и ресурсов процессора
@@ -43,13 +107,165 @@
ngx_http_mp4_module содержимое памяти рабочего процесса могло быть
отправлено клиенту (CVE-2018-16845).
+ *) Добавление: директивы proxy_socket_keepalive,
+ fastcgi_socket_keepalive, grpc_socket_keepalive,
+ memcached_socket_keepalive, scgi_socket_keepalive и
+ uwsgi_socket_keepalive.
+
+ *) Исправление: если nginx был собран с OpenSSL 1.1.0, а использовался с
+ OpenSSL 1.1.1, протокол TLS 1.3 всегда был разрешён.
+
*) Исправление: при работе с gRPC-бэкендами могло расходоваться большое
количество памяти.
-Изменения в nginx 1.14.0 17.04.2018
+Изменения в nginx 1.15.5 02.10.2018
- *) Стабильная ветка 1.14.x.
+ *) Исправление: при использовании OpenSSL 1.1.0h и новее в рабочем
+ процессе мог произойти segmentation fault; ошибка появилась в 1.15.4.
+
+ *) Исправление: незначительных потенциальных ошибок.
+
+
+Изменения в nginx 1.15.4 25.09.2018
+
+ *) Добавление: теперь директиву ssl_early_data можно использовать с
+ OpenSSL.
+
+ *) Исправление: в модуле ngx_http_uwsgi_module.
+ Спасибо Chris Caputo.
+
+ *) Исправление: соединения к некоторым gRPC-бэкендам могли не
+ кэшироваться при использовании директивы keepalive.
+
+ *) Исправление: при использовании директивы error_page для
+ перенаправления ошибок, возникающих на ранних этапах обработки
+ запроса, в частности ошибок с кодом 400, могла происходить утечка
+ сокетов.
+
+ *) Исправление: директива return при возврате ошибок не изменяла код
+ ответа, если запрос был перенаправлен с помощью директивы error_page.
+
+ *) Исправление: стандартные сообщения об ошибках и ответы модуля
+ ngx_http_autoindex_module содержали атрибут bgcolor, что могло
+ приводить к их некорректному отображению при использовании
+ пользовательских настроек цветов в браузерах.
+ Спасибо Nova DasSarma.
+
+ *) Изменение: уровень логгирования ошибок SSL "no suitable key share" и
+ "no suitable signature algorithm" понижен с уровня crit до info.
+
+
+Изменения в nginx 1.15.3 28.08.2018
+
+ *) Добавление: теперь TLSv1.3 можно использовать с BoringSSL.
+
+ *) Добавление: директива ssl_early_data, сейчас доступна при
+ использовании BoringSSL.
+
+ *) Добавление: директивы keepalive_timeout и keepalive_requests в блоке
+ upstream.
+
+ *) Исправление: модуль ngx_http_dav_module при копировании файла поверх
+ существующего файла с помощью метода COPY не обнулял целевой файл.
+
+ *) Исправление: модуль ngx_http_dav_module при перемещении файла между
+ файловыми системами с помощью метода MOVE устанавливал нулевые права
+ доступа на результирующий файл и не сохранял время изменения файла.
+
+ *) Исправление: модуль ngx_http_dav_module при копировании файла с
+ помощью метода COPY для результирующего файла использовал права
+ доступа по умолчанию.
+
+ *) Изменение: некоторые клиенты могли не работать при использовании
+ HTTP/2; ошибка появилась в 1.13.5.
+
+ *) Исправление: nginx не собирался с LibreSSL 2.8.0.
+
+
+Изменения в nginx 1.15.2 24.07.2018
+
+ *) Добавление: переменная $ssl_preread_protocol в модуле
+ ngx_stream_ssl_preread_module.
+
+ *) Добавление: теперь при использовании директивы
+ reset_timedout_connection nginx сбрасывает соединения, закрываемые с
+ кодом 444.
+
+ *) Изменение: уровень логгирования ошибок SSL "http request", "https
+ proxy request", "unsupported protocol" и "version too low" понижен с
+ уровня crit до info.
+
+ *) Исправление: запросы к DNS-серверу не отправлялись повторно, если при
+ первой попытке отправки происходила ошибка.
+
+ *) Исправление: параметр reuseport директивы listen игнорировался, если
+ количество рабочих процессов было задано после директивы listen.
+
+ *) Исправление: при использовании OpenSSL 1.1.0 и новее директиву
+ ssl_prefer_server_ciphers нельзя было выключить в виртуальном
+ сервере, если она была включена в сервере по умолчанию.
+
+ *) Исправление: повторное использование SSL-сессий к бэкендам не
+ работало с протоколом TLS 1.3.
+
+
+Изменения в nginx 1.15.1 03.07.2018
+
+ *) Добавление: директива random в блоке upstream.
+
+ *) Добавление: улучшена производительность при использовании директив
+ hash и ip_hash совместно с директивой zone.
+
+ *) Добавление: параметр reuseport директивы listen теперь использует
+ SO_REUSEPORT_LB на FreeBSD 12.
+
+ *) Исправление: HTTP/2 server push не работал, если SSL терминировался
+ прокси-сервером перед nginx'ом.
+
+ *) Исправление: директива tcp_nopush всегда использовалась для
+ соединений к бэкендам.
+
+ *) Исправление: при отправке сохранённого на диск тела запроса на
+ gRPC-бэкенд могли возникать ошибки.
+
+
+Изменения в nginx 1.15.0 05.06.2018
+
+ *) Изменение: директива "ssl" теперь считается устаревшей; вместо неё
+ следует использовать параметр ssl директивы listen.
+
+ *) Изменение: теперь при использовании директивы listen с параметром ssl
+ nginx определяет отсутствие SSL-сертификатов при тестировании
+ конфигурации.
+
+ *) Добавление: теперь модуль stream умеет обрабатывать несколько
+ входящих UDP-пакетов от клиента в рамках одной сессии.
+
+ *) Исправление: в директиве proxy_cache_valid можно было указать
+ некорректный код ответа.
+
+ *) Исправление: nginx не собирался gcc 8.1.
+
+ *) Исправление: логгирование в syslog останавливалось при изменении
+ локального IP-адреса.
+
+ *) Исправление: nginx не собирался компилятором clang, если был
+ установлен CUDA SDK; ошибка появилась в 1.13.8.
+
+ *) Исправление: при использовании unix domain listen-сокетов на FreeBSD
+ в процессе обновления исполняемого файла в логе могли появляться
+ сообщения "getsockopt(TCP_FASTOPEN) ... failed".
+
+ *) Исправление: nginx не собирался на Fedora 28 Linux.
+
+ *) Исправление: при использовании директивы limit_req заданная скорость
+ обработки запросов могла не соблюдаться.
+
+ *) Исправление: в обработке адресов клиентов при использовании unix
+ domain listen-сокетов для работы с датаграммами на Linux.
+
+ *) Исправление: в обработке ошибок выделения памяти.
Изменения в nginx 1.13.12 10.04.2018
diff --git a/LICENSE b/LICENSE
index 9401174..c63e0ba 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2002-2018 Igor Sysoev
- * Copyright (C) 2011-2018 Nginx, Inc.
+ * Copyright (C) 2002-2019 Igor Sysoev
+ * Copyright (C) 2011-2019 Nginx, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/auto/cc/clang b/auto/cc/clang
index 9d900c2..a962ee2 100644
--- a/auto/cc/clang
+++ b/auto/cc/clang
@@ -6,7 +6,8 @@
NGX_CLANG_VER=`$CC -v 2>&1 | grep 'version' 2>&1 \
- | sed -e 's/^.* version \(.*\)/\1/'`
+ | sed -n -e 's/^.*clang version \(.*\)/\1/p' \
+ -e 's/^.*LLVM version \(.*\)/\1/p'`
echo " + clang version: $NGX_CLANG_VER"
diff --git a/auto/cc/msvc b/auto/cc/msvc
index 8257252..68435ff 100644
--- a/auto/cc/msvc
+++ b/auto/cc/msvc
@@ -108,7 +108,7 @@ CORE_LIBS="$CORE_LIBS kernel32.lib user32.lib"
# msvc under Wine issues
# C1902: Program database manager mismatch; please check your installation
if [ -z "$NGX_WINE" ]; then
- CFLAGS="$CFLAGS -Zi"
+ CFLAGS="$CFLAGS -Zi -Fd$NGX_OBJS/nginx.pdb"
CORE_LINK="$CORE_LINK -debug"
fi
diff --git a/auto/lib/google-perftools/conf b/auto/lib/google-perftools/conf
index 5d5ddae..7f1a911 100644
--- a/auto/lib/google-perftools/conf
+++ b/auto/lib/google-perftools/conf
@@ -9,7 +9,8 @@
ngx_feature_incs=
ngx_feature_path=
ngx_feature_libs="-lprofiler"
- ngx_feature_test="ProfilerStop()"
+ ngx_feature_test="void ProfilerStop(void);
+ ProfilerStop()"
. auto/feature
diff --git a/auto/lib/libgd/conf b/auto/lib/libgd/conf
index 87761f1..6786397 100644
--- a/auto/lib/libgd/conf
+++ b/auto/lib/libgd/conf
@@ -9,7 +9,8 @@
ngx_feature_incs="#include "
ngx_feature_path=
ngx_feature_libs="-lgd"
- ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);"
+ ngx_feature_test="gdImagePtr img = gdImageCreateFromGifPtr(1, NULL);
+ (void) img"
. auto/feature
@@ -76,7 +77,8 @@ if [ $ngx_found = yes ]; then
ngx_feature="GD WebP support"
ngx_feature_name="NGX_HAVE_GD_WEBP"
- ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);"
+ ngx_feature_test="gdImagePtr img = gdImageCreateFromWebpPtr(1, NULL);
+ (void) img"
. auto/feature
else
diff --git a/auto/lib/libxslt/conf b/auto/lib/libxslt/conf
index 3a0f37b..3063ac7 100644
--- a/auto/lib/libxslt/conf
+++ b/auto/lib/libxslt/conf
@@ -16,8 +16,8 @@
ngx_feature_libs="-lxml2 -lxslt"
ngx_feature_test="xmlParserCtxtPtr ctxt = NULL;
xsltStylesheetPtr sheet = NULL;
- xmlDocPtr doc;
- doc = xmlParseChunk(ctxt, NULL, 0, 0);
+ xmlDocPtr doc = NULL;
+ xmlParseChunk(ctxt, NULL, 0, 0);
xsltApplyStylesheet(sheet, doc, NULL);"
. auto/feature
diff --git a/auto/make b/auto/make
index 7ddd100..34c40cd 100644
--- a/auto/make
+++ b/auto/make
@@ -229,7 +229,7 @@ build: binary modules manpage
binary: $NGX_OBJS${ngx_dirsep}nginx$ngx_binext
$NGX_OBJS${ngx_dirsep}nginx$ngx_binext: $ngx_deps$ngx_spacer
- \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
+ \$(LINK) $ngx_long_start$ngx_binout$NGX_OBJS${ngx_dirsep}nginx$ngx_binext$ngx_long_cont$ngx_objs$ngx_libs$ngx_link$ngx_main_link
$ngx_rcc
$ngx_long_end
diff --git a/auto/modules b/auto/modules
index 73a9bae..09bfcb0 100644
--- a/auto/modules
+++ b/auto/modules
@@ -878,6 +878,17 @@ if [ $HTTP = YES ]; then
. auto/module
fi
+ if [ $HTTP_UPSTREAM_RANDOM = YES ]; then
+ ngx_module_name=ngx_http_upstream_random_module
+ ngx_module_incs=
+ ngx_module_deps=
+ ngx_module_srcs=src/http/modules/ngx_http_upstream_random_module.c
+ ngx_module_libs=
+ ngx_module_link=$HTTP_UPSTREAM_RANDOM
+
+ . auto/module
+ fi
+
if [ $HTTP_UPSTREAM_KEEPALIVE = YES ]; then
ngx_module_name=ngx_http_upstream_keepalive_module
ngx_module_incs=
@@ -1143,6 +1154,16 @@ if [ $STREAM != NO ]; then
. auto/module
fi
+ if [ $STREAM_UPSTREAM_RANDOM = YES ]; then
+ ngx_module_name=ngx_stream_upstream_random_module
+ ngx_module_deps=
+ ngx_module_srcs=src/stream/ngx_stream_upstream_random_module.c
+ ngx_module_libs=
+ ngx_module_link=$STREAM_UPSTREAM_RANDOM
+
+ . auto/module
+ fi
+
if [ $STREAM_UPSTREAM_ZONE = YES ]; then
have=NGX_STREAM_UPSTREAM_ZONE . auto/have
diff --git a/auto/options b/auto/options
index 59f0449..d8b421b 100644
--- a/auto/options
+++ b/auto/options
@@ -102,6 +102,7 @@ HTTP_GZIP_STATIC=NO
HTTP_UPSTREAM_HASH=YES
HTTP_UPSTREAM_IP_HASH=YES
HTTP_UPSTREAM_LEAST_CONN=YES
+HTTP_UPSTREAM_RANDOM=YES
HTTP_UPSTREAM_KEEPALIVE=YES
HTTP_UPSTREAM_ZONE=YES
@@ -126,6 +127,7 @@ STREAM_SPLIT_CLIENTS=YES
STREAM_RETURN=YES
STREAM_UPSTREAM_HASH=YES
STREAM_UPSTREAM_LEAST_CONN=YES
+STREAM_UPSTREAM_RANDOM=YES
STREAM_UPSTREAM_ZONE=YES
STREAM_SSL_PREREAD=NO
@@ -273,6 +275,8 @@ $0: warning: the \"--with-ipv6\" option is deprecated"
--without-http_upstream_ip_hash_module) HTTP_UPSTREAM_IP_HASH=NO ;;
--without-http_upstream_least_conn_module)
HTTP_UPSTREAM_LEAST_CONN=NO ;;
+ --without-http_upstream_random_module)
+ HTTP_UPSTREAM_RANDOM=NO ;;
--without-http_upstream_keepalive_module) HTTP_UPSTREAM_KEEPALIVE=NO ;;
--without-http_upstream_zone_module) HTTP_UPSTREAM_ZONE=NO ;;
@@ -325,6 +329,8 @@ use the \"--with-mail_ssl_module\" option instead"
STREAM_UPSTREAM_HASH=NO ;;
--without-stream_upstream_least_conn_module)
STREAM_UPSTREAM_LEAST_CONN=NO ;;
+ --without-stream_upstream_random_module)
+ STREAM_UPSTREAM_RANDOM=NO ;;
--without-stream_upstream_zone_module)
STREAM_UPSTREAM_ZONE=NO ;;
@@ -485,6 +491,8 @@ cat << END
disable ngx_http_upstream_ip_hash_module
--without-http_upstream_least_conn_module
disable ngx_http_upstream_least_conn_module
+ --without-http_upstream_random_module
+ disable ngx_http_upstream_random_module
--without-http_upstream_keepalive_module
disable ngx_http_upstream_keepalive_module
--without-http_upstream_zone_module
@@ -535,6 +543,8 @@ cat << END
disable ngx_stream_upstream_hash_module
--without-stream_upstream_least_conn_module
disable ngx_stream_upstream_least_conn_module
+ --without-stream_upstream_random_module
+ disable ngx_stream_upstream_random_module
--without-stream_upstream_zone_module
disable ngx_stream_upstream_zone_module
diff --git a/auto/os/linux b/auto/os/linux
index 2c8a9bb..5e280ec 100644
--- a/auto/os/linux
+++ b/auto/os/linux
@@ -185,6 +185,8 @@ ngx_feature_test="struct __user_cap_data_struct data;
data.effective = CAP_TO_MASK(CAP_NET_RAW);
data.permitted = 0;
+ (void) header;
+ (void) data;
(void) SYS_capset"
. auto/feature
diff --git a/auto/os/win32 b/auto/os/win32
index 7a82774..b821ae6 100644
--- a/auto/os/win32
+++ b/auto/os/win32
@@ -11,6 +11,7 @@ CORE_SRCS="$WIN32_SRCS $IOCP_SRCS"
OS_CONFIG="$WIN32_CONFIG"
NGX_ICONS="$NGX_WIN32_ICONS"
SELECT_SRCS=$WIN32_SELECT_SRCS
+POLL_SRCS=$WIN32_POLL_SRCS
ngx_pic_opt=
ngx_binext=".exe"
@@ -31,12 +32,7 @@ case "$NGX_CC_NAME" in
esac
EVENT_MODULES="$EVENT_MODULES $IOCP_MODULE"
-EVENT_FOUND=YES
-
-if [ $EVENT_SELECT = NO ]; then
- CORE_SRCS="$CORE_SRCS $SELECT_SRCS"
- EVENT_MODULES="$EVENT_MODULES $SELECT_MODULE"
-fi
+#EVENT_FOUND=YES
have=NGX_HAVE_INET6 . auto/have
diff --git a/auto/sources b/auto/sources
index 1398147..3dad111 100644
--- a/auto/sources
+++ b/auto/sources
@@ -95,6 +95,7 @@ EVENT_SRCS="src/event/ngx_event.c \
src/event/ngx_event_timer.c \
src/event/ngx_event_posted.c \
src/event/ngx_event_accept.c \
+ src/event/ngx_event_udp.c \
src/event/ngx_event_connect.c \
src/event/ngx_event_pipe.c"
@@ -105,6 +106,7 @@ WIN32_SELECT_SRCS=src/event/modules/ngx_win32_select_module.c
POLL_MODULE=ngx_poll_module
POLL_SRCS=src/event/modules/ngx_poll_module.c
+WIN32_POLL_SRCS=src/event/modules/ngx_win32_poll_module.c
KQUEUE_MODULE=ngx_kqueue_module
KQUEUE_SRCS=src/event/modules/ngx_kqueue_module.c
diff --git a/conf/mime.types b/conf/mime.types
index 8a2348a..2961256 100644
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -24,7 +24,9 @@ types {
image/x-jng jng;
image/x-ms-bmp bmp;
- application/font-woff woff;
+ font/woff woff;
+ font/woff2 woff2;
+
application/java-archive jar war ear;
application/json json;
application/mac-binhex40 hqx;
diff --git a/contrib/vim/syntax/nginx.vim b/contrib/vim/syntax/nginx.vim
index 075b19a..6bee7a2 100644
--- a/contrib/vim/syntax/nginx.vim
+++ b/contrib/vim/syntax/nginx.vim
@@ -108,6 +108,7 @@ syn keyword ngxDirectiveControl contained set
syn keyword ngxDirectiveError contained error_page
syn keyword ngxDirectiveError contained post_action
+syn keyword ngxDirectiveDeprecated contained limit_zone
syn keyword ngxDirectiveDeprecated contained proxy_downstream_buffer
syn keyword ngxDirectiveDeprecated contained proxy_upstream_buffer
syn keyword ngxDirectiveDeprecated contained spdy_chunk_size
@@ -118,6 +119,7 @@ syn keyword ngxDirectiveDeprecated contained spdy_pool_size
syn keyword ngxDirectiveDeprecated contained spdy_recv_buffer_size
syn keyword ngxDirectiveDeprecated contained spdy_recv_timeout
syn keyword ngxDirectiveDeprecated contained spdy_streams_index_size
+syn keyword ngxDirectiveDeprecated contained ssl
syn keyword ngxDirectiveDeprecated contained upstream_conf
syn keyword ngxDirective contained absolute_redirect
@@ -136,6 +138,7 @@ syn keyword ngxDirective contained alias
syn keyword ngxDirective contained allow
syn keyword ngxDirective contained ancient_browser
syn keyword ngxDirective contained ancient_browser_value
+syn keyword ngxDirective contained api
syn keyword ngxDirective contained auth_basic
syn keyword ngxDirective contained auth_basic_user_file
syn keyword ngxDirective contained auth_http
@@ -143,7 +146,11 @@ syn keyword ngxDirective contained auth_http_header
syn keyword ngxDirective contained auth_http_pass_client_cert
syn keyword ngxDirective contained auth_http_timeout
syn keyword ngxDirective contained auth_jwt
+syn keyword ngxDirective contained auth_jwt_claim_set
+syn keyword ngxDirective contained auth_jwt_header_set
syn keyword ngxDirective contained auth_jwt_key_file
+syn keyword ngxDirective contained auth_jwt_key_request
+syn keyword ngxDirective contained auth_jwt_leeway
syn keyword ngxDirective contained auth_request
syn keyword ngxDirective contained auth_request_set
syn keyword ngxDirective contained autoindex
@@ -229,6 +236,7 @@ syn keyword ngxDirective contained fastcgi_read_timeout
syn keyword ngxDirective contained fastcgi_request_buffering
syn keyword ngxDirective contained fastcgi_send_lowat
syn keyword ngxDirective contained fastcgi_send_timeout
+syn keyword ngxDirective contained fastcgi_socket_keepalive
syn keyword ngxDirective contained fastcgi_split_path_info
syn keyword ngxDirective contained fastcgi_store
syn keyword ngxDirective contained fastcgi_store_access
@@ -255,6 +263,7 @@ syn keyword ngxDirective contained grpc_pass_header
syn keyword ngxDirective contained grpc_read_timeout
syn keyword ngxDirective contained grpc_send_timeout
syn keyword ngxDirective contained grpc_set_header
+syn keyword ngxDirective contained grpc_socket_keepalive
syn keyword ngxDirective contained grpc_ssl_certificate
syn keyword ngxDirective contained grpc_ssl_certificate_key
syn keyword ngxDirective contained grpc_ssl_ciphers
@@ -330,6 +339,8 @@ syn keyword ngxDirective contained keepalive
syn keyword ngxDirective contained keepalive_disable
syn keyword ngxDirective contained keepalive_requests
syn keyword ngxDirective contained keepalive_timeout
+syn keyword ngxDirective contained keyval
+syn keyword ngxDirective contained keyval_zone
syn keyword ngxDirective contained kqueue_changes
syn keyword ngxDirective contained kqueue_events
syn keyword ngxDirective contained large_client_header_buffers
@@ -367,6 +378,7 @@ syn keyword ngxDirective contained memcached_next_upstream_timeout
syn keyword ngxDirective contained memcached_next_upstream_tries
syn keyword ngxDirective contained memcached_read_timeout
syn keyword ngxDirective contained memcached_send_timeout
+syn keyword ngxDirective contained memcached_socket_keepalive
syn keyword ngxDirective contained merge_slashes
syn keyword ngxDirective contained min_delete_depth
syn keyword ngxDirective contained mirror
@@ -375,9 +387,9 @@ syn keyword ngxDirective contained modern_browser
syn keyword ngxDirective contained modern_browser_value
syn keyword ngxDirective contained mp4
syn keyword ngxDirective contained mp4_buffer_size
-syn keyword ngxDirective contained mp4_max_buffer_size
syn keyword ngxDirective contained mp4_limit_rate
syn keyword ngxDirective contained mp4_limit_rate_after
+syn keyword ngxDirective contained mp4_max_buffer_size
syn keyword ngxDirective contained msie_padding
syn keyword ngxDirective contained msie_refresh
syn keyword ngxDirective contained multi_accept
@@ -456,11 +468,13 @@ syn keyword ngxDirective contained proxy_protocol_timeout
syn keyword ngxDirective contained proxy_read_timeout
syn keyword ngxDirective contained proxy_redirect
syn keyword ngxDirective contained proxy_request_buffering
+syn keyword ngxDirective contained proxy_requests
syn keyword ngxDirective contained proxy_responses
syn keyword ngxDirective contained proxy_send_lowat
syn keyword ngxDirective contained proxy_send_timeout
syn keyword ngxDirective contained proxy_set_body
syn keyword ngxDirective contained proxy_set_header
+syn keyword ngxDirective contained proxy_socket_keepalive
syn keyword ngxDirective contained proxy_ssl
syn keyword ngxDirective contained proxy_ssl_certificate
syn keyword ngxDirective contained proxy_ssl_certificate_key
@@ -481,6 +495,7 @@ syn keyword ngxDirective contained proxy_temp_path
syn keyword ngxDirective contained proxy_timeout
syn keyword ngxDirective contained proxy_upload_rate
syn keyword ngxDirective contained queue
+syn keyword ngxDirective contained random
syn keyword ngxDirective contained random_index
syn keyword ngxDirective contained read_ahead
syn keyword ngxDirective contained real_ip_header
@@ -533,6 +548,7 @@ syn keyword ngxDirective contained scgi_pass_request_headers
syn keyword ngxDirective contained scgi_read_timeout
syn keyword ngxDirective contained scgi_request_buffering
syn keyword ngxDirective contained scgi_send_timeout
+syn keyword ngxDirective contained scgi_socket_keepalive
syn keyword ngxDirective contained scgi_store
syn keyword ngxDirective contained scgi_store_access
syn keyword ngxDirective contained scgi_temp_file_write_size
@@ -565,7 +581,6 @@ syn keyword ngxDirective contained ssi_min_file_chunk
syn keyword ngxDirective contained ssi_silent_errors
syn keyword ngxDirective contained ssi_types
syn keyword ngxDirective contained ssi_value_length
-syn keyword ngxDirective contained ssl
syn keyword ngxDirective contained ssl_buffer_size
syn keyword ngxDirective contained ssl_certificate
syn keyword ngxDirective contained ssl_certificate_key
@@ -573,6 +588,7 @@ syn keyword ngxDirective contained ssl_ciphers
syn keyword ngxDirective contained ssl_client_certificate
syn keyword ngxDirective contained ssl_crl
syn keyword ngxDirective contained ssl_dhparam
+syn keyword ngxDirective contained ssl_early_data
syn keyword ngxDirective contained ssl_ecdh_curve
syn keyword ngxDirective contained ssl_engine
syn keyword ngxDirective contained ssl_handshake_timeout
@@ -664,6 +680,7 @@ syn keyword ngxDirective contained uwsgi_pass_request_headers
syn keyword ngxDirective contained uwsgi_read_timeout
syn keyword ngxDirective contained uwsgi_request_buffering
syn keyword ngxDirective contained uwsgi_send_timeout
+syn keyword ngxDirective contained uwsgi_socket_keepalive
syn keyword ngxDirective contained uwsgi_ssl_certificate
syn keyword ngxDirective contained uwsgi_ssl_certificate_key
syn keyword ngxDirective contained uwsgi_ssl_ciphers
@@ -701,6 +718,26 @@ syn keyword ngxDirective contained xslt_string_param
syn keyword ngxDirective contained xslt_stylesheet
syn keyword ngxDirective contained xslt_types
syn keyword ngxDirective contained zone
+syn keyword ngxDirective contained zone_sync
+syn keyword ngxDirective contained zone_sync_buffers
+syn keyword ngxDirective contained zone_sync_connect_retry_interval
+syn keyword ngxDirective contained zone_sync_connect_timeout
+syn keyword ngxDirective contained zone_sync_interval
+syn keyword ngxDirective contained zone_sync_recv_buffer_size
+syn keyword ngxDirective contained zone_sync_server
+syn keyword ngxDirective contained zone_sync_ssl
+syn keyword ngxDirective contained zone_sync_ssl_certificate
+syn keyword ngxDirective contained zone_sync_ssl_certificate_key
+syn keyword ngxDirective contained zone_sync_ssl_ciphers
+syn keyword ngxDirective contained zone_sync_ssl_crl
+syn keyword ngxDirective contained zone_sync_ssl_name
+syn keyword ngxDirective contained zone_sync_ssl_password_file
+syn keyword ngxDirective contained zone_sync_ssl_protocols
+syn keyword ngxDirective contained zone_sync_ssl_server_name
+syn keyword ngxDirective contained zone_sync_ssl_trusted_certificate
+syn keyword ngxDirective contained zone_sync_ssl_verify
+syn keyword ngxDirective contained zone_sync_ssl_verify_depth
+syn keyword ngxDirective contained zone_sync_timeout
" 3rd party modules list taken from
" https://github.com/freebsd/freebsd-ports/blob/master/www/nginx-devel/Makefile
@@ -876,6 +913,8 @@ syn keyword ngxDirectiveThirdParty contained more_set_input_headers
" NGINX WebDAV missing commands support (PROPFIND & OPTIONS)
" https://github.com/arut/nginx-dav-ext-module
+syn keyword ngxDirectiveThirdParty contained dav_ext_lock
+syn keyword ngxDirectiveThirdParty contained dav_ext_lock_zone
syn keyword ngxDirectiveThirdParty contained dav_ext_methods
" ngx_eval
@@ -895,6 +934,7 @@ syn keyword ngxDirectiveThirdParty contained fancyindex_directories_first
syn keyword ngxDirectiveThirdParty contained fancyindex_exact_size
syn keyword ngxDirectiveThirdParty contained fancyindex_footer
syn keyword ngxDirectiveThirdParty contained fancyindex_header
+syn keyword ngxDirectiveThirdParty contained fancyindex_hide_parent_dir
syn keyword ngxDirectiveThirdParty contained fancyindex_hide_symlinks
syn keyword ngxDirectiveThirdParty contained fancyindex_ignore
syn keyword ngxDirectiveThirdParty contained fancyindex_localtime
@@ -937,8 +977,17 @@ syn keyword ngxDirectiveThirdParty contained notice_type
" nchan
" https://github.com/slact/nchan
+syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_credentials
syn keyword ngxDirectiveThirdParty contained nchan_access_control_allow_origin
syn keyword ngxDirectiveThirdParty contained nchan_authorize_request
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_channels
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_message_padding_bytes
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_messages_per_channel_per_minute
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_publisher_distribution
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscriber_distribution
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_subscribers_per_channel
+syn keyword ngxDirectiveThirdParty contained nchan_benchmark_time
syn keyword ngxDirectiveThirdParty contained nchan_channel_event_string
syn keyword ngxDirectiveThirdParty contained nchan_channel_events_channel_id
syn keyword ngxDirectiveThirdParty contained nchan_channel_group
@@ -974,15 +1023,19 @@ syn keyword ngxDirectiveThirdParty contained nchan_publisher_upstream_request
syn keyword ngxDirectiveThirdParty contained nchan_pubsub
syn keyword ngxDirectiveThirdParty contained nchan_pubsub_channel_id
syn keyword ngxDirectiveThirdParty contained nchan_pubsub_location
+syn keyword ngxDirectiveThirdParty contained nchan_redis_connect_timeout
syn keyword ngxDirectiveThirdParty contained nchan_redis_fakesub_timer_interval
syn keyword ngxDirectiveThirdParty contained nchan_redis_idle_channel_cache_timeout
syn keyword ngxDirectiveThirdParty contained nchan_redis_namespace
+syn keyword ngxDirectiveThirdParty contained nchan_redis_nostore_fastpublish
+syn keyword ngxDirectiveThirdParty contained nchan_redis_optimize_target
syn keyword ngxDirectiveThirdParty contained nchan_redis_pass
syn keyword ngxDirectiveThirdParty contained nchan_redis_pass_inheritable
syn keyword ngxDirectiveThirdParty contained nchan_redis_ping_interval
syn keyword ngxDirectiveThirdParty contained nchan_redis_publish_msgpacked_max_size
syn keyword ngxDirectiveThirdParty contained nchan_redis_server
syn keyword ngxDirectiveThirdParty contained nchan_redis_storage_mode
+syn keyword ngxDirectiveThirdParty contained nchan_redis_subscribe_weights
syn keyword ngxDirectiveThirdParty contained nchan_redis_url
syn keyword ngxDirectiveThirdParty contained nchan_redis_wait_after_connecting
syn keyword ngxDirectiveThirdParty contained nchan_shared_memory_size
@@ -1280,6 +1333,7 @@ syn keyword ngxDirectiveThirdParty contained lua_package_cpath
syn keyword ngxDirectiveThirdParty contained lua_package_path
syn keyword ngxDirectiveThirdParty contained lua_regex_cache_max_entries
syn keyword ngxDirectiveThirdParty contained lua_regex_match_limit
+syn keyword ngxDirectiveThirdParty contained lua_sa_restart
syn keyword ngxDirectiveThirdParty contained lua_shared_dict
syn keyword ngxDirectiveThirdParty contained lua_socket_buffer_size
syn keyword ngxDirectiveThirdParty contained lua_socket_connect_timeout
@@ -1355,9 +1409,15 @@ syn keyword ngxDirectiveThirdParty contained rules_enabled
" https://www.phusionpassenger.com/library/config/nginx/reference/
syn keyword ngxDirectiveThirdParty contained passenger_abort_on_startup_error
syn keyword ngxDirectiveThirdParty contained passenger_abort_websockets_on_process_shutdown
+syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_auth_type
+syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_password
+syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_url
+syn keyword ngxDirectiveThirdParty contained passenger_admin_panel_username
+syn keyword ngxDirectiveThirdParty contained passenger_anonymous_telemetry_proxy
syn keyword ngxDirectiveThirdParty contained passenger_app_env
syn keyword ngxDirectiveThirdParty contained passenger_app_file_descriptor_ulimit
syn keyword ngxDirectiveThirdParty contained passenger_app_group_name
+syn keyword ngxDirectiveThirdParty contained passenger_app_log_file
syn keyword ngxDirectiveThirdParty contained passenger_app_rights
syn keyword ngxDirectiveThirdParty contained passenger_app_root
syn keyword ngxDirectiveThirdParty contained passenger_app_type
@@ -1373,8 +1433,10 @@ syn keyword ngxDirectiveThirdParty contained passenger_data_buffer_dir
syn keyword ngxDirectiveThirdParty contained passenger_debugger
syn keyword ngxDirectiveThirdParty contained passenger_default_group
syn keyword ngxDirectiveThirdParty contained passenger_default_user
+syn keyword ngxDirectiveThirdParty contained passenger_disable_anonymous_telemetry
syn keyword ngxDirectiveThirdParty contained passenger_disable_security_update_check
syn keyword ngxDirectiveThirdParty contained passenger_document_root
+syn keyword ngxDirectiveThirdParty contained passenger_dump_config_manifest
syn keyword ngxDirectiveThirdParty contained passenger_enabled
syn keyword ngxDirectiveThirdParty contained passenger_env_var
syn keyword ngxDirectiveThirdParty contained passenger_file_descriptor_log_file
@@ -1402,6 +1464,7 @@ syn keyword ngxDirectiveThirdParty contained passenger_max_requests
syn keyword ngxDirectiveThirdParty contained passenger_memory_limit
syn keyword ngxDirectiveThirdParty contained passenger_meteor_app_settings
syn keyword ngxDirectiveThirdParty contained passenger_min_instances
+syn keyword ngxDirectiveThirdParty contained passenger_monitor_log_file
syn keyword ngxDirectiveThirdParty contained passenger_nodejs
syn keyword ngxDirectiveThirdParty contained passenger_pass_header
syn keyword ngxDirectiveThirdParty contained passenger_pool_idle_time
@@ -1778,6 +1841,8 @@ syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_host
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_by_set_key
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_check_duplicate
+syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_filter_max_node
+syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_histogram_buckets
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_check_duplicate
syn keyword ngxDirectiveThirdParty contained vhost_traffic_status_limit_traffic
@@ -1899,11 +1964,11 @@ syn keyword ngxDirectiveThirdParty contained form_auth_remote_user
" ngx_http_accounting_module
" https://github.com/Lax/ngx_http_accounting_module
-syn keyword ngxDirectiveThirdParty contained http_accounting
-syn keyword ngxDirectiveThirdParty contained http_accounting_id
-syn keyword ngxDirectiveThirdParty contained http_accounting_interval
-syn keyword ngxDirectiveThirdParty contained http_accounting_log
-syn keyword ngxDirectiveThirdParty contained http_accounting_perturb
+syn keyword ngxDirectiveThirdParty contained accounting
+syn keyword ngxDirectiveThirdParty contained accounting_id
+syn keyword ngxDirectiveThirdParty contained accounting_interval
+syn keyword ngxDirectiveThirdParty contained accounting_log
+syn keyword ngxDirectiveThirdParty contained accounting_perturb
" concatenating files in a given context: CSS and JS files usually
" https://github.com/alibaba/nginx-http-concat
diff --git a/html/50x.html b/html/50x.html
index f60f5e7..9071e0a 100644
--- a/html/50x.html
+++ b/html/50x.html
@@ -15,7 +15,7 @@
Sorry, the page you are looking for is currently unavailable.
Please try again later.
If you are the system administrator of this resource then you should check
-the error log for details.
+the error log for details.
Faithfully yours, nginx.