From c0676d5b332d3bca5cc89c9b94880c594d90e678 Mon Sep 17 00:00:00 2001
From: SuryawanshiAmol <44642533+SuryawanshiAmol@users.noreply.github.com>
Date: Tue, 19 Sep 2023 13:35:31 +0530
Subject: [PATCH 01/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
---
.../upstreamzmauth/ngx_http_upstream_zmauth_module.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
index 9582dd96b..02f02161c 100644
--- a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
+++ b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
@@ -1650,10 +1650,11 @@ zmauth_check_authtoken(ngx_http_request_t *r, ngx_str_t* field,
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP, log, 0,
"zmauth: search for ZM_AUTH_TOKEN");
- /* look for auth token in the request cookie(s) */
+ /* look for auth token in the request cookie(s)
+ AMB - There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
f = ngx_get_cookie_value(log,
(ngx_table_elt_t **) r->headers_in.cookies.elts,
- r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN, &token);
+ r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN, &token);*/
if (!f) {
/* if not found, then look in the zauthtoken= query string arg */
@@ -1783,10 +1784,11 @@ zmauth_check_admin_authtoken(ngx_http_request_t *r, ngx_str_t* field,
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP, log, 0,
"zmauth: search for ZM_ADMIN_AUTH_TOKEN");
- /* look for auth token in the request cookie(s) */
+ /* look for auth token in the request cookie(s)
+ AMB - There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
f = ngx_get_cookie_value(log,
(ngx_table_elt_t **) r->headers_in.cookies.elts,
- r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN_ADMIN, &token);
+ r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN_ADMIN, &token);*/
if (f) {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
From 39228a36609e310142d8e8f8821b9ca6bc7c8f73 Mon Sep 17 00:00:00 2001
From: SuryawanshiAmol <44642533+SuryawanshiAmol@users.noreply.github.com>
Date: Tue, 19 Sep 2023 16:13:08 +0530
Subject: [PATCH 02/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- Updated nginx version
---
versions.def | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/versions.def b/versions.def
index 2c80743a9..8bf338c0f 100644
--- a/versions.def
+++ b/versions.def
@@ -98,7 +98,7 @@ MARIADB_VERSION := 10.4.13
MAVEN_VERSION := 3.3.9
-NGINX_VERSION := 1.20.0
+NGINX_VERSION := 1.24.0
NGINX_HTTP_KEEPALIVE := 19755fc0e22aa7d7ac2198f78b297951d31ea1dc
OPENSSL_VERSION := 3.0.9
From 41c5230882784d48acaafea9de3dd2558a3a400d Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Wed, 20 Sep 2023 17:46:04 +0530
Subject: [PATCH 03/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
- Fixed the problem by breaking the external for loop as its not needed to loop over as cookie data may come in string
---
.../ngx_http_upstream_zmauth_module.c | 29 +++++++++++--------
1 file changed, 17 insertions(+), 12 deletions(-)
diff --git a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
index 02f02161c..2a696031c 100644
--- a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
+++ b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
@@ -82,8 +82,12 @@ static ngx_flag_t ngx_get_authheader_bearer(ngx_log_t *log, ngx_pool_t *pool,
ngx_http_headers_in_t *headers_in, ngx_str_t *value);
static ngx_flag_t ngx_claimdata_from_payload(ngx_log_t *log, ngx_pool_t *pool,
ngx_str_t *payload, ngx_str_t *value);
+/*
+AMB : Function ngx_get_cookie_value changed to receive the ngx_table_elt_t* instead of ngx_array_t. As the type ngx_table_elt_t don't have members elts & nelts
+This change occurs from upgrading the nginx library from version 1.20.0 to 1.24.0
+*/
static ngx_flag_t ngx_get_cookie_value(ngx_log_t *log,
- ngx_table_elt_t **cookies, ngx_uint_t ncookies, ngx_str_t *name,
+ ngx_table_elt_t *cookies, ngx_uint_t ncookies, ngx_str_t *name,
ngx_str_t *value);
static ngx_flag_t ngx_get_query_string_arg(ngx_log_t *log, ngx_str_t *args,
ngx_str_t *name, ngx_str_t *value);
@@ -845,15 +849,15 @@ static ngx_flag_t ngx_http_upstream_zmserver_from_cookie
static ngx_flag_t
ngx_get_cookie_value(ngx_log_t *log,
- ngx_table_elt_t **cookies, ngx_uint_t ncookies, ngx_str_t *name,
+ ngx_table_elt_t *cookies, ngx_uint_t ncookies, ngx_str_t *name,
ngx_str_t *value) {
- ngx_table_elt_t **c;
+ ngx_table_elt_t *c;
u_char *s, *p, *e;
ngx_str_t V, n, v;
ngx_flag_t f;
-
- for (c = cookies, f = 0; c < cookies + ncookies && f == 0; ++c) {
- V = (*c)->value;
+ // AMB : changed cookies from ngx_array_t to ngx_table_elt_t when upgrading the nginx library from version 1.20.0 to 1.24.0
+ for (c = cookies, f = 0; /*c < cookies + ncookies && f == 0*/;/* ++c*/) {
+ V = c->value;
/* v is of the form "name=value; name=value;" */
s = V.data;
e = s + V.len;
@@ -891,6 +895,7 @@ ngx_get_cookie_value(ngx_log_t *log,
++p;
}
}
+ break; // AMB : change done as part of cookie handling as per new type "ngx_table_elt_t"
}
return f;
@@ -1651,10 +1656,10 @@ zmauth_check_authtoken(ngx_http_request_t *r, ngx_str_t* field,
"zmauth: search for ZM_AUTH_TOKEN");
/* look for auth token in the request cookie(s)
- AMB - There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
+ AMB - There appears that in version 1.24.0 request member "cookie" has changed. This change occurs from upgrading the nginx library from version 1.20.0 to 1.24.0 (Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).*/
f = ngx_get_cookie_value(log,
- (ngx_table_elt_t **) r->headers_in.cookies.elts,
- r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN, &token);*/
+ (ngx_table_elt_t *) r->headers_in.cookie,
+ (ngx_uint_t)r->headers_in.cookie, &NGX_ZMAUTHTOKEN, &token);
if (!f) {
/* if not found, then look in the zauthtoken= query string arg */
@@ -1785,10 +1790,10 @@ zmauth_check_admin_authtoken(ngx_http_request_t *r, ngx_str_t* field,
"zmauth: search for ZM_ADMIN_AUTH_TOKEN");
/* look for auth token in the request cookie(s)
- AMB - There appears to be a significant change in request member "cookie" that must be handled. Code is commented in order to move compilation forward and detect any errors that arise. ( Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).
+ AMB - There appears that in version 1.24.0 request member "cookie" has changed. This change occurs from upgrading the nginx library from version 1.20.0 to 1.24.0 (Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).*/
f = ngx_get_cookie_value(log,
- (ngx_table_elt_t **) r->headers_in.cookies.elts,
- r->headers_in.cookies.nelts, &NGX_ZMAUTHTOKEN_ADMIN, &token);*/
+ (ngx_table_elt_t *) r->headers_in.cookie,
+ (ngx_uint_t)r->headers_in.cookie, &NGX_ZMAUTHTOKEN_ADMIN, &token);
if (f) {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
From e1afb0f1410402cfb0aa453254b65886af6652b7 Mon Sep 17 00:00:00 2001
From: SuryawanshiAmol <44642533+SuryawanshiAmol@users.noreply.github.com>
Date: Thu, 21 Sep 2023 12:04:57 +0530
Subject: [PATCH 04/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- Modified some logging statements in-order to differentiate it from original logs. This changes will be reverted once testing done.
---
.../ngx_http_upstream_zmauth_module.c | 22 +++++++++----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
index 2a696031c..b5e18aaf4 100644
--- a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
+++ b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
@@ -864,7 +864,7 @@ ngx_get_cookie_value(ngx_log_t *log,
p = s;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: examining cookie value:%V",&V);
+ "zmauth: examining cookie value:(AMB)%V",&V);
while (p < e) {
n.data = p;
@@ -1653,7 +1653,7 @@ zmauth_check_authtoken(ngx_http_request_t *r, ngx_str_t* field,
log = r->connection->log;
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: search for ZM_AUTH_TOKEN");
+ "zmauth: search for ZM_AUTH_TOKEN(AMB)");
/* look for auth token in the request cookie(s)
AMB - There appears that in version 1.24.0 request member "cookie" has changed. This change occurs from upgrading the nginx library from version 1.20.0 to 1.24.0 (Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).*/
@@ -1668,13 +1668,13 @@ zmauth_check_authtoken(ngx_http_request_t *r, ngx_str_t* field,
if (f) {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: found ZM_AUTH_TOKEN:%V",
+ "zmauth: found ZM_AUTH_TOKEN(AMB):%V",
&token);
f = ngx_field_from_zmauthtoken(log, pool, &token, field, &value);
if (f) {
ngx_log_debug2 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: got %V:%V from ZM_AUTH_TOKEN",
+ "zmauth: got %V:%V from ZM_AUTH_TOKEN(AMB)",
field, &value);
if (value.len > 0) {
pvalue = ngx_palloc(pool, sizeof(ngx_str_t));
@@ -1694,12 +1694,12 @@ zmauth_check_authtoken(ngx_http_request_t *r, ngx_str_t* field,
}
} else {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: no %V in ZM_AUTH_TOKEN", field);
+ "zmauth: no %V in ZM_AUTH_TOKEN(AMB)", field);
}
} else {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: no ZM_AUTH_TOKEN",
+ "zmauth: no ZM_AUTH_TOKEN(AMB)",
&token);
}
@@ -1787,7 +1787,7 @@ zmauth_check_admin_authtoken(ngx_http_request_t *r, ngx_str_t* field,
log = r->connection->log;
ngx_log_debug0 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: search for ZM_ADMIN_AUTH_TOKEN");
+ "zmauth: search for ZM_ADMIN_AUTH_TOKEN(AMB)");
/* look for auth token in the request cookie(s)
AMB - There appears that in version 1.24.0 request member "cookie" has changed. This change occurs from upgrading the nginx library from version 1.20.0 to 1.24.0 (Previously it was ngx_array_t and now its changed to ngx_table_elt_t which don't have members elts & nelts).*/
@@ -1797,13 +1797,13 @@ zmauth_check_admin_authtoken(ngx_http_request_t *r, ngx_str_t* field,
if (f) {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: found ZM_AUTH_TOKEN:%V",
+ "zmauth: found ZM_AUTH_TOKEN:(AMB)%V",
&token);
f = ngx_field_from_zmauthtoken(log, pool, &token, field, &value);
if (f) {
ngx_log_debug2 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: got %V:%V from ZM_AUTH_TOKEN",
+ "zmauth: got %V:%V from ZM_AUTH_TOKEN(AMB)",
field, &value);
if (value.len > 0) {
@@ -1824,12 +1824,12 @@ zmauth_check_admin_authtoken(ngx_http_request_t *r, ngx_str_t* field,
}
} else {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: no %V in ZM_ADMIN_AUTH_TOKEN", field);
+ "zmauth: no %V in ZM_ADMIN_AUTH_TOKEN(AMB)", field);
}
} else {
ngx_log_debug1 (NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: no ZM_ADMIN_AUTH_TOKEN",
+ "zmauth: no ZM_ADMIN_AUTH_TOKEN(AMB)",
&token);
}
From 45f75c1e0cd7bde90a981b691d445672f89db484 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Tue, 26 Sep 2023 12:28:41 +0530
Subject: [PATCH 05/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- Modified some logging statements in-order to differentiate it from original logs. This changes will be reverted once testing done.
---
.../ngx_http_upstream_zmauth_module.c | 95 +++++++++++--------
1 file changed, 53 insertions(+), 42 deletions(-)
diff --git a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
index b5e18aaf4..67f6cc5a6 100644
--- a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
+++ b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
@@ -855,48 +855,59 @@ ngx_get_cookie_value(ngx_log_t *log,
u_char *s, *p, *e;
ngx_str_t V, n, v;
ngx_flag_t f;
- // AMB : changed cookies from ngx_array_t to ngx_table_elt_t when upgrading the nginx library from version 1.20.0 to 1.24.0
- for (c = cookies, f = 0; /*c < cookies + ncookies && f == 0*/;/* ++c*/) {
- V = c->value;
- /* v is of the form "name=value; name=value;" */
- s = V.data;
- e = s + V.len;
- p = s;
-
- ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
- "zmauth: examining cookie value:(AMB)%V",&V);
-
- while (p < e) {
- n.data = p;
- while (p < e && *p != '=') {
- ++p;
- }
- if (p == e) {
- break;
- }
- n.len = p - n.data;
- ++p; // consume =
- v.data = p;
- while (p < e && *p != ';') {
- ++p;
- }
- v.len = p - v.data;
- if (n.len == name->len && ngx_memcmp(n.data, name->data, n.len)
- == 0) {
- *value = v;
- f = 1;
- break;
- }
- if (p == e) {
- break;
- }
- ++p; // consume ;
- while (p < e && (*p == ' ' || *p == '\t')) {
- ++p;
- }
- }
- break; // AMB : change done as part of cookie handling as per new type "ngx_table_elt_t"
- }
+
+ if (cookies && cookies->value.len)
+ {
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+ "zmauth: printing cookie value:(AMB)%V",&cookies->value);
+ // AMB : changed cookies from ngx_array_t to ngx_table_elt_t when upgrading the nginx library from version 1.20.0 to 1.24.0
+ for (c = cookies, f = 0; /*c < cookies + ncookies && f == 0*/;/* ++c*/) {
+ V = c->value;
+ /* v is of the form "name=value; name=value;" */
+ s = V.data;
+ e = s + V.len;
+ p = s;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
+ "zmauth: examining cookie value:(AMB)%V",&V);
+
+ while (p < e) {
+ n.data = p;
+ while (p < e && *p != '=') {
+ ++p;
+ }
+ if (p == e) {
+ break;
+ }
+ n.len = p - n.data;
+ ++p; // consume =
+ v.data = p;
+ while (p < e && *p != ';') {
+ ++p;
+ }
+ v.len = p - v.data;
+ if (n.len == name->len && ngx_memcmp(n.data, name->data, n.len)
+ == 0) {
+ *value = v;
+ f = 1;
+ break;
+ }
+ if (p == e) {
+ break;
+ }
+ ++p; // consume ;
+ while (p < e && (*p == ' ' || *p == '\t')) {
+ ++p;
+ }
+ }
+ break; // AMB : change done as part of cookie handling as per new type "ngx_table_elt_t"
+ }
+ }
+ else
+ {
+ ngx_log_debug0 (NGX_LOG_DEBUG_HTTP, log, 0,
+ "zmauth: exiting get cookie without value:(AMB)");
+ }
return f;
}
From 24bd8cb22ac3388778142f5a3f40044346c4fb88 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Wed, 27 Sep 2023 01:02:32 +0530
Subject: [PATCH 06/14] ZCOMT-2586 - Compile the nginx code in branch
feature/ZCS-11179
- Minor change. Initialized return bool variable ngx_flag_t to 0.
---
.../http/upstreamzmauth/ngx_http_upstream_zmauth_module.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
index 67f6cc5a6..a9b74716e 100644
--- a/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
+++ b/thirdparty/nginx/zmmodules/http/upstreamzmauth/ngx_http_upstream_zmauth_module.c
@@ -854,7 +854,7 @@ ngx_get_cookie_value(ngx_log_t *log,
ngx_table_elt_t *c;
u_char *s, *p, *e;
ngx_str_t V, n, v;
- ngx_flag_t f;
+ ngx_flag_t f = 0;
if (cookies && cookies->value.len)
{
From 9140a96ff9c384c38577217f459ab80ede2be5f1 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Mon, 2 Oct 2023 16:44:50 +0530
Subject: [PATCH 07/14] ZCS-13998 : NGINX - Customization code separation from
repo
- Created the patch files to add zimbra specific customization on the top of the public nginx repository stable-1.24.0
---
thirdparty/nginx/patches/nginx_README.patch | 14 +
thirdparty/nginx/patches/nginx_auto_cc.patch | 15 +
thirdparty/nginx/patches/nginx_auto_lib.patch | 110 +
.../nginx/patches/nginx_auto_modules.patch | 65 +
.../nginx/patches/nginx_auto_options.patch | 58 +
.../nginx/patches/nginx_auto_sources.patch | 45 +
thirdparty/nginx/patches/nginx_src_core.patch | 4943 +++++++++++++++++
.../nginx/patches/nginx_src_event.patch | 45 +
thirdparty/nginx/patches/nginx_src_http.patch | 1687 ++++++
.../patches/nginx_src_mail_ngx_mail.patch | 260 +
...x_src_mail_ngx_mail_auth_http_module.patch | 18 +
.../nginx_src_mail_ngx_mail_core_module.patch | 160 +
.../nginx_src_mail_ngx_mail_handler.patch | 1490 +++++
...nginx_src_mail_ngx_mail_imap_handler.patch | 462 ++
...ginx_src_mail_ngx_mail_imap_module_c.patch | 420 ++
...ginx_src_mail_ngx_mail_imap_module_h.patch | 18 +
.../nginx_src_mail_ngx_mail_parse.patch | 1336 +++++
...nginx_src_mail_ngx_mail_pop3_handler.patch | 386 ++
...ginx_src_mail_ngx_mail_pop3_module_c.patch | 370 ++
...ginx_src_mail_ngx_mail_pop3_module_h.patch | 24 +
...nginx_src_mail_ngx_mail_proxy_module.patch | 1663 ++++++
.../nginx_src_mail_ngx_mail_smtp_module.patch | 14 +
22 files changed, 13603 insertions(+)
create mode 100644 thirdparty/nginx/patches/nginx_README.patch
create mode 100644 thirdparty/nginx/patches/nginx_auto_cc.patch
create mode 100644 thirdparty/nginx/patches/nginx_auto_lib.patch
create mode 100644 thirdparty/nginx/patches/nginx_auto_modules.patch
create mode 100644 thirdparty/nginx/patches/nginx_auto_options.patch
create mode 100644 thirdparty/nginx/patches/nginx_auto_sources.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_core.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_event.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_http.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_auth_http_module.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_core_module.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_handler.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_handler.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_c.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_h.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_handler.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_c.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_h.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_proxy_module.patch
create mode 100644 thirdparty/nginx/patches/nginx_src_mail_ngx_mail_smtp_module.patch
diff --git a/thirdparty/nginx/patches/nginx_README.patch b/thirdparty/nginx/patches/nginx_README.patch
new file mode 100644
index 000000000..876c1167d
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_README.patch
@@ -0,0 +1,14 @@
+--- nginx/README.md 1970-01-01 05:30:00.000000000 +0530
++++ nginx/README.md 2023-09-14 18:47:11.380437400 +0530
+@@ -0,0 +1,11 @@
++# nginx
++
++This is the official repository for building out the third party dependency nginx for Zimbra Collaboration Suite 8.7 and later.
++
++Issues should be reported via [Zimbra's bugzilla](https://bugzilla.zimbra.com)
++
++## Development branch
++zimbra/develop
++
++## Release tags
++zimbra-release-1.24.0
diff --git a/thirdparty/nginx/patches/nginx_auto_cc.patch b/thirdparty/nginx/patches/nginx_auto_cc.patch
new file mode 100644
index 000000000..b56cb14b3
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_auto_cc.patch
@@ -0,0 +1,15 @@
+diff -urN nginx/auto/cc/gcc nginx/auto/cc/gcc
+--- nginx/auto/cc/gcc 2023-03-07 16:26:44.050300500 +0530
++++ nginx/auto/cc/gcc 2023-09-14 18:47:11.398148600 +0530
+@@ -50,7 +50,10 @@
+
+ #NGX_GCC_OPT="-O2"
+ #NGX_GCC_OPT="-Os"
+-NGX_GCC_OPT="-O"
++# Zimbra customizations start here (Jira Tickets: )
++#NGX_GCC_OPT="-O"
++NGX_GCC_OPT="-O0"
++# Zimbra customizations end here
+
+ #CFLAGS="$CFLAGS -fomit-frame-pointer"
+
diff --git a/thirdparty/nginx/patches/nginx_auto_lib.patch b/thirdparty/nginx/patches/nginx_auto_lib.patch
new file mode 100644
index 000000000..cf6aff81c
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_auto_lib.patch
@@ -0,0 +1,110 @@
+diff -urN nginx/auto/lib/conf nginx/auto/lib/conf
+--- nginx/auto/lib/conf 2023-03-07 16:26:44.070240100 +0530
++++ nginx/auto/lib/conf 2023-09-14 18:47:11.422502700 +0530
+@@ -52,3 +52,9 @@
+ if [ $NGX_LIBATOMIC != NO ]; then
+ . auto/lib/libatomic/conf
+ fi
++
++# Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++if [ $USE_SASL = YES ]; then
++ . auto/lib/sasl/conf
++fi
++# Zimbra customizations end here
+diff -urN nginx/auto/lib/sasl/conf nginx/auto/lib/sasl/conf
+--- nginx/auto/lib/sasl/conf 1970-01-01 05:30:00.000000000 +0530
++++ nginx/auto/lib/sasl/conf 2023-03-04 13:25:59.784471400 +0530
+@@ -0,0 +1,93 @@
++#
++# ***** BEGIN LICENSE BLOCK *****
++# Zimbra Collaboration Suite Server
++# Copyright (C) 2011 Zimbra Software, LLC.
++#
++# The contents of this file are subject to the Zimbra Public License
++# Version 1.4 ("License"); you may not use this file except in
++# compliance with the License. You may obtain a copy of the License at
++# http://www.zimbra.com/license.
++#
++# Software distributed under the License is distributed on an "AS IS"
++# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++# ***** END LICENSE BLOCK *****
++#
++ ngx_feature="SASL library"
++ ngx_feature_name="NGX_SASL"
++ ngx_feature_run=no
++ ngx_feature_incs="#include "
++ ngx_feature_path=
++ ngx_feature_libs="-lsasl2"
++ ngx_feature_test="int rc = sasl_server_init(NULL, \"test\");"
++ . auto/feature
++
++
++if [ $ngx_found = no ]; then
++
++ # FreeBSD port
++
++ ngx_feature="SASL library in /usr/local/"
++ ngx_feature_path="/usr/local/include"
++
++ if [ $NGX_RPATH = YES ]; then
++ ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lsasl2"
++ else
++ ngx_feature_libs="-L/usr/local/lib -lsasl2"
++ fi
++
++ . auto/feature
++fi
++
++
++if [ $ngx_found = no ]; then
++
++ # NetBSD port
++
++ ngx_feature="SASL library in /usr/pkg/"
++ ngx_feature_path="/usr/pkg/include/"
++
++ if [ $NGX_RPATH = YES ]; then
++ ngx_feature_libs="-R/usr/pkg/lib -L/usr/pkg/lib -lsasl2"
++ else
++ ngx_feature_libs="-L/usr/pkg/lib -lsasl2"
++ fi
++
++ . auto/feature
++fi
++
++
++if [ $ngx_found = no ]; then
++
++ # MacPorts
++
++ ngx_feature="SASL library in /opt/local/"
++ ngx_feature_path="/opt/local/include"
++
++ if [ $NGX_RPATH = YES ]; then
++ ngx_feature_libs="-R/opt/local/lib -L/opt/local/lib -lsasl2"
++ else
++ ngx_feature_libs="-L/opt/local/lib -lsasl2"
++ fi
++
++ . auto/feature
++fi
++
++
++if [ $ngx_found = yes ]; then
++
++ CORE_INCS="$CORE_INCS $ngx_feature_path"
++ CORE_LIBS="$CORE_LIBS $ngx_feature_libs"
++ SASL=YES
++
++else
++
++cat << END
++
++$0: error: SASL support in the MAIL filter modules requires the SASL library.
++You can either not enable the feature or install the libraries.
++
++END
++
++ exit 1
++
++fi
diff --git a/thirdparty/nginx/patches/nginx_auto_modules.patch b/thirdparty/nginx/patches/nginx_auto_modules.patch
new file mode 100644
index 000000000..aea232fbd
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_auto_modules.patch
@@ -0,0 +1,65 @@
+--- nginx/auto/modules 2023-08-18 17:02:49.192905800 +0530
++++ nginx/auto/modules 2023-09-14 18:47:11.461941600 +0530
+@@ -63,6 +63,7 @@
+
+ ngx_module_type=HTTP
+
++ # Zimbra customizations start here: Adding ngx_http_upstream_fair (Jira Tickets: )
+ if :; then
+ ngx_module_name="ngx_http_module \
+ ngx_http_core_module \
+@@ -77,7 +78,8 @@
+ src/http/ngx_http_variables.h \
+ src/http/ngx_http_script.h \
+ src/http/ngx_http_upstream.h \
+- src/http/ngx_http_upstream_round_robin.h"
++ src/http/ngx_http_upstream_round_robin.h \
++ src/http/ngx_http_upstream_fair.h"
+ ngx_module_srcs="src/http/ngx_http.c \
+ src/http/ngx_http_core_module.c \
+ src/http/ngx_http_special_response.c \
+@@ -88,13 +90,14 @@
+ src/http/ngx_http_variables.c \
+ src/http/ngx_http_script.c \
+ src/http/ngx_http_upstream.c \
+- src/http/ngx_http_upstream_round_robin.c"
++ src/http/ngx_http_upstream_round_robin.c \
++ src/http/ngx_http_upstream_fair.c"
+ ngx_module_libs=
+ ngx_module_link=YES
+
+ . auto/module
+ fi
+-
++ # Zimbra customizations end here (Jira Tickets: )
+
+ if [ $HTTP_CACHE = YES ]; then
+ have=NGX_HTTP_CACHE . auto/have
+@@ -939,6 +942,13 @@
+
+ ngx_module_incs=
+
++ # Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++ if [ $MAIL_SASL = YES ]; then
++ USE_SASL=YES
++ have=NGX_MAIL_SASL . auto/have
++ fi
++ # Zimbra customizations end
++
+ if [ $MAIL_SSL = YES ]; then
+ USE_OPENSSL=YES
+ have=NGX_MAIL_SSL . auto/have
+@@ -1285,9 +1295,11 @@
+ . auto/module
+ fi
+
+-
++# Zimbra customizations start here: Adding Nginx memcache and zm_lookup module (Jira Tickets: )
+ modules="$CORE_MODULES $EVENT_MODULES"
+-
++modules="$modules $MEMCACHE_MODULE"
++modules="$modules $ZM_LOOKUP_MODULE"
++# Zimbra customizations end here
+
+ # thread pool module should be initialized after events
+ if [ $USE_THREADS = YES ]; then
diff --git a/thirdparty/nginx/patches/nginx_auto_options.patch b/thirdparty/nginx/patches/nginx_auto_options.patch
new file mode 100644
index 000000000..e6da5891e
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_auto_options.patch
@@ -0,0 +1,58 @@
+--- nginx/auto/options 2023-08-18 17:02:49.224080200 +0530
++++ nginx/auto/options 2023-09-14 18:47:11.483533400 +0530
+@@ -151,6 +151,12 @@
+ USE_OPENSSL=NO
+ OPENSSL=NONE
+
++# Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++USE_SASL=NO
++SASL=NONE
++SASL_OPT=
++# Zimbra customizations end here
++
+ USE_ZLIB=NO
+ ZLIB=NONE
+ ZLIB_OPT=
+@@ -292,6 +298,9 @@
+ --with-http_stub_status_module) HTTP_STUB_STATUS=YES ;;
+
+ --with-mail) MAIL=YES ;;
++ # Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++ --with-mail-sasl) MAIL_SASL=YES ;;
++ # Zimbra customizations end here
+ --with-mail=dynamic) MAIL=DYNAMIC ;;
+ --with-mail_ssl_module) MAIL_SSL=YES ;;
+ # STUB
+@@ -363,6 +372,11 @@
+ --with-openssl=*) OPENSSL="$value" ;;
+ --with-openssl-opt=*) OPENSSL_OPT="$value" ;;
+
++ # Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++ --with-sasl=*) SASL="$value" ;;
++ --with-sasl-opt=*) SASL_OPT="$value" ;;
++ # Zimbra customizations end here
++
+ --with-md5=*)
+ NGX_POST_CONF_MSG="$NGX_POST_CONF_MSG
+ $0: warning: the \"--with-md5\" option is deprecated"
+@@ -524,6 +538,9 @@
+ --without-http-cache disable HTTP cache
+
+ --with-mail enable POP3/IMAP4/SMTP proxy module
++ # Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++ --with-mail-sasl enable SASL support
++ # Zimbra customizations end here
+ --with-mail=dynamic enable dynamic POP3/IMAP4/SMTP proxy module
+ --with-mail_ssl_module enable ngx_mail_ssl_module
+ --without-mail_pop3_module disable ngx_mail_pop3_module
+@@ -577,6 +594,10 @@
+ --with-pcre-jit build PCRE with JIT compilation support
+ --without-pcre2 do not use PCRE2 library
+
++ # Zimbra customizations start here: Implement SASL Authentication (Jira Tickets: )
++ --with-sasl=DIR set path to sasl library sources
++ --with-sasl-opt=OPTIONS set additional options for sasl building
++ # Zimbra customizations end
+ --with-zlib=DIR set path to zlib library sources
+ --with-zlib-opt=OPTIONS set additional build options for zlib
+ --with-zlib-asm=CPU use zlib assembler sources optimized
diff --git a/thirdparty/nginx/patches/nginx_auto_sources.patch b/thirdparty/nginx/patches/nginx_auto_sources.patch
new file mode 100644
index 000000000..7c1506f2d
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_auto_sources.patch
@@ -0,0 +1,45 @@
+--- nginx/auto/sources 2023-08-18 17:02:49.229066800 +0530
++++ nginx/auto/sources 2023-09-14 18:47:11.526404800 +0530
+@@ -7,6 +7,7 @@
+
+ CORE_INCS="src/core"
+
++# Zimbra customizations start here: Adding Nginx memcache and zm_lookup module (Jira Tickets: )
+ CORE_DEPS="src/core/nginx.h \
+ src/core/ngx_config.h \
+ src/core/ngx_core.h \
+@@ -39,6 +40,8 @@
+ src/core/ngx_module.h \
+ src/core/ngx_resolver.h \
+ src/core/ngx_open_file_cache.h \
++ src/core/ngx_memcache.h \
++ src/core/ngx_zm_lookup.h \
+ src/core/ngx_crypt.h \
+ src/core/ngx_proxy_protocol.h \
+ src/core/ngx_syslog.h"
+@@ -76,10 +79,12 @@
+ src/core/ngx_module.c \
+ src/core/ngx_resolver.c \
+ src/core/ngx_open_file_cache.c \
++ src/core/ngx_memcache.c \
++ src/core/ngx_zm_lookup.c \
+ src/core/ngx_crypt.c \
+ src/core/ngx_proxy_protocol.c \
+ src/core/ngx_syslog.c"
+-
++# Zimbra customizations end
+
+ EVENT_MODULES="ngx_events_module ngx_event_core_module"
+
+@@ -127,6 +132,11 @@
+ FILE_AIO_SRCS="src/os/unix/ngx_file_aio_read.c"
+ LINUX_AIO_SRCS="src/os/unix/ngx_linux_aio_read.c"
+
++# Zimbra customizations start here: Adding Nginx memcache and zm_lookup module (Jira Tickets: )
++MEMCACHE_MODULE=ngx_memcache_module
++ZM_LOOKUP_MODULE=ngx_zm_lookup_module
++# Zimbra customizations end here
++
+ UNIX_INCS="$CORE_INCS $EVENT_INCS src/os/unix"
+
+ UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \
diff --git a/thirdparty/nginx/patches/nginx_src_core.patch b/thirdparty/nginx/patches/nginx_src_core.patch
new file mode 100644
index 000000000..e056ecd41
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_core.patch
@@ -0,0 +1,4943 @@
+diff -urN nginx/src/core/ngx_log.c nginx/src/core/ngx_log.c
+--- nginx/src/core/ngx_log.c 2023-07-26 17:25:13.691656100 +0530
++++ nginx/src/core/ngx_log.c 2023-10-01 21:39:22.880121200 +0530
+@@ -86,7 +86,7 @@
+
+ static const char *debug_levels[] = {
+ "debug_core", "debug_alloc", "debug_mutex", "debug_event",
+- "debug_http", "debug_mail", "debug_stream"
++ "debug_http", "debug_mail", "debug_stream", "debug_zimbra" // Zimbra customizations added debug_zimbra for logging (Jira Tickets: Part of first commit:https://github.com/Zimbra/packages/commit/2b59af7543b67542dfdb0ea21844f0caf73b0cd0)
+ };
+
+
+diff -urN nginx/src/core/ngx_log.h nginx/src/core/ngx_log.h
+--- nginx/src/core/ngx_log.h 2023-07-26 17:25:13.689661500 +0530
++++ nginx/src/core/ngx_log.h 2023-10-01 21:39:22.878112400 +0530
+@@ -30,14 +30,18 @@
+ #define NGX_LOG_DEBUG_HTTP 0x100
+ #define NGX_LOG_DEBUG_MAIL 0x200
+ #define NGX_LOG_DEBUG_STREAM 0x400
+-
++// Zimbra customizations start here (Jira Tickets: )
++#define NGX_LOG_DEBUG_ZIMBRA 0x800
++// Zimbra customizations end here
+ /*
+ * do not forget to update debug_levels[] in src/core/ngx_log.c
+ * after the adding a new debug level
+ */
+
+ #define NGX_LOG_DEBUG_FIRST NGX_LOG_DEBUG_CORE
+-#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_STREAM
++// Zimbra customizations start here: instead of NGX_LOG_DEBUG_STREAM as last debug logs we have mentioned ZIMBRA logs as last one (Jira Tickets:Part of first commit:https://github.com/Zimbra/packages/commit/2b59af7543b67542dfdb0ea21844f0caf73b0cd0 )
++#define NGX_LOG_DEBUG_LAST NGX_LOG_DEBUG_ZIMBRA
++// Zimbra customizations end here
+ #define NGX_LOG_DEBUG_CONNECTION 0x80000000
+ #define NGX_LOG_DEBUG_ALL 0x7ffffff0
+
+diff -urN nginx/src/core/ngx_memcache.c nginx/src/core/ngx_memcache.c
+--- nginx/src/core/ngx_memcache.c 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/core/ngx_memcache.c 2023-03-04 13:25:59.822406800 +0530
+@@ -0,0 +1,2185 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#include
++#include
++
++#define MC_INVALID_HASH ((ngx_uint_t) - 1)
++#define MC_REQ_POOL_SIZE 1024
++#define SHA256_KEY_LENGTH 64
++
++static int mc_sndbuf_len = 256 * 1024;
++
++ngx_str_t NGX_EMPTY_STR = ngx_string("");
++
++/* config-related function prototypes */
++static char *ngx_memcache_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
++static void *ngx_memcache_create_conf(ngx_cycle_t *cycle);
++static char *ngx_memcache_init_conf(ngx_cycle_t *cycle, void *conf);
++static ngx_int_t ngx_memcache_init_process(ngx_cycle_t *cycle);
++static char *
++ngx_memcache_servers (ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
++static char *
++ngx_memcache_ttl (ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
++
++/* memcache protocol response handler prototype */
++typedef ngx_int_t (*mcp_handler)
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++
++/* memcache protocol response processing functions */
++static ngx_int_t ngx_memcache_process_add_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_add_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_add_invalid
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_delete_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_delete_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_get_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_get_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_incr_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_incr_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_decr_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_decr_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_client_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_server_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_error_line
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++static ngx_int_t ngx_memcache_process_any_response
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed);
++
++/* hashing functions to elect a memcached server for caching */
++static ngx_uint_t ngx_memcache_hash (u_char *key, size_t len);
++static ngx_uint_t ngx_memcache_perl_hash (u_char *key, size_t len);
++static ngx_str_t ngx_sha256_hash (ngx_pool_t* p, u_char *key, size_t len);
++
++/* generic event handler to read any memcache response */
++static void ngx_memcache_any_read_handler (ngx_event_t *rev);
++static void ngx_memcache_dummy_write_handler (ngx_event_t *wev);
++static void ngx_memcache_reconnection_handler (ngx_event_t *ev);
++static inline void ngx_memcache_callback (mc_work_t * w);
++
++/* Workqueue and connection maintenance functions */
++static inline mc_workqueue_t *ngx_memcache_wq_front (mc_workqueue_t *head);
++static inline ngx_int_t ngx_memcache_wq_isempty (mc_workqueue_t *head);
++static void ngx_memcache_purge_connection_workqueue (mc_context_t *mcctx, mc_response_code_t res);
++static void ngx_memcache_reestablish_connection (mc_context_t *mcctx);
++static inline void ngx_memcache_close_connection (ngx_peer_connection_t *pc);
++static inline void ngx_memcache_prepare_reconnection (mc_context_t *mcctx);
++
++/* main post function */
++static void ngx_memcache_do_post(mc_work_t *w, ngx_str_t key, ngx_str_t value,
++ ngx_str_t ttl, ngx_pool_t *p, ngx_log_t *l);
++
++/* other utility */
++static u_char * ngx_memcache_hexstr(u_char* md, int len);
++static ngx_str_t ngx_memcache_create_pdu(ngx_pool_t *pool, mc_work_t *w,
++ ngx_str_t key, ngx_str_t value, ngx_str_t ttl, ngx_log_t * log);
++
++static ngx_command_t ngx_memcache_commands[] =
++{
++ { ngx_string("memcache"),
++ NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
++ ngx_memcache_block,
++ 0,
++ 0,
++ NULL },
++
++ { ngx_string("servers"),
++ NGX_DIRECT_CONF|NGX_MEMCACHE_CONF|NGX_CONF_1MORE,
++ ngx_memcache_servers,
++ 0,
++ 0,
++ NULL },
++
++ { ngx_string("timeout"),
++ NGX_DIRECT_CONF|NGX_MEMCACHE_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ 0,
++ offsetof(ngx_memcache_conf_t, timeout),
++ NULL },
++
++ { ngx_string("reconnect"),
++ NGX_DIRECT_CONF|NGX_MEMCACHE_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ 0,
++ offsetof(ngx_memcache_conf_t, reconnect),
++ NULL },
++
++ { ngx_string("ttl"),
++ NGX_DIRECT_CONF|NGX_MEMCACHE_CONF|NGX_CONF_TAKE1,
++ ngx_memcache_ttl,
++ 0,
++ offsetof(ngx_memcache_conf_t, ttl),
++ NULL },
++
++ ngx_null_command
++};
++
++static ngx_core_module_t ngx_memcache_module_ctx =
++{
++ ngx_string("memcache"),
++ ngx_memcache_create_conf,
++ ngx_memcache_init_conf
++};
++
++ngx_module_t ngx_memcache_module =
++{
++ NGX_MODULE_V1,
++ &ngx_memcache_module_ctx, /* module context */
++ ngx_memcache_commands, /* module directives */
++ NGX_CORE_MODULE, /* module type */
++ NULL, /* init master */
++ NULL, /* init module */
++ ngx_memcache_init_process, /* init process */
++ NULL, /* init thread */
++ NULL, /* exit thread */
++ NULL, /* exit process */
++ NULL, /* exit master */
++ NGX_MODULE_V1_PADDING
++};
++
++static void *ngx_memcache_create_conf(ngx_cycle_t *cycle)
++{
++ ngx_memcache_conf_t *mcf;
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++
++ log = cycle->log;
++ pool = ngx_create_pool (8 * ngx_pagesize, cycle->log);
++
++ mcf = ngx_pcalloc (pool, sizeof(ngx_memcache_conf_t));
++ if (mcf == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ mcf->cpool = pool;
++ mcf->log = log;
++
++ if(ngx_array_init (&mcf->servers, mcf->cpool, 4, sizeof(ngx_addr_t*))
++ != NGX_OK) {
++ return NGX_CONF_ERROR;
++ }
++
++ mcf->timeout = NGX_CONF_UNSET_MSEC;
++ mcf->reconnect = NGX_CONF_UNSET_MSEC;
++ mcf->ttl = NGX_CONF_UNSET_MSEC;
++ mcf->ttl_text.len = 0;
++ mcf->allow_unqualified = NGX_CONF_UNSET;
++
++ ngx_log_error(NGX_LOG_DEBUG_CORE, cycle->log, 0,
++ "memcache - created configuration:%p", mcf);
++ return mcf;
++}
++
++static char *ngx_memcache_init_conf(ngx_cycle_t *cycle, void *conf)
++{
++ ngx_memcache_conf_t *mcf = conf;
++
++ ngx_conf_init_msec_value(mcf->timeout, 5000);
++ ngx_conf_init_msec_value(mcf->reconnect, 60000);
++ ngx_conf_init_msec_value(mcf->ttl, 0);
++ if (mcf->ttl_text.len == 0) {
++ ngx_str_set(&mcf->ttl_text, "0");
++ }
++ ngx_conf_init_value(mcf->allow_unqualified, 0);
++
++ ngx_log_error(NGX_LOG_DEBUG_CORE,cycle->log, 0,
++ "memcache - initialized config defaults:%p", mcf);
++ return NGX_CONF_OK;
++}
++
++static char* ngx_memcache_ttl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ char *res;
++ ngx_str_t *value, *ttl;
++ ngx_memcache_conf_t *mcf = (ngx_memcache_conf_t *)conf;
++
++ res = ngx_conf_set_msec_slot(cf, cmd, conf);
++
++ if (res != NGX_CONF_OK) {
++ return res;
++ }
++
++ value = cf->args->elts;
++ ttl = &value[1];
++
++ /* trim the last 5 digit 'NNNms' and become the number of seconds
++ * for example, 3600000ms --> 3600 */
++ if (mcf->ttl > 1000) {
++ mcf->ttl_text.data = ttl->data;
++ mcf->ttl_text.len = ttl->len - 5;
++ } else if (mcf->ttl > 0) {
++ /* 0 ~ 1000ms, make it 1 */
++ ngx_str_set(&mcf->ttl_text, "1");
++ } else {
++ /* ttl is 0, so keep the default ttl_text "0" */
++ }
++
++ return NGX_CONF_OK;
++}
++/* per-process initialization routine */
++static ngx_int_t ngx_memcache_init_process(ngx_cycle_t *cycle)
++{
++ ngx_memcache_conf_t *mcf;
++ ngx_log_t *log;
++ ngx_pool_t *pool;
++ ngx_addr_t *peer,
++ **peers;
++ ngx_peer_connection_t *peercxn;
++ mc_context_t *mcctx;
++ mc_workqueue_t *mcwq;
++ ngx_int_t rc;
++ ngx_uint_t npeers,i;
++ ngx_buf_t *buff;
++
++ mcf = (ngx_memcache_conf_t*) ngx_get_conf(cycle->conf_ctx, ngx_memcache_module);
++ log = cycle->log;
++ // pool = ngx_create_pool(8*ngx_pagesize,log);
++ pool = mcf->cpool;
++
++ npeers = mcf->servers.nelts;
++ peers = (ngx_addr_t **)mcf->servers.elts;
++
++ rc = ngx_array_init(&mcf->contexts, pool, npeers > 0 ? npeers : 1, sizeof(mc_context_t));
++ if (rc != NGX_OK) {
++ return rc;
++ }
++
++ for ( i = 0; i < npeers; ++i)
++ {
++ peer = peers[i];
++ peercxn = ngx_pcalloc(pool, sizeof(ngx_peer_connection_t));
++ peercxn->sockaddr = peer->sockaddr; /* XXX peer->sockaddr is on cf->pool */
++ peercxn->socklen = peer->socklen;
++ peercxn->name = &peer->name; /* XXX peer->name is on cf->pool */
++ peercxn->get = ngx_event_get_peer;
++ peercxn->log = log;
++ peercxn->log_error = NGX_ERROR_ERR;
++
++ rc = ngx_event_connect_peer(peercxn);
++
++ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
++ ngx_log_error (NGX_LOG_ERR, log, 0,
++ "cannot connect to memcached server %V (rc:%d)",
++ &peer->name, rc);
++
++ if (peercxn->connection) {
++ ngx_close_connection (peercxn->connection);
++ }
++ continue;
++ }
++
++ /* nginx sockets are non-blocking, so connect() returns EINPROGRESS */
++ peercxn->connection->read->handler = ngx_memcache_any_read_handler;
++ peercxn->connection->write->handler = ngx_memcache_dummy_write_handler;
++
++ mcctx = ngx_array_push (&mcf->contexts);
++ ngx_memzero (mcctx, sizeof (mc_context_t));
++ buff = ngx_create_temp_buf (pool, ngx_pagesize); /* circular buffer */
++ mcctx->readbuffer = buff;
++
++ /* reconnection event */
++ mcctx->reconnect_ev = ngx_palloc (pool, sizeof (ngx_event_t));
++ ngx_memzero (mcctx->reconnect_ev, sizeof (ngx_event_t));
++ mcctx->reconnect_ev->handler = ngx_memcache_reconnection_handler;
++ mcctx->reconnect_ev->log = log;
++
++ /* Initialize the head of the work queue doubly-linked list */
++ mcwq = &mcctx->wq_head;
++ mcwq->w.request_code = mcreq_noop;
++ mcwq->pool = pool;
++ mcwq->prev = mcwq;
++ mcwq->next = mcwq;
++
++ peercxn->connection->data = mcctx;
++ peercxn->connection->log = log;
++
++ mcctx->srvconn = peercxn;
++ mcctx->srvaddr = peer;
++ mcctx->status = mcchan_good;
++ mcctx->timeout = mcf->timeout;
++ mcctx->cxn_interval = mcf->reconnect;
++ setsockopt(peercxn->connection->fd, SOL_SOCKET, SO_SNDBUF,
++ (void *) &mc_sndbuf_len, sizeof (mc_sndbuf_len));
++ }
++
++ ngx_log_error(NGX_LOG_INFO, log, 0,
++ "memcache: %d/%d connections initialized",
++ mcf->contexts.nelts, mcf->servers.nelts);
++
++ return NGX_OK;
++}
++
++static char *ngx_memcache_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ ngx_conf_t ocf;
++ char *rc;
++
++ ocf = *cf;
++
++ cf->ctx = cf->cycle->conf_ctx;
++ cf->module_type = NGX_CORE_MODULE;
++ cf->cmd_type = NGX_MEMCACHE_CONF;
++
++ rc = ngx_conf_parse(cf, NULL);
++
++ *cf = ocf;
++
++ return rc;
++}
++
++static char *
++ngx_memcache_servers (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ ngx_memcache_conf_t *mcf = conf;
++ ngx_addr_t **server;
++ ngx_uint_t i;
++ ngx_url_t u;
++
++ for (i = 1; i < cf->args->nelts; ++i)
++ {
++ server = ngx_array_push(&mcf->servers);
++ if (server == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ *server = NULL;
++
++ ngx_memzero(&u, sizeof(u));
++ u.url = ((ngx_str_t *)cf->args->elts)[i];
++ u.default_port = 11211;
++ u.uri_part = 1;
++
++ /* note - since ngx_parse_url uses pools from cf, therefore all address
++ structures in *server will be allocated on the config pool instead
++ of the memcached pool
++ */
++ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
++ if (u.err) {
++ ngx_log_error(NGX_LOG_ERR, cf->cycle->log, 0,
++ "%s in memcache:server %V", u.err, &u.url);
++ }
++ return NGX_CONF_ERROR;
++ }
++
++ *server = u.addrs;
++ }
++
++ return NGX_CONF_OK;
++}
++
++/* Work queue manipulation functions */
++static inline mc_workqueue_t *ngx_memcache_wq_front (mc_workqueue_t *head)
++{
++ return head->next;
++}
++
++mc_workqueue_t *ngx_memcache_wq_enqueue (mc_workqueue_t *head, mc_workqueue_t *wqe)
++{
++ wqe->prev = head->prev;
++ wqe->next = head;
++ wqe->prev->next = wqe;
++ wqe->next->prev = wqe;
++ return wqe;
++}
++
++mc_workqueue_t *ngx_memcache_wq_dequeue (mc_workqueue_t *head)
++{
++ mc_workqueue_t *wqe;
++
++ wqe = head->next;
++
++ if (wqe != head)
++ {
++ wqe->prev->next = wqe->next;
++ wqe->next->prev = wqe->prev;
++ wqe->prev = NULL;
++ wqe->next = NULL;
++ }
++
++ return wqe;
++}
++
++static inline ngx_int_t ngx_memcache_wq_isempty (mc_workqueue_t *head)
++{
++ return (ngx_memcache_wq_front(head) == head);
++}
++
++/* Ignore a work entry in memcache work queue. This should be done if
++ * the ctx who initiated the memcache request is destroyed before
++ * memcache server returns. Otherwise, when response is coming, the
++ * invalid ctx may be callback and reused.
++ *
++ * Any work entry in the queue whose ctx is equal to the specified one
++ * will be ignored.
++ *
++ * */
++void ngx_memcache_ignore_work_by_ctx (void * ctx) {
++ mc_workqueue_t * head, * entry;
++ ngx_memcache_conf_t * mcf;
++ mc_context_t * contexts;
++ ngx_uint_t i;
++
++ mcf = (ngx_memcache_conf_t *)
++ ngx_get_conf(ngx_cycle->conf_ctx, ngx_memcache_module);
++ contexts = (mc_context_t *)mcf->contexts.elts;
++ for (i = 0; i < mcf->contexts.nelts; i++) {
++ mc_context_t * context = contexts + i;
++ head = &context->wq_head;
++ if (!ngx_memcache_wq_isempty(head)) {
++ entry = head->next;
++ while (entry->w.request_code != mcreq_noop) {
++ if ((void *) entry->w.ctx == (void *) ctx ) {
++ // mark it NULL and ignored later
++ entry->w.ctx = NULL;
++ }
++ entry = entry->next;
++ }
++ }
++ }
++}
++
++/* Post a memcached request onto the workqueue of a memcached server
++ w work request describing the task
++ (also contains on_success/on_failure handlers)
++ k opaque key which will be used for calculating the server hash
++ value the data which should be sent to the memcached server
++ p the pool from which additional memory may be allocated as needed
++ l log object for debug/informational messages
++ */
++void ngx_memcache_post (
++ mc_work_t *w,
++ ngx_str_t key,
++ ngx_str_t value,
++ ngx_pool_t *p,
++ ngx_log_t *l
++ )
++{
++ ngx_str_t dummy_ttl = ngx_string("-1");
++ ngx_memcache_post_with_ttl (w, key, value, dummy_ttl, p, l);
++}
++
++void ngx_memcache_post_with_ttl (
++ mc_work_t *w,
++ ngx_str_t key,
++ ngx_str_t value,
++ ngx_str_t ttl,
++ ngx_pool_t *p,
++ ngx_log_t *l) {
++ ngx_memcache_do_post(w, key, value, ttl, p, l);
++}
++
++static void
++ngx_memcache_do_post (
++ mc_work_t *w,
++ ngx_str_t key,
++ ngx_str_t value,
++ ngx_str_t ttl,
++ ngx_pool_t *p,
++ ngx_log_t *l
++ )
++{
++ ngx_uint_t h;
++ size_t t;
++ ssize_t n;
++ mc_context_t *mcctx;
++ mc_workqueue_t *r;
++ ngx_memcache_conf_t *mcf;
++ mc_context_t *contexts;
++ ngx_flag_t locked = 0;
++ ngx_flag_t reclaim = 0;
++ ngx_str_t pdu;
++
++ mcf = (ngx_memcache_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_memcache_module);
++ contexts = (mc_context_t *)mcf->contexts.elts;
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "ngx_mc_log, org_key=[%s]", key.data);
++ h = ngx_memcache_hash (key.data, key.len);
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, l, 0,
++ "ngx_mc_log, posting memcache request to cache server #%d", h);
++ mcctx = contexts + h;
++
++ if (h == MC_INVALID_HASH) {
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, no memcache server available, cannot post request");
++ w->response_code = mcres_failure_unavailable;
++ w->on_failure(w);
++ return;
++ }
++
++ if (p == NULL) {
++ p = ngx_create_pool(MC_REQ_POOL_SIZE, l);
++ if (p == NULL) {
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, failed to create pool, cannot post request");
++ w->response_code = mcres_failure_unavailable;
++ w->on_failure(w);
++ return;
++ }
++ reclaim = 1;
++ }
++
++ key = ngx_sha256_hash (p, key.data, key.len);
++ if (0 == key.len || NULL == key.data) {
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, failed to hash the key, cannot post request");
++ w->response_code = mcres_failure_unavailable;
++ w->on_failure(w);
++ return;
++ }
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "ngx_mc_log, hashed_key=[%s]", key.data);
++
++ pdu = ngx_memcache_create_pdu(p, w, key, value, ttl, l);
++ if (pdu.data == NULL) {
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, failed to create pdu, cannot post request");
++ w->response_code = mcres_failure_normal;
++ w->on_failure(w);
++ return;
++ }
++
++ /* build up the request to enqueue on the workqueue
++ we build up the request earlier on, so that if
++ memory errors occur, we would not have posted a pdu
++ on the memcached channel that we cannot handle
++ */
++
++ r = ngx_pcalloc(p, sizeof(mc_workqueue_t));
++ if (r == NULL) {
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, failed to allocate memory, cannot post request");
++ w->response_code = mcres_failure_unavailable;
++ w->on_failure(w);
++ return;
++ }
++
++ if (ngx_log_tid && mcctx->lock != ngx_log_tid) {
++ ngx_spinlock(&mcctx->lock, ngx_log_tid, 40);
++ locked = 1;
++ }
++ t = 0;
++ while (t < pdu.len)
++ {
++ n = ngx_send (mcctx->srvconn->connection, pdu.data + t, pdu.len - t);
++ if (n > 0) {
++ t += n;
++ if (mcctx->status == mcchan_reconnect) {
++ mcctx->status = mcchan_good;
++ }
++ } else {
++ if (locked)
++ ngx_unlock(&mcctx->lock);
++
++ ngx_log_error (NGX_LOG_NOTICE, l, 0,
++ "ngx_mc_log, memcached channel %V orderly shutdown when posting request",
++ mcctx->srvconn->name);
++
++ mcctx->status = mcchan_bad;
++ ngx_memcache_close_connection (mcctx->srvconn);
++ ngx_memcache_purge_connection_workqueue
++ (mcctx, mcres_failure_again);
++ ngx_memcache_prepare_reconnection(mcctx);
++ w->response_code = mcres_failure_again;
++ w->on_failure(w);
++ return;
++ }
++ }
++
++ if (t == pdu.len) {
++ /* set the read timeout on the server channel *only* if there is no
++ outstanding timer set already (this is to opportunistically catch
++ any responses before the stipulated timeout
++ */
++
++ if (!mcctx->srvconn->connection->read->timer_set) {
++ ngx_add_timer (mcctx->srvconn->connection->read, mcctx->timeout);
++ }
++
++ /* ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, ngx_cycle->log, 0,
++ "XXX post requst:%V", &pdu);*/
++ }
++
++ r->pool = p;
++ r->reclaim = reclaim;
++ r->w = *w;
++ r->w.response_code = mcres_unknown;
++
++ ngx_memcache_wq_enqueue (&mcctx->wq_head, r);
++
++ if (locked) {
++ ngx_unlock(&mcctx->lock);
++ }
++ ngx_log_debug2 (NGX_LOG_DEBUG_CORE, l, 0,
++ "ngx_mc_log, posted request(%p) on server #%d", r, h);
++
++ return;
++}
++
++/* memcache protocol handling routines */
++
++/* process successful add response */
++static ngx_int_t ngx_memcache_process_add_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("STORED") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "STORED" CRLF, sizeof("STORED" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = sizeof ("STORED" CRLF) - 1;
++ wq->w.response_code = mcres_success;
++
++ return NGX_OK;
++}
++
++/* process unsuccessful add response */
++static ngx_int_t ngx_memcache_process_add_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("NOT_STORED") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "NOT_STORED" CRLF, sizeof("NOT_STORED" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = sizeof ("NOT_STORED" CRLF) - 1;
++ wq->w.response_code = mcres_failure_normal;
++
++ return NGX_OK;
++}
++
++/*
++ * process the invalid add command. If the key in add command too long,
++ * memcached will return 2 error msgs for "add CRLF"
++ * and the "CRLF" respectively. It should be:
++ * CLIENT_ERROR bad command line format\r\nERROR\r\n
++ */
++static ngx_int_t ngx_memcache_process_add_invalid
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t len;
++ len = sizeof ("CLIENT_ERROR bad command line format" CRLF) - 1 +
++ sizeof ("ERROR" CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "CLIENT_ERROR bad command line format" CRLF
++ "ERROR" CRLF,
++ len))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = len;
++ wq->w.response_code = mcres_failure_input;
++
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached return error message: "
++ "CLIENT_ERROR bad command line format ERROR");
++
++ return NGX_OK;
++}
++
++/* process successful delete response */
++static ngx_int_t ngx_memcache_process_delete_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("DELETED") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "DELETED" CRLF, sizeof("DELETED" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = sizeof ("DELETED" CRLF) - 1;
++ wq->w.response_code = mcres_success;
++
++ return NGX_OK;
++}
++
++/* handle unsuccessful delete response */
++static ngx_int_t ngx_memcache_process_delete_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("NOT_FOUND") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "NOT_FOUND" CRLF, sizeof("NOT_FOUND" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream,size,wq,consumed);
++ }
++
++ *consumed = sizeof ("NOT_FOUND" CRLF) - 1;
++ wq->w.response_code = mcres_failure_normal;
++
++ return NGX_OK;
++}
++
++/* process successful get response */
++static ngx_int_t ngx_memcache_process_get_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ /* A successful `get' response looks like:
++
++ VALUE keyname flag size
++
++ END
++
++ A successful `get' response must be at least as long as:
++
++ VALUE K F S
++ b
++ END
++ */
++
++ enum {
++ rr_value_read,
++ rr_key_read,
++ rr_flag_read,
++ rr_size_read,
++ rr_data_read,
++ rr_end_read
++ } state;
++
++ size_t minimum_len;
++ u_char *p;
++ /* size_t tokenpos; */
++ /* ngx_str_t key = ngx_string (""); */
++ ngx_str_t value = ngx_string ("");
++ size_t value_size;
++ uint16_t flag;
++
++ minimum_len =
++ sizeof ("VALUE ") - 1 +
++ sizeof ("k ") - 1 +
++ sizeof ("0 ") - 1 +
++ sizeof ("0 ") - 1 +
++ sizeof (CRLF) - 1 +
++ sizeof (CRLF) - 1 +
++ sizeof ("END") - 1 +
++ sizeof (CRLF) -1;
++
++ p = stream;
++ *consumed = 0;
++ value_size = 0;
++
++ /* If there is not enough space to even hold a bare minimum response,
++ then we cannot proceed */
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "VALUE ", sizeof ("VALUE ") - 1))
++ {
++ return ngx_memcache_process_error_line(stream,size,wq,consumed);
++ }
++
++ p += (sizeof ("VALUE ") - 1);
++ *consumed += (sizeof ("VALUE ") - 1);
++ state = rr_value_read;
++
++ for (;(p < stream + size) && (state != rr_end_read); ++p, ++*consumed)
++ {
++ switch (state)
++ {
++ case rr_value_read:
++ /* now we're expecting the key name */
++ /* tokenpos = *consumed; */
++
++ while ((p < stream + size) && (*p != ' '))
++ {
++ ++p;
++ ++*consumed;
++ }
++
++ if (p == stream + size)
++ {
++ /* end of stream */
++ --p; --*consumed;
++ }
++ else
++ {
++ /* The key is constructed */
++ /* key.data = stream + tokenpos; */
++ /* key.len = *consumed - tokenpos; */
++
++ state = rr_key_read;
++ }
++
++ break;
++
++ case rr_key_read:
++ /* now we're expecting a flag, which is a short integer
++ which corresponds to the `flags' argument to mc_add
++ To avoid looping more than is necessary, we'll play a
++ simple trick, which is to initialize the flag to 0,
++ and then keep *10 + the current digit encountered
++ */
++
++ flag = 0;
++
++ while ((p < stream + size) && (*p != ' '))
++ {
++ flag = (flag * 10) + *p;
++ ++p;
++ ++*consumed;
++ }
++
++ if (p == stream + size)
++ {
++ --p; --*consumed;
++ }
++ else
++ {
++ /* The flag is constructed */
++
++ state = rr_flag_read;
++ }
++
++ break;
++
++ case rr_flag_read:
++ /* now we're expecting the size of the data
++ */
++ value_size = 0;
++
++ while ((p < stream + size)
++ && (*p != ' ') /* wasteful ? */
++ && (*p != CR)
++ && (*p != LF) /* wasteful ? */
++ )
++ {
++ value_size = (value_size * 10) + (*p - '0');
++ ++p;
++ ++*consumed;
++ }
++
++ if (p == stream + size)
++ {
++ --p; --*consumed;
++ }
++ else
++ {
++ /* The size is constructed */
++ state = rr_size_read;
++ }
++
++ break;
++
++ case rr_size_read:
++ /* now we're looking out for the data
++ the '\r' has already been consumed in the for loop
++ so we must look beyond the '\n', and then read
++ value_size bytes more from the stream
++ */
++
++ while ((p < stream + size) && (*p != LF))
++ {
++ ++p; ++*consumed;
++ }
++
++ if (p == stream + size)
++ {
++ --p; --*consumed;
++ }
++ else
++ {
++ /* now p is pointing at the line feed preceding the data */
++
++ ++p; ++*consumed;
++
++ if (p == stream + size)
++ {
++ --p; --*consumed;
++ }
++ else
++ {
++ minimum_len =
++ value_size +
++ sizeof (CRLF) - 1 +
++ sizeof ("END") - 1 +
++ sizeof (CRLF) - 1;
++
++
++ if (size - *consumed < minimum_len)
++ {
++ /* request cannot be completed here */
++ }
++ else
++ {
++ /* we have the value, starting at p */
++ value.data = p;
++ value.len = value_size;
++
++ /* now just advance in one shot till the end */
++
++ p+= value_size; *consumed += value_size;
++
++ /* And now, just consume the following CR too
++ so that the END context lands bingo at END
++ */
++
++ state = rr_data_read;
++
++ if (*p == CR) /* this is superfluous */
++ {
++ ++p; ++*consumed;
++ }
++ }
++ }
++ }
++
++ break;
++
++ case rr_data_read:
++ /* we know that sufficient bytes are present, and that we
++ should be looking at "END"
++ */
++
++ if (ngx_memcmp (p, "END" CRLF, sizeof ("END" CRLF) - 1))
++ {
++ /* not possible. try logging here */
++ }
++ else
++ {
++ state = rr_end_read;
++
++ p += (sizeof ("END") - 1);
++ *consumed += (sizeof ("END") - 1);
++
++ /* again, we will consume the CR so that we break out at
++ once */
++
++ if (*p == CR) /* superfluous */
++ {
++ ++p;
++ ++*consumed;
++ }
++ }
++
++ break;
++
++ default:
++ break;
++ }
++ }
++
++ if (state != rr_end_read)
++ {
++ return NGX_AGAIN; /* This means there wasn't enough data */
++ }
++
++ /* we've finished processing the get response */
++
++ wq->w.payload.data = ngx_pstrdup (wq->pool, &value);
++ wq->w.payload.len = value.len;
++ wq->w.response_code = mcres_success;
++
++ return NGX_OK;
++}
++
++/* process unsuccessful get response */
++static ngx_int_t ngx_memcache_process_get_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("END") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "END" CRLF, sizeof("END" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream,size,wq,consumed);
++ }
++
++ *consumed = sizeof ("END" CRLF) - 1;
++ wq->w.response_code = mcres_failure_normal;
++
++ return NGX_OK;
++}
++
++static ngx_int_t ngx_memcache_process_incr_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ u_char *p;
++
++ p = stream;
++
++ while ((p < stream + size) && (*p != CR) && (*p != LF))
++ {
++ if (!(*p >= '0' && *p <= '9')) {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ ++p;
++ ++*consumed;
++ }
++
++ if (p == stream + size) {
++ return NGX_AGAIN;
++ } else {
++ if (size - *consumed >= 2)
++ {
++ if (*p == CR && *(p + 1) == LF)
++ {
++ *consumed += 2;
++ wq->w.payload.len = p - stream;
++ wq->w.payload.data = ngx_palloc(wq->pool, wq->w.payload.len);
++ ngx_memcpy (wq->w.payload.data,stream, wq->w.payload.len);
++ wq->w.response_code = mcres_success;
++ return NGX_OK;
++ }
++ else
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++ }
++ else
++ {
++ return NGX_AGAIN;
++ }
++ }
++}
++
++static ngx_int_t ngx_memcache_process_incr_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("NOT_FOUND") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "NOT_FOUND" CRLF, sizeof ("NOT_FOUND" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = sizeof ("NOT_FOUND" CRLF) - 1;
++ wq->w.response_code = mcres_failure_normal;
++
++ return NGX_OK;
++}
++
++static ngx_int_t ngx_memcache_process_decr_ok
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ u_char *p;
++
++ p = stream;
++
++ while ((p < stream+size) && (*p != CR) && (*p != LF))
++ {
++ if (!(*p>='0' && *p<='9')) {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ ++p;
++ ++*consumed;
++ }
++
++ if (p == stream + size) {
++ return NGX_AGAIN;
++ } else {
++ if (size - *consumed >= 2)
++ {
++ if (*p == CR && *(p+1) == LF)
++ {
++ *consumed += 2;
++ wq->w.payload.len = p-stream;
++ wq->w.payload.data = ngx_palloc(wq->pool,wq->w.payload.len);
++ ngx_memcpy (wq->w.payload.data,stream,wq->w.payload.len);
++ wq->w.response_code = mcres_success;
++ return NGX_OK;
++ }
++ else
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++ }
++ else
++ {
++ return NGX_AGAIN;
++ }
++ }
++}
++
++static ngx_int_t ngx_memcache_process_decr_failed
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("NOT_FOUND") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "NOT_FOUND" CRLF, sizeof ("NOT_FOUND" CRLF) - 1))
++ {
++ return ngx_memcache_process_error_line(stream, size, wq, consumed);
++ }
++
++ *consumed = sizeof ("NOT_FOUND" CRLF) - 1;
++ wq->w.response_code = mcres_failure_normal;
++
++ return NGX_OK;
++}
++
++/* process "ERROR\r\n" */
++static ngx_int_t ngx_memcache_process_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++
++ minimum_len = sizeof ("ERROR") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "ERROR" CRLF, sizeof ("ERROR" CRLF) - 1))
++ {
++ return NGX_ERROR;
++ }
++
++ *consumed = sizeof ("ERROR" CRLF) - 1;
++
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached return error message: ERROR");
++
++ wq->w.response_code = mcres_failure_input;
++ return NGX_OK;
++}
++
++static ngx_int_t ngx_memcache_process_client_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++ u_char *p;
++ minimum_len = sizeof ("CLIENT_ERROR") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "CLIENT_ERROR", sizeof ("CLIENT_ERROR") - 1))
++ {
++ return NGX_ERROR;
++ }
++
++ p = stream + sizeof ("CLIENT_ERROR") - 1;
++ *consumed = sizeof ("CLIENT_ERROR") - 1;
++ while ((p < stream + size) && (*p != LF))
++ {
++ ++p; ++*consumed;
++ }
++
++ if (*p != LF || *(p - 1) != CR)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (p < stream + size)
++ {
++ ++p;
++ ++*consumed;
++ }
++
++ ngx_str_t log_output;
++ log_output.data = stream;
++ log_output.len = *consumed - 2; //chomp the trailing CRLF
++
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached return error message: %V", &log_output);
++
++ wq->w.response_code = mcres_failure_input;
++ return NGX_OK;
++}
++
++static ngx_int_t ngx_memcache_process_server_error
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ size_t minimum_len;
++ u_char *p;
++ minimum_len = sizeof ("SERVER_ERROR") - 1 +
++ sizeof (CRLF) - 1;
++
++ *consumed = 0;
++
++ if (size < minimum_len)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (ngx_memcmp (stream, "SERVER_ERROR", sizeof ("SERVER_ERROR") - 1))
++ {
++ return NGX_ERROR;
++ }
++
++ p = stream + sizeof ("SERVER_ERROR") - 1;
++ *consumed = sizeof ("SERVER_ERROR") - 1;
++ while ((p < stream + size) && (*p != LF))
++ {
++ ++p; ++*consumed;
++ }
++
++ if (*p != LF || *(p - 1) != CR)
++ {
++ return NGX_AGAIN;
++ }
++
++ if (p < stream + size)
++ {
++ ++p;
++ ++*consumed;
++ }
++
++ ngx_str_t log_output;
++ log_output.data = stream;
++ log_output.len = *consumed - 2; //chomp the trailing CRLF
++
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached return error message: %V", &log_output);
++
++ wq->w.response_code = mcres_failure_again;
++ return NGX_OK;
++}
++
++/* consume a line of error message or unexcepted response,
++ * including ERROR, SERVER_ERROR and CLIENT_ERROR, as well as
++ * other unrecognized ones.
++ * Returns:
++ * NGX_OK: handle correctly and continue the next qork queue entry
++ * NGX_ERROR: server is bad, has to close connection and purge work
++ * queue
++ * NGX_AGAIN: recv more bytes to complete handling */
++static ngx_int_t ngx_memcache_process_error_line
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ u_char *p;
++ ngx_int_t rc = NGX_ERROR;
++
++ p = stream;
++ *consumed = 0;
++
++ if (*p == 'E') {
++ /* memcached return 'ERROR CRLF' */
++ rc = ngx_memcache_process_error (stream, size, wq, consumed);
++ } else if (*p == 'C' ) {
++ /* memcached return 'CLIENT_ERROR CRLF' */
++ rc = ngx_memcache_process_client_error (stream, size, wq, consumed);
++ } else if (*p == 'S') {
++ /* memcached return 'SERVER_ERROR CRLF'
++ * if it's a valid SERVER_ERROR, we still have
++ * to return NGX_ERROR to close the connection to current
++ * channel and purge the queue. Therefore, all the buffered bytes
++ * has to be chomped here.
++ */
++ rc = ngx_memcache_process_server_error (stream, size, wq, consumed);
++ if (rc == NGX_OK) {
++ /* chomp all the received raw bytes in buffer */
++ *consumed = size;
++ ngx_str_t log_output;
++ log_output.data = stream;
++ log_output.len = *consumed;
++ ngx_log_error (NGX_LOG_ERR, ngx_cycle->log, 0,
++ "memcached returns SERVER_ERROR, "
++ "chomp all %d bytes in buffer: %V",
++ *consumed, &log_output);
++ return NGX_ERROR;
++ }
++ }
++
++ if (rc == NGX_OK || rc == NGX_AGAIN) {
++ return rc;
++ } else {
++ /* the response is unrecognized,
++ * chomp all the received raw bytes in buffer */
++ *consumed = size;
++
++ ngx_str_t log_output;
++ log_output.data = stream;
++ log_output.len = size;
++ ngx_log_error (NGX_LOG_ERR, ngx_cycle->log, 0,
++ "memcached returns unrecognized response, "
++ "chomp all %d bytes in buffer: %V",
++ *consumed, &log_output);
++ return NGX_ERROR;
++ }
++}
++
++/* process response to any memcached command
++ with the advent of more supported operations, we need more context in
++ order to process the response to a previously submitted command
++ that is because responses to some memcached commands are identical
++
++ see docs/MEMCACHE-PROTOCOL for details
++ */
++ngx_int_t ngx_memcache_process_any_response
++ (u_char *stream, size_t size, mc_workqueue_t *wq, size_t *consumed)
++{
++ mcp_handler handler;
++ mc_request_code_t op;
++
++ *consumed = 0;
++ if (size == 0) { return NGX_AGAIN; }
++
++ op = wq->w.request_code;
++
++ switch (op)
++ {
++ case mcreq_add:
++ switch (*stream)
++ {
++ case 'S': /* STORED */
++ handler = ngx_memcache_process_add_ok;
++ break;
++ case 'N': /* NOT_STORED */
++ handler = ngx_memcache_process_add_failed;
++ break;
++ case 'C': /* CLIENT_ERROR msgERROR */
++ handler = ngx_memcache_process_add_invalid;
++ break;
++ default:
++ handler = ngx_memcache_process_error_line;
++ break;
++ }
++ break;
++ case mcreq_get:
++ switch (*stream)
++ {
++ case 'V': /* VALUE */
++ handler = ngx_memcache_process_get_ok;
++ break;
++ case 'E': /* END */
++ handler = ngx_memcache_process_get_failed;
++ break;
++ default:
++ handler = ngx_memcache_process_error_line;
++ break;
++ }
++ break;
++ case mcreq_delete:
++ switch (*stream)
++ {
++ case 'D': /* DELETED */
++ handler = ngx_memcache_process_delete_ok;
++ break;
++ case 'N': /* NOT_FOUND */
++ handler = ngx_memcache_process_delete_failed;
++ break;
++ default:
++ handler = ngx_memcache_process_error_line;
++ break;
++ }
++ break;
++ case mcreq_incr:
++ if (*stream == 'N') /* NOT_FOUND */ {
++ handler = ngx_memcache_process_incr_failed;
++ } else {
++ handler = ngx_memcache_process_incr_ok;
++ }
++ break;
++ case mcreq_decr:
++ if (*stream == 'N') /* NOT_FOUND */ {
++ handler = ngx_memcache_process_decr_failed;
++ } else {
++ handler = ngx_memcache_process_decr_ok;
++ }
++ break;
++ default:
++ handler = ngx_memcache_process_error_line;
++ break;
++ }
++
++ return handler (stream, size, wq, consumed);
++}
++
++static void ngx_memcache_dummy_write_handler (ngx_event_t *wev)
++{
++ ngx_log_debug0(NGX_LOG_DEBUG_CORE, wev->log, 0,
++ "dummy memcache write-event handler");
++}
++
++/* Generic memcache response event handler (see docs/MEMCACHE-PROTOCOL) */
++static void ngx_memcache_any_read_handler(ngx_event_t *rev)
++{
++ ngx_connection_t *c;
++ mc_context_t *ctx;
++ size_t available, consumed;
++ ssize_t n;
++ ngx_buf_t *readbuffer;
++ /* volatile */ mc_workqueue_t *wq_head;
++ mc_workqueue_t *wq_entry;
++ ngx_int_t rc;
++ ngx_flag_t reclaim;
++
++ c = rev->data;
++ ctx = c->data;
++ readbuffer = ctx->readbuffer;
++ wq_head = &ctx->wq_head;
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "memcached read event:%V", ctx->srvconn->name);
++
++ if (ctx->status == mcchan_bad) {
++ ngx_log_error (NGX_LOG_ERR, ngx_cycle->log, 0,
++ "ngx_memcache_any_read_handler should always be "
++ "callback when channel status is \"good\" or "
++ "\"reconnect\"");
++ }
++
++ /* nginx buffer
++
++ [[s]......[p]......[l].......[e]]
++
++ s = start
++ p = pos
++ l = last
++ e = end
++
++ */
++
++ /* TODO Why here is not locked ??? */
++ available = readbuffer->end - readbuffer->last;
++
++ if (available == 0)
++ {
++ /* no space in circular buffer to read the responses */
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "recycle circular buffer:%d bytes",
++ readbuffer->pos - readbuffer->start
++ );
++
++ memmove (readbuffer->start, readbuffer->pos,
++ readbuffer->last - readbuffer->pos);
++
++ readbuffer->last -= (readbuffer->pos - readbuffer->start);
++ readbuffer->pos = readbuffer->start;
++
++ available = readbuffer->end - readbuffer->last;
++
++ if (available == 0)
++ {
++ ngx_log_error (NGX_LOG_CRIT, ngx_cycle->log, 0,
++ "cannot recycle circular buffer");
++
++ /* TODO how to recover ? */
++ return;
++ }
++
++ /* note: recursive call has been removed */
++ }
++
++ if (ngx_log_tid && ctx->lock == ngx_log_tid) {
++ ngx_log_error (NGX_LOG_CRIT, ngx_cycle->log, 0,
++ "memcached loop");
++ return;
++ } else {
++ ngx_spinlock(&ctx->lock, ngx_log_tid, 40);
++ }
++
++ if (rev->timedout)
++ {
++ /* read timed out */
++ ngx_log_error (NGX_LOG_INFO, ngx_cycle->log, 0,
++ "memcached channel:%V timed out", ctx->srvconn->name);
++
++ ctx->status = mcchan_bad;
++ ngx_memcache_close_connection (ctx->srvconn);
++ ngx_memcache_purge_connection_workqueue (ctx, mcres_failure_again);
++ ngx_memcache_prepare_reconnection (ctx); // schedule reconnection event
++
++ ngx_unlock(&ctx->lock);
++ return;
++ }
++
++ n = ngx_recv (c, readbuffer->last, available);
++
++ if (rev->eof)
++ {
++ /* recv() zero bytes implies peer orderly shutdown (recv(2)) */
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached channel:%V orderly shutdown", ctx->srvconn->name);
++
++ /* channel was hitherto good, don't reconnect immediately, rather
++ wait for cxn_interval before reconnecting
++ */
++ ctx->status = mcchan_bad;
++ ngx_memcache_close_connection (ctx->srvconn);
++ ngx_memcache_purge_connection_workqueue (ctx, mcres_failure_again);
++ ngx_log_debug2 (NGX_LOG_DEBUG_MAIL, ngx_cycle->log, 0,
++ "bad memcached channel:%V, reconnect:%d ms",
++ ctx->srvconn->name, ctx->cxn_interval);
++ ngx_memcache_prepare_reconnection(ctx);
++
++ if (rev->timer_set) {
++ ngx_del_timer (rev);
++ }
++ ngx_unlock(&ctx->lock);
++ return;
++
++ }
++ else if (n == NGX_AGAIN)
++ {
++ /* EAGAIN should have resulted in a timeout which has been
++ handled previously
++ */
++ ngx_log_error (NGX_LOG_WARN, ngx_cycle->log, 0,
++ "ignoring *AGAIN on memcached channel %V", ctx->srvconn->name);
++
++ ngx_unlock(&ctx->lock);
++ return;
++
++ }
++ else if (n == NGX_ERROR)
++ {
++ /* After trying to reconnection, and then reach here, it indicates
++ * that the reconnection fails because target server is not available
++ */
++ if (ctx->status == mcchan_reconnect) {
++ ctx->status = mcchan_bad;
++ ngx_log_error (NGX_LOG_ERR, ngx_cycle->log, 0,
++ "reconnect to memcached channel %V fails", ctx->srvconn->name);
++ ngx_memcache_close_connection (ctx->srvconn);
++ ngx_memcache_prepare_reconnection(ctx);
++ ngx_unlock(&ctx->lock);
++ return;
++ }
++ /* There was an error reading from this socket */
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "memcached channel %V:error in recv, purging queue",
++ ctx->srvconn->name
++ );
++ ctx->status = mcchan_bad;
++ ngx_memcache_close_connection (ctx->srvconn);
++ ngx_memcache_purge_connection_workqueue (ctx, mcres_failure_again);
++ ngx_log_debug2 (NGX_LOG_DEBUG_MAIL, ngx_cycle->log, 0,
++ "bad memcached channel:%V, reconnect:%d ms",
++ ctx->srvconn->name, ctx->cxn_interval);
++ ngx_memcache_prepare_reconnection(ctx);
++ if (rev->timer_set) {
++ ngx_del_timer (rev);
++ }
++ ngx_unlock(&ctx->lock);
++ return;
++ }
++
++ readbuffer->last += n;
++
++ if (rev->timer_set) {
++ ngx_del_timer (rev);
++ }
++
++ if (ngx_memcache_wq_isempty (wq_head))
++ {
++ ctx->readbuffer->pos = ctx->readbuffer->last;
++ ngx_unlock(&ctx->lock);
++ ngx_log_error (NGX_LOG_WARN, ngx_cycle->log, 0,
++ "memcached channel %V:discard %d bytes(bad data), reset buffer",
++ ctx->srvconn->name, n);
++
++ return;
++ }
++
++ while ((!ngx_memcache_wq_isempty (wq_head)) && ((readbuffer->last - readbuffer->pos) > 0))
++ {
++ wq_entry = ngx_memcache_wq_front (wq_head);
++ consumed = 0;
++
++ rc = ngx_memcache_process_any_response (
++ readbuffer->pos,
++ readbuffer->last - readbuffer->pos,
++ wq_entry,
++ &consumed);
++
++ ngx_log_debug2 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "memcache proto-handler consumed:%d,rc:%d", consumed, rc
++ );
++
++ if (rc == NGX_OK)
++ {
++ readbuffer->pos += consumed;
++
++ /* correct response, so dequeue entry */
++ wq_entry = ngx_memcache_wq_dequeue (wq_head);
++
++ reclaim = wq_entry->reclaim;
++ ngx_memcache_callback (&wq_entry->w);
++ if (reclaim) { // free the memory if allocated from memcache request pool
++ ngx_destroy_pool(wq_entry->pool);
++ }
++ }
++ else if (rc == NGX_ERROR)
++ {
++ readbuffer->pos += consumed;
++
++ /* wrong response, purge all the entries (including the current one) */
++ ctx->status = mcchan_bad;
++ ngx_memcache_close_connection (ctx->srvconn);
++ ngx_memcache_purge_connection_workqueue
++ (ctx, mcres_failure_again);
++ ngx_memcache_prepare_reconnection(ctx);
++ }
++ else if (rc == NGX_AGAIN)
++ {
++ /* The response handler has indicated that there isn't sufficient
++ space to read the data, so we must move bytes over to the start
++ */
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "proto-handler got partial response, recycling [pos=%d]",
++ readbuffer->pos - readbuffer->start
++ );
++
++ memmove (readbuffer->start, readbuffer->pos,
++ readbuffer->last - readbuffer->pos);
++
++ readbuffer->last -= (readbuffer->pos - readbuffer->start);
++ readbuffer->pos = readbuffer->start;
++
++ ngx_unlock(&ctx->lock);
++ ngx_memcache_any_read_handler (rev);
++ ngx_spinlock(&ctx->lock, ngx_log_tid, 40);
++
++ break;
++ }
++ } /* while */
++
++ if (!ngx_memcache_wq_isempty (wq_head)) {
++ ngx_add_timer (rev, ctx->timeout);
++ }
++
++ ngx_unlock(&ctx->lock);
++}
++
++/* purge all outstanding connections from memcached work-queue */
++
++static void ngx_memcache_purge_connection_workqueue (mc_context_t *mcctx, mc_response_code_t res)
++{
++ mc_workqueue_t *head, *entry;
++ ngx_flag_t reclaim;
++ ngx_uint_t count;
++
++ head = &mcctx->wq_head;
++ if (ngx_memcache_wq_isempty(head))
++ return;
++
++ /*the mcchannel status of current context has to be set as
++ "mcchan_bad" before this function's invoke because the user
++ in the upper layer may retry connection. If status is
++ mcchan_good, the retry may incur an endless recursion */
++ if (mcctx->status == mcchan_good)
++ mcctx->status = mcchan_bad;
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
++ "memcached channel:%V, purging all entries",
++ mcctx->srvconn->name);
++
++ count = 0;
++ while (!ngx_memcache_wq_isempty(head)) {
++ entry = ngx_memcache_wq_dequeue (head);
++ reclaim = entry->reclaim;
++ entry->w.response_code = res;
++ ngx_memcache_callback(&entry->w);
++
++ if (reclaim) {
++ ngx_destroy_pool(entry->pool);
++ }
++ count++;
++ }
++
++ ngx_log_error (NGX_LOG_INFO, ngx_cycle->log, 0,
++ "memcached channel:%V, purged all %d entries",
++ mcctx->srvconn->name, count);
++
++ return;
++}
++
++static inline void ngx_memcache_callback (mc_work_t * w)
++{
++ if (w->ctx != NULL) { //call back only when not ignored
++ if (w->response_code == mcres_success) {
++ w->on_success (w);
++ } else {
++ w->on_failure (w);
++ }
++ }
++}
++
++static inline void ngx_memcache_close_connection (ngx_peer_connection_t * pc) {
++ ngx_close_connection (pc->connection);
++ pc->connection = NULL;
++}
++
++/* This is the routine for re-establishing a memcache connection that has
++ broken down for some reason. Usually, we *expect* this to happen in
++ cases when a memcache server crashes.
++
++ There are interesting effects observed on linux how a connected TCP
++ socket, which is marked in non-blocking mode (as nginx does), behaves
++ when the peer end goes down.
++
++ Firstly, when a connect() is invoked on a socket that's non-blocking,
++ the return code is EINPROGRESS even if the peer is up, or whether it's
++ down at the time (which is the reason why nginx's connection logic
++ in ngx_event_connect_peer explicitly checks for EINPROGRESS, and why we
++ explicitly ignore it)
++
++ Now, there are two very distinct fates of the subsequent send() and recv()
++ calls on the socket, in case something goes(or went) wrong with the peer:
++
++ (*) In the case when the peer was down at the time of connect(), then any
++ send() and recv() immediately fails with ECONNREFUSED.
++
++ (*) In the case when the peer went down at some point after the connect(),
++ then the first send() after this time *appears* to succeed, whereas
++ subsequent send()s fail with EPIPE (broken pipe). recv(), however, as
++ usual, succeeds, but with 0 bytes read
++
++ What this means for us, is that if a memcache connection goes sour because
++ of peer problems, then we can expect ngx_send()s to start failing with
++ EPIPE, whereas our ngx_recv(), which is indirectly invoked via the event
++ handling mechanism, will receive 0 bytes from ngx_recv()
++
++ In both cases, we need to purge the corresponding work queues ASAP, because
++ these may contain pending cache-get requests. A pending cache-get request
++ corresponds to a email connection freshly initiated by a client, and which
++ is requesting for upstream server information in order to initiate the proxy.
++ This is a high priority request, because the proxy initiation is waiting for
++ the result of this operation.
++
++ On the other hand, a pending cache-add request corresponds to a proxy session
++ already initiated (and possibly, already finished), which just needs to cache
++ the upstream info, which was previously retrieved from the http-auth servers.
++ In this situation, no client is really waiting for the add operation to
++ complete, but the memory still needs to be freed. Hence, it's lower priority.
++
++ So, purging a work queue is an action that is highest priority, and must be
++ triggered whenever anything goes amiss with the ngx_send() or ngx_recv().
++
++ On the other hand, we don't need to be very aggressive in trying to re-
++ establish the connection to a broken peer, as long as we mark that memcache
++ connection as `bad', so that our memcache server hashing algorithm is smart
++ enough to ignore the bad connection.
++
++ We can just maintain a counter, which will signify the number of times that
++ a connection could have been used, but was ignored because the server was
++ down. This counter will start at 0, and will be incremented whenever any
++ ngx_send() or ngx_recv() failed, or whenever the hashing algorithm
++ originally selected that channel, but selected another because the channel
++ was marked as `bad'.
++
++ A channel is `bad' when the counter is greater than zero, and it is good if
++ the counter is 0.
++
++ The counter is incremented by one (and the channel is marked bad) whenever
++ there is an error on ngx_send and/or ngx_recv, and it is also incremented by
++ one whenever the hashing algorithm elects the channel, but finds it bad.
++
++ The counter is reset to zero (and the channel marked good), after we re-
++ establish the connection. The re-establishment is attempted when the counter
++ reaches the config-file-defined threshold. A threshold of 1 indicates
++ aggressive re-connection, whereas larger values signify more lethargic
++ attempts at re-connection
++
++ (important note)
++ As an alternative to the channel ageing algorithm used above, we can use
++ a simple timeout to indicate how long nginx will do without a bad memcache
++ connection before attempting to reconnect. Therefore, all references to
++ memcache channel age are superseded by the `reconnect interval'
++
++ */
++static void ngx_memcache_reestablish_connection (mc_context_t *mcctx)
++{
++ ngx_int_t rc;
++
++ if (mcctx->srvconn->connection) {
++ ngx_memcache_close_connection (mcctx->srvconn);
++ }
++
++ ngx_memzero (mcctx->srvconn, sizeof (ngx_peer_connection_t));
++
++ mcctx->srvconn->sockaddr = mcctx->srvaddr->sockaddr;
++ mcctx->srvconn->socklen = mcctx->srvaddr->socklen;
++ mcctx->srvconn->name = &mcctx->srvaddr->name;
++ mcctx->srvconn->get = ngx_event_get_peer;
++ mcctx->srvconn->log = ngx_cycle->log;
++ mcctx->srvconn->log_error = NGX_ERROR_ERR;
++
++ rc = ngx_event_connect_peer (mcctx->srvconn);
++
++ if (mcctx->srvconn->connection)
++ {
++ mcctx->srvconn->connection->read->handler = ngx_memcache_any_read_handler;
++ mcctx->srvconn->connection->write->handler = ngx_memcache_dummy_write_handler;
++ mcctx->srvconn->connection->data = mcctx;
++ mcctx->srvconn->connection->log = ngx_cycle->log;
++ }
++
++ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
++ ngx_log_error (NGX_LOG_WARN, ngx_cycle->log, 0,
++ "cannot re-establish connection to memcached channel %V",
++ mcctx->srvconn->name);
++ mcctx->status = mcchan_bad;
++ } else {
++ /* In this case, the connection may return NGX_AGAIN (-2).
++ * If Then the read event is comming and recv return NGX_ERROR (-1),
++ * the reconnection fails. Otherwise, the reconnection is successful.
++ */
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "reconnect to memcached channel %V (rc: %d)",
++ mcctx->srvconn->name, rc);
++ mcctx->status = mcchan_reconnect;
++ setsockopt(mcctx->srvconn->connection->fd, SOL_SOCKET, SO_SNDBUF,
++ (void *) &mc_sndbuf_len, sizeof (mc_sndbuf_len));
++ }
++}
++
++/* mc_hash
++ *
++ * hash an opaque key onto an available memcached channel number
++ * if the memcached channel is currently bad, then fail-over to the next
++ * server in declarative order, until all channels are exhausted
++ *
++ * return MC_INVALID_HASH on failure
++ */
++static ngx_uint_t ngx_memcache_hash (u_char *key, size_t len)
++{
++ ngx_uint_t h, r, i;
++ mc_context_t *mcctx;
++ ngx_memcache_conf_t *mcf;
++
++ mcf = (ngx_memcache_conf_t*) ngx_get_conf(ngx_cycle->conf_ctx, ngx_memcache_module);
++
++ if (mcf->contexts.nelts == 0) {
++ r = MC_INVALID_HASH;
++ } else {
++ h = ngx_memcache_perl_hash (key, len);
++ r = h % mcf->contexts.nelts;
++ i = r;
++
++ do {
++ mcctx = ((mc_context_t *)mcf->contexts.elts) + i;
++
++ if (mcctx->status == mcchan_bad) {
++ i = (i + 1) % mcf->contexts.nelts;
++ }
++ } while ((mcctx->status == mcchan_bad) && (i != r));
++
++ if (mcctx->status == mcchan_bad)
++ r = MC_INVALID_HASH;
++ else
++ r = i;
++ }
++
++ return r;
++}
++
++static ngx_uint_t ngx_memcache_perl_hash (u_char *key, size_t len)
++{
++ size_t i;
++ ngx_uint_t h;
++ u_char *p;
++
++ p = key;
++ i = len;
++ h = 0;
++
++ while (i--)
++ {
++ h += *p++;
++ h += (h << 10);
++ h ^= (h >> 6);
++ }
++
++ h += (h << 3);
++ h ^= (h >> 11);
++ h += (h << 15);
++
++ return h;
++}
++
++static ngx_str_t ngx_sha256_hash (ngx_pool_t* p, u_char* key, size_t len)
++{
++ ngx_str_t hashed_key;
++ u_char * digest = ngx_pnalloc(p, SHA256_KEY_LENGTH);
++ SHA256(key, len, digest);
++ hashed_key.data = ngx_memcache_hexstr(digest, SHA256_KEY_LENGTH);
++ hashed_key.len = strlen((const char *)hashed_key.data);
++
++ return hashed_key;
++}
++
++static inline void
++ngx_memcache_prepare_reconnection (mc_context_t * mcctx) {
++ ngx_event_t * ev = mcctx->reconnect_ev;
++ ev->data = mcctx;
++
++ if (!ev->timer_set) {
++ ngx_add_timer(ev, mcctx->cxn_interval);
++ ngx_log_error (NGX_LOG_NOTICE, ngx_cycle->log, 0,
++ "memcached channel:%V down, reconnect after:%d ms",
++ mcctx->srvconn->name, mcctx->cxn_interval);
++ }
++}
++
++static void
++ngx_memcache_reconnection_handler (ngx_event_t * ev) {
++ mc_context_t * ctx = (mc_context_t *) ev->data;
++
++ if (ctx->status == mcchan_good) return;
++
++ ev->timedout = 0;
++ //ev->timer_set has been set to 0 before this handler are invoked.
++
++ /* unconditionally re-connect bad channel if this event is fired */
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, ngx_cycle->log, 0,
++ "reconnect to %V right now",
++ ctx->srvconn->name);
++
++ ngx_memcache_reestablish_connection (ctx);
++ ngx_unlock(&ctx->lock);
++
++ if (ctx->status == mcchan_bad) { //schedule next retry
++ ngx_memcache_prepare_reconnection (ctx);
++ }
++
++ return;
++}
++
++static u_char *
++ngx_memcache_hexstr(unsigned char *buf, int len)
++{
++ const char *set = "0123456789abcdef";
++ static u_char str[65], *tmp;
++ unsigned char *end;
++ if (len > 32)
++ len = 32;
++ end = buf + len;
++ tmp = &str[0];
++ while (buf < end)
++ {
++ *tmp++ = set[ (*buf) >> 4 ];
++ *tmp++ = set[ (*buf) & 0xF ];
++ buf ++;
++ }
++ *tmp = '\0';
++ return str;
++}
++
++/*
++ * generate memcache post data unit (pdu)
++ * the value's usage depends on the request command:
++ * 1. for "get", "delete", value is useless. you can set it to null
++ * 2. for "add", value is the value to be added
++ * 3. for "incr" or "decr", value is the number to increase or decrease. You
++ * have to ensure it's an integer.
++ *
++ * If the ttl is set to "-1", the memcache conf's ttl will be used; otherwise
++ * use the specified one. ttl is only effective for the "add" command.
++ */
++static ngx_str_t ngx_memcache_create_pdu(ngx_pool_t *pool, mc_work_t *w,
++ ngx_str_t key, ngx_str_t value, ngx_str_t ttl, ngx_log_t * log) {
++
++ ngx_str_t pdu;
++ size_t l, ll, len;
++ u_char *p;
++ ngx_memcache_conf_t *mcf;
++
++ len = 0, ll = 0;
++
++ /* check key validity */
++ if (key.len > NGX_MAX_KEY_LENGTH) {
++ ngx_str_t md5_key;
++ u_char * md5 = ngx_pnalloc(pool, MD5_DIGEST_LENGTH);
++ MD5(key.data, key.len, md5);
++ md5_key.data = ngx_memcache_hexstr(md5, MD5_DIGEST_LENGTH);
++ md5_key.len = strlen((const char *)md5_key.data);
++
++ ngx_log_debug2 (NGX_LOG_DEBUG_ZIMBRA, log, 0,
++ "the memcache request key %V is too long, use "
++ "its MD5 digest string %V as the key",
++ &key, &md5_key);
++
++ key = md5_key;
++ }
++
++ switch (w->request_code) {
++ case mcreq_get:
++ l = sizeof("get ") - 1 + key.len + sizeof(CRLF) - 1;
++ break;
++ case mcreq_add:
++ ll = 0;
++ len = value.len;
++ do {
++ len /= 10;
++ ll++;
++ } while (len != 0);
++
++ mcf = (ngx_memcache_conf_t*) ngx_get_conf(ngx_cycle->conf_ctx, ngx_memcache_module);
++
++ if (ngx_strncmp(ttl.data, "-1", 2) == 0) {
++ ttl = mcf->ttl_text;
++ }
++
++ l = sizeof("add ") - 1 + key.len + sizeof(" ") - 1 +
++ sizeof("0 ") - 1 + ttl.len + sizeof(" ") - 1 +
++ ll + sizeof(CRLF) - 1 + value.len + sizeof(CRLF) - 1;
++ break;
++ case mcreq_incr:
++ l = sizeof("incr ") - 1 + key.len + sizeof(" ") - 1 + value.len + sizeof(CRLF) - 1;
++ break;
++ case mcreq_decr:
++ l = sizeof("decr ") - 1 + key.len + sizeof(" ") - 1 + value.len + sizeof(CRLF) - 1;
++ break;
++ case mcreq_delete:
++ l = sizeof("delete ") - 1 + key.len + sizeof(CRLF) - 1;
++ break;
++ default:
++ ngx_log_error (NGX_LOG_ERR, log, 0,
++ "unkown command for the memcache key: %V", &key);
++ ngx_str_null(&pdu);
++ return pdu;
++ }
++
++ pdu.data = ngx_palloc(pool, l);
++
++ if (pdu.data == NULL) {
++ ngx_str_null(&pdu);
++ return pdu;
++ }
++
++ p = pdu.data;
++
++ switch (w->request_code) {
++ case mcreq_get:
++ ngx_sprintf(p, "get %V" CRLF, &key);
++ break;
++ case mcreq_add:
++ ngx_sprintf(p, "add %V 0 %V %d" CRLF "%V" CRLF, &key,
++ &ttl, value.len, &value);
++ break;
++ case mcreq_incr:
++ ngx_sprintf(p, "incr %V %V" CRLF, &key, &value);
++ break;
++ case mcreq_decr:
++ ngx_sprintf(p, "decr %V %V" CRLF, &key, &value);
++ break;
++ case mcreq_delete:
++ ngx_sprintf(p, "delete %V" CRLF, &key);
++ break;
++ default:
++ /* impossible to reach here */
++ return pdu;
++ }
++
++ pdu.len = l;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_ZIMBRA, log, 0,
++ "generate pdu %V", &pdu);
++
++ return pdu;
++}
+diff -urN nginx/src/core/ngx_memcache.h nginx/src/core/ngx_memcache.h
+--- nginx/src/core/ngx_memcache.h 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/core/ngx_memcache.h 2023-03-04 13:25:59.825361500 +0530
+@@ -0,0 +1,157 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#ifndef _NGX_MEMCACHE_H_INCLUDED_
++#define _NGX_MEMCACHE_H_INCLUDED_
++
++#include
++#include
++#include
++#include
++
++#define NGX_MEMCACHE_CONF 0x02000000
++#define NGX_MAX_KEY_LENGTH 250
++
++typedef struct {
++ ngx_pool_t *cpool; /* main pool where self resides */
++ ngx_log_t *log;
++ ngx_array_t contexts; /* mc_context_t[] */
++ ngx_array_t servers; /* ngx_addr_t*[] */
++ ngx_msec_t timeout;
++ ngx_msec_t reconnect;
++ ngx_msec_t ttl;
++ ngx_str_t ttl_text; /* in second, ttl / 1000 */
++ ngx_flag_t allow_unqualified;
++} ngx_memcache_conf_t;
++
++/* supported memcache request codes */
++typedef enum {
++ mcreq_noop,
++ mcreq_get,
++ mcreq_add,
++ mcreq_delete,
++ mcreq_incr,
++ mcreq_decr
++} mc_request_code_t;
++
++/* memcache response codes */
++typedef enum {
++ mcres_unknown,
++ mcres_success,
++ mcres_failure_normal, /* memcached server response with failure info,
++ such as NOT_FOUND, NOT_STORED, ... */
++ mcres_failure_input, /* failures triggered by the user input, such as
++ invalid key or command */
++ mcres_failure_again, /* failures that might be recovered by retry, such as
++ one of many memcached servers is down; or the
++ message replied can't be parsed correctly */
++ mcres_failure_unavailable /* failures of no memcache servers are available,
++ or other failures that make memcache service
++ unavailable */
++} mc_response_code_t;
++
++/* memcache channel status */
++typedef enum {
++ mcchan_good,
++ mcchan_bad,
++ mcchan_reconnect /* temp status in reconnection */
++} mc_channel_status_t;
++
++/* additional data returned by a memcache operation */
++typedef ngx_str_t mc_data_t;
++
++struct mc_work_s;
++/* prototype for sucess/failure handler */
++typedef void (*mc_chain_handler) (struct mc_work_s *w);
++
++/* workqueue entry representing an outstanding memcache request
++ */
++struct mc_work_s
++{
++ mc_request_code_t request_code; /* op request code */
++ mc_response_code_t response_code; /* op response status */
++ void *ctx; /* op context */
++ mc_data_t payload; /* op response payload */
++ mc_chain_handler on_success; /* success handler */
++ mc_chain_handler on_failure; /* failure handler */
++};
++
++typedef struct mc_work_s mc_work_t;
++
++
++/* a queue of memcache entries representing all outstanding memcache
++ requests for a particular connection to a memcache server
++ */
++
++typedef struct mc_workqueue_s mc_workqueue_t;
++
++struct mc_workqueue_s {
++ mc_work_t w; /* payload of the workqueue entry */
++ ngx_pool_t *pool; /* pool in which this node resides */
++ ngx_flag_t reclaim; /* reclaim the pool? (default:0) */
++ mc_workqueue_t *prev; /* previous node in the queue */
++ mc_workqueue_t *next; /* next node in the queue */
++};
++
++/* a `memcache context' data structure that completely represents the
++ state of a particular connection to a memcached server
++ */
++
++typedef struct {
++ ngx_buf_t *readbuffer; /* circular buffer for recv() */
++ mc_workqueue_t wq_head; /* head of outstanding requests */
++ ngx_addr_t *srvaddr; /* address of memcached server */
++ ngx_peer_connection_t *srvconn; /* active connection to server */
++ mc_channel_status_t status; /* connection status */
++ ngx_msec_t timeout; /* read/write timeout */
++ ngx_msec_t cxn_interval; /* timeout for reconnection */
++ ngx_event_t *reconnect_ev; /* event for reconnection */
++ ngx_atomic_t lock; /* concurrent access lock */
++} mc_context_t;
++
++/* Functions to manipulate the memcache work queue */
++mc_workqueue_t *ngx_memcache_wq_enqueue (mc_workqueue_t *head, mc_workqueue_t *wq);
++mc_workqueue_t *ngx_memcache_wq_dequeue (mc_workqueue_t *head);
++
++/* Post a memcache operation request onto an available channel */
++void ngx_memcache_post (
++ mc_work_t *w,
++ ngx_str_t key,
++ ngx_str_t value,
++ ngx_pool_t *p,
++ ngx_log_t *l
++ );
++
++/*
++ * Post a memcache operation request onto an available channel
++ * custom ttl. (Only "add" is supported)
++ */
++void ngx_memcache_post_with_ttl (
++ mc_work_t *w,
++ ngx_str_t key,
++ ngx_str_t value,
++ ngx_str_t ttl,
++ ngx_pool_t *p,
++ ngx_log_t *l
++ );
++
++extern ngx_str_t NGX_EMPTY_STR; /* for dummy value */
++
++/* Ignore a work entry in the queue whose ctx is equal to
++ * the specified one.
++ */
++void ngx_memcache_ignore_work_by_ctx (void * ctx);
++
++#endif
+diff -urN nginx/src/core/ngx_palloc.c nginx/src/core/ngx_palloc.c
+--- nginx/src/core/ngx_palloc.c 2023-03-07 16:26:44.281516600 +0530
++++ nginx/src/core/ngx_palloc.c 2023-09-14 18:47:11.690205600 +0530
+@@ -70,9 +70,10 @@
+ }
+
+ for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
+- ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
+- "free: %p, unused: %uz", p, p->d.end - p->d.last);
+-
++// Zimbra customizations start here (Jira Tickets: )
++// ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
++// "free: %p, unused: %uz", p, p->d.end - p->d.last);
++// Zimbra customizations end here
+ if (n == NULL) {
+ break;
+ }
+diff -urN nginx/src/core/ngx_string.c nginx/src/core/ngx_string.c
+--- nginx/src/core/ngx_string.c 2023-07-23 13:21:26.899184500 +0530
++++ nginx/src/core/ngx_string.c 2023-09-14 18:47:11.725602200 +0530
+@@ -85,8 +85,26 @@
+
+ return dst;
+ }
++// Zimbra customizations start here (Jira Tickets: )
++ngx_str_t *
++ngx_pstrcpy(ngx_pool_t *pool, ngx_str_t *src) {
++ ngx_str_t * dst;
+
++ dst = ngx_pnalloc(pool, sizeof(ngx_str_t));
++ if (dst == NULL) {
++ return NULL;
++ }
+
++ dst->data = ngx_pnalloc(pool, src->len);
++ if (dst->data == NULL) {
++ return NULL;
++ }
++
++ ngx_memcpy(dst->data, src->data, src->len);
++ dst->len = src->len;
++ return dst;
++}
++// Zimbra customizations end here
+ /*
+ * supported formats:
+ * %[0][width][x][X]O off_t
+diff -urN nginx/src/core/ngx_string.h nginx/src/core/ngx_string.h
+--- nginx/src/core/ngx_string.h 2023-07-23 13:21:26.903174100 +0530
++++ nginx/src/core/ngx_string.h 2023-10-01 22:17:25.661131500 +0530
+@@ -150,6 +150,9 @@
+
+ u_char *ngx_cpystrn(u_char *dst, u_char *src, size_t n);
+ u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src);
++// Zimbra customizations start here (Jira Tickets: )
++ngx_str_t *ngx_pstrcpy(ngx_pool_t *pool, ngx_str_t *src);
++// Zimbra customizations end here
+ u_char * ngx_cdecl ngx_sprintf(u_char *buf, const char *fmt, ...);
+ u_char * ngx_cdecl ngx_snprintf(u_char *buf, size_t max, const char *fmt, ...);
+ u_char * ngx_cdecl ngx_slprintf(u_char *buf, u_char *last, const char *fmt,
+diff -urN nginx/src/core/ngx_zm_lookup.c nginx/src/core/ngx_zm_lookup.c
+--- nginx/src/core/ngx_zm_lookup.c 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/core/ngx_zm_lookup.c 2023-03-04 13:25:59.839357600 +0530
+@@ -0,0 +1,2282 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#include
++#include
++
++static char * ngx_zm_lookup_handlers(ngx_conf_t *cf, ngx_command_t *cmd,
++ void *conf);
++
++/* lookup from memcache */
++static void ngx_zm_lookup_account_from_cache(ngx_zm_lookup_ctx_t *ctx);
++static void ngx_zm_lookup_account_from_cache_success_handler(mc_work_t *work);
++static void ngx_zm_lookup_account_from_cache_failure_handler(mc_work_t *work);
++static void ngx_zm_lookup_route_from_cache(ngx_zm_lookup_ctx_t *ctx);
++static void ngx_zm_lookup_route_from_cache_success_handler(mc_work_t *work);
++static void ngx_zm_lookup_route_from_cache_failure_handler(mc_work_t *work);
++static void ngx_zm_lookup_cache_alias(ngx_zm_lookup_ctx_t *ctx,
++ ngx_str_t alias, ngx_str_t account_name);
++static void ngx_zm_lookup_cache_route(ngx_zm_lookup_ctx_t *ctx,
++ ngx_str_t user, ngx_str_t route);
++static void ngx_zm_lookup_cache_dummy_handler(mc_work_t *work);
++static void ngx_zm_lookup_delete_cache_handler(mc_work_t *work);
++
++/* memcache key creation */
++static ngx_str_t
++ngx_zm_lookup_get_user_route_key(ngx_pool_t *pool, ngx_log_t *log,
++ ngx_str_t proto, ngx_str_t account_name, ngx_str_t client_ip);
++static ngx_str_t
++ngx_zm_lookup_get_id_route_key(ngx_pool_t *pool, ngx_log_t *log, ngx_str_t proto,
++ ngx_str_t id, ngx_http_zmauth_t type);
++
++/* lookup from route lookup servlet */
++static void ngx_zm_lookup_dummy_handler(ngx_event_t *ev);
++static void ngx_zm_lookup_connect_handler(ngx_event_t *ev);
++static void ngx_zm_lookup_connect(ngx_zm_lookup_ctx_t * ctx);
++static ngx_int_t ngx_zm_lookup_parse_response_headers(ngx_zm_lookup_ctx_t * ctx);
++static ngx_int_t ngx_zm_lookup_create_request(ngx_zm_lookup_ctx_t *ctx);
++static ngx_str_t ngx_zm_lookup_get_local_socket_addr_text (ngx_pool_t *pool,
++ ngx_socket_t s);
++static void ngx_zm_lookup_process_response(ngx_zm_lookup_ctx_t *ctx);
++static void ngx_zm_lookup_process_response_headers(ngx_zm_lookup_ctx_t *ctx);
++static void ngx_zm_lookup_send_request_handler(ngx_event_t *wev);
++static void ngx_zm_lookup_recv_response_handler(ngx_event_t *rev);
++static ngx_int_t ngx_zm_lookup_retrieve_route(ngx_pool_t * pool,
++ ngx_str_t * addr_text, ngx_str_t * port_text, ngx_addr_t * route);
++static void ngx_zm_lookup_close_connection(ngx_zm_lookup_ctx_t * ctx);
++
++/* module configuration */
++static void * ngx_zm_lookup_create_conf(ngx_cycle_t *cycle);
++static char * ngx_zm_lookup_init_conf(ngx_cycle_t *cycle, void *conf);
++static char *ngx_zm_lookup_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
++
++/* utility */
++static const u_char * ngx_zm_strchr (ngx_str_t str, int chr);
++
++static ngx_command_t ngx_zm_lookup_commands[] =
++{
++ { ngx_string("zm_lookup"),
++ NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS,
++ ngx_zm_lookup_block,
++ 0,
++ 0,
++ NULL },
++
++ { ngx_string("zm_lookup_handlers"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_1MORE,
++ ngx_zm_lookup_handlers,
++ 0,
++ 0,
++ NULL },
++
++ { ngx_string("zm_lookup_handler_retry_interval"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, retry_interval),
++ NULL },
++
++ { ngx_string("zm_lookup_timeout"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, timeout),
++ NULL },
++
++ { ngx_string("zm_lookup_buffer_size"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_size_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, buffer_size),
++ NULL },
++
++ { ngx_string("zm_lookup_master_auth_username"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, master_auth_username),
++ NULL },
++
++ { ngx_string("zm_lookup_master_auth_password"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, master_auth_password),
++ NULL },
++
++ { ngx_string("zm_lookup_caching"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, caching),
++ NULL },
++
++ { ngx_string("zm_lookup_allow_unqualified"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, allow_unqualified),
++ NULL },
++
++ { ngx_string("zm_prefix_url"),
++ NGX_ZM_LOOKUP_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ 0,
++ offsetof(ngx_zm_lookup_conf_t, url),
++ NULL },
++
++ ngx_null_command
++};
++
++static ngx_core_module_t ngx_zm_lookup_module_ctx =
++{
++ ngx_string("ngx_zm_lookup"),
++ ngx_zm_lookup_create_conf,
++ ngx_zm_lookup_init_conf
++};
++
++/*static const u_char * LOGIN_FAILED = (u_char *)"login failed";*/
++
++static const ngx_str_t ZM_PROTO[] = {
++ ngx_string("unknown"),
++ ngx_string("http"),
++ ngx_string("httpssl"),
++ ngx_string("pop3"),
++ ngx_string("pop3ssl"),
++ ngx_string("imap"),
++ ngx_string("imapssl")
++};
++
++static const ngx_str_t ZM_AUTHMETH[] = {
++ ngx_string("username"),
++ ngx_string("gssapi"),
++ ngx_string("zimbraId"),
++ ngx_string("certauth")
++};
++
++static const ngx_str_t ERRMSG[] = {
++ ngx_string("success"),
++ ngx_string("mem alloc err"),
++ ngx_string("error occurs when writing lookup request to handler"),
++ ngx_string("error occurs when reading lookup response from handler"),
++ ngx_string("timeout occurs when writing lookup request to handler"),
++ ngx_string("timeout occurs when reading lookup response from handler"),
++ ngx_string("no valid lookup handlers"),
++ ngx_string("invalid route is returned"),
++ ngx_string("LOGIN failed"),
++ ngx_string("invalid response from lookup handler"),
++ ngx_string("client connection is closed"),
++ ngx_string("dummy")
++};
++
++/*There is no need to send real password for now */
++static const ngx_str_t
++ngx_zm_lookup_password_placeholder = ngx_string("_password_");
++
++static const ngx_str_t
++ngx_zm_prefix_url = ngx_string("/");
++
++ngx_module_t ngx_zm_lookup_module =
++{
++ NGX_MODULE_V1,
++ &ngx_zm_lookup_module_ctx, /* module context */
++ ngx_zm_lookup_commands, /* module directives */
++ NGX_CORE_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
++};
++
++static char *ngx_zm_lookup_block(ngx_conf_t *cf, ngx_command_t *cmd,
++ void *conf)
++{
++ ngx_conf_t ocf;
++ char *rc;
++
++ ocf = *cf;
++
++ cf->ctx = cf->cycle->conf_ctx;
++ cf->module_type = NGX_CORE_MODULE;
++ cf->cmd_type = NGX_ZM_LOOKUP_CONF;
++
++ rc = ngx_conf_parse(cf, NULL);
++
++ *cf = ocf;
++
++ return rc;
++}
++
++static void *
++ngx_zm_lookup_create_conf(ngx_cycle_t *cycle)
++{
++ ngx_zm_lookup_conf_t *zlcf;
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++
++ log = cycle->log;
++ pool = ngx_create_pool (8 * ngx_pagesize, cycle->log);
++
++ zlcf = ngx_pcalloc (pool, sizeof(ngx_zm_lookup_conf_t));
++ if (zlcf == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ zlcf->pool = pool;
++ zlcf->log = log;
++
++#if (NGX_SSL)
++
++ ngx_pool_cleanup_t *cln;
++ zlcf->ssl = ngx_pcalloc(pool, sizeof(ngx_ssl_t));
++
++ if (zlcf->ssl == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ zlcf->ssl->log = log;
++
++ // don't support SSLv2 anymore
++ if (ngx_ssl_create(zlcf->ssl, ~(NGX_SSL_SSLv2|NGX_SSL_SSLv3), NULL)
++ != NGX_OK) {
++ return NGX_CONF_ERROR;
++ }
++
++ cln = ngx_pool_cleanup_add(zlcf->pool, 0);
++ if (cln == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ cln->handler = ngx_ssl_cleanup_ctx;
++ cln->data = zlcf->ssl;
++
++#endif
++
++ if(ngx_array_init (&zlcf->handlers, zlcf->pool, 4,
++ sizeof(ngx_zm_lookup_handler_t)) != NGX_OK) {
++ return NGX_CONF_ERROR;
++ }
++
++ zlcf->retry_interval = NGX_CONF_UNSET;
++ zlcf->buffer_size = NGX_CONF_UNSET_SIZE;
++ zlcf->timeout = NGX_CONF_UNSET;
++ zlcf->caching = NGX_CONF_UNSET;
++ zlcf->allow_unqualified = NGX_CONF_UNSET;
++ ngx_str_null(&zlcf->master_auth_username);
++ ngx_str_null(&zlcf->master_auth_password);
++ ngx_str_null(&zlcf->url);
++ ngx_log_error(NGX_LOG_DEBUG_ZIMBRA, cycle->log, 0,
++ "zm lookup configuration created");
++ return zlcf;
++}
++
++static char *
++ngx_zm_lookup_init_conf(ngx_cycle_t *cycle, void *conf)
++{
++ ngx_zm_lookup_conf_t *zlcf = conf;
++
++ // set default value of timeout
++ if (zlcf->retry_interval == NGX_CONF_UNSET_UINT) {
++ zlcf->retry_interval = 60000;
++ }
++
++ if (zlcf->caching == NGX_CONF_UNSET) {
++ zlcf->caching = 1;
++ }
++
++ if (zlcf->allow_unqualified == NGX_CONF_UNSET) {
++ zlcf->allow_unqualified = 0;
++ }
++
++ if (zlcf->buffer_size == NGX_CONF_UNSET_SIZE) {
++ zlcf->buffer_size = 1024;
++ }
++
++ if (zlcf->timeout == NGX_CONF_UNSET_UINT) {
++ zlcf->timeout = 15000;
++ }
++
++ if (zlcf->master_auth_username.data == NULL) {
++ zlcf->master_auth_username = ngx_zm_lookup_password_placeholder;
++ }
++
++ if (zlcf->master_auth_password.data == NULL) {
++ zlcf->master_auth_password = ngx_zm_lookup_password_placeholder;
++ }
++
++ if (zlcf->url.data == NULL) {
++ zlcf->url = ngx_zm_prefix_url;
++ }
++
++ ngx_log_error(NGX_LOG_DEBUG_ZIMBRA,cycle->log, 0,
++ "zm lookup - initialized config defaults");
++ return NGX_CONF_OK;
++}
++
++static char *
++ngx_zm_lookup_handlers(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ ngx_zm_lookup_conf_t *zlcf = conf;
++ ngx_zm_lookup_handler_t *handler;
++ ngx_url_t u;
++ ngx_uint_t i;
++ ngx_uint_t add;
++
++ /* parse each url specified against directive "zm_lookup_handlers" */
++ for(i = 1; i < cf->args->nelts; ++i)
++ {
++ ngx_memzero(&u, sizeof(ngx_url_t));
++ u.url = ((ngx_str_t*)cf->args->elts)[i];
++ u.default_port = 7072;
++ u.uri_part = 1;
++ add = 0;
++
++ if (ngx_strncasecmp(u.url.data, (u_char *) "http://", 7) == 0) {
++ add = 7;
++ } else if (ngx_strncasecmp(u.url.data, (u_char *) "https://", 8) == 0) {
++#if (NGX_SSL)
++ add = 8;
++#else
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
++ "https protocol requires SSL support");
++ return NGX_CONF_ERROR;
++#endif
++ } else {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid URL prefix");
++ return NGX_CONF_ERROR;
++ }
++ u.url.len -= add;
++ u.url.data += add;
++
++ if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
++ if (u.err) {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
++ "%s in zm lookup handlers \"%V\"", u.err, &u.url);
++ }
++ return NGX_CONF_ERROR;
++ }
++
++ handler = ngx_array_push(&zlcf->handlers);
++ if (handler == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ handler->peer = u.addrs;
++ handler->host = u.host;
++ handler->uri = u.uri;
++ handler->failure_time = 0;
++ if (add == 7) {
++ handler->ssl = 0;
++ } else if (add == 8) {
++ handler->ssl = 1;
++ }
++
++ ngx_conf_log_error(NGX_LOG_INFO, cf, 0,
++ "add zimbra route lookup handler %V", &u.url);
++ }
++
++ if (zlcf->handlers.nelts == 0) {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
++ "zero valid zmauth route handlers");
++ return NGX_CONF_ERROR;
++ }
++
++ return NGX_CONF_OK;
++}
++
++static ngx_int_t
++ngx_zm_lookup_elect_handler(ngx_zm_lookup_ctx_t *ctx, ngx_zm_lookup_conf_t *zlcf)
++{
++ ngx_zm_lookup_handler_t * handler;
++ time_t now = time(NULL);
++
++ if (zlcf->handlers.nelts == 0) {
++ return NGX_ERROR;
++ }
++ /* so the loop below can start from zlcf->handler_index rather than
++ zlcf->handler_index + 1
++ */
++ ctx->handler_index = zlcf->handler_index - 1;
++ zlcf->handler_index = (zlcf->handler_index + 1) % zlcf->handlers.nelts;
++ do {
++ if (ctx->tries >= zlcf->handlers.nelts) {
++ ngx_log_error (NGX_LOG_ERR, ctx->log, 0,
++ "All nginx lookup handlers are unavailable");
++ return NGX_ERROR;
++
++ } else {
++ ctx->handler_index = (ctx->handler_index + 1) % zlcf->handlers.nelts;
++ ctx->tries ++;
++
++ handler = ((ngx_zm_lookup_handler_t*)zlcf->handlers.elts) + ctx->handler_index;
++ if (handler->failure_time != 0) {
++ if((now < handler->failure_time ||
++ (now - handler->failure_time) < (time_t)(zlcf->retry_interval / 1000))) {
++ continue;
++ } else {
++ handler->failure_time = 0; // mark it as available and try to connect it
++ }
++ }
++ ctx->handler = handler;
++ break;
++ }
++ } while (1);
++
++ return NGX_OK;
++}
++
++/* portal API */
++void
++ngx_zm_lookup(ngx_zm_lookup_work_t * work)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++ ngx_zm_lookup_conf_t *zlcf;
++
++ zlcf = (ngx_zm_lookup_conf_t *)
++ ngx_get_conf (ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ ctx = ngx_pcalloc(work->pool, sizeof(ngx_zm_lookup_ctx_t));
++ if (ctx == NULL) {
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++ ctx->pool = work->pool;
++ ctx->log = work->log;
++ ctx->work = work;
++ ctx->tries = 0;
++ ctx->handler = NULL;
++ ctx->state = 0;
++ work->ctx = ctx;
++
++ if (ctx->work->auth_method == ZM_AUTHMETH_GSSAPI ||
++ ctx->work->auth_method == ZM_AUTHMETH_CERTAUTH) {
++ /* These methods should never be cached */
++ ngx_zm_lookup_connect(ctx);
++ return;
++ }
++
++ if (zlcf->caching) {
++
++ if (work->auth_method == ZM_AUTHMETH_ZIMBRAID) {
++ ngx_zm_lookup_route_from_cache(ctx);
++ return;
++ }
++
++ if (work->alias_check_stat == ZM_ALIAS_NOT_CHECKED) {
++ ngx_zm_lookup_account_from_cache(ctx);
++ } else {
++ ngx_zm_lookup_route_from_cache(ctx);
++ }
++
++ } else {
++ ngx_zm_lookup_connect(ctx);
++ }
++}
++
++/*
++ * Consider current user name is an alias and lookup its
++ * corresponding account name, such 'john' --> 'john@test.com'
++ */
++static void
++ngx_zm_lookup_account_from_cache (ngx_zm_lookup_ctx_t * ctx)
++{
++ ngx_zm_lookup_work_t *work;
++ ngx_str_t key;
++ ngx_log_t *log;
++ mc_work_t mc;
++ ngx_pool_t *pool;
++
++ log = ctx->log;
++ pool = ctx->pool;
++ work = ctx->work;
++
++ if (work->alias_key.len > 0) {
++ key = work->alias_key;
++ } else {
++ if (IS_PROTO_WEB(work->protocol)) {
++ key = ngx_zm_lookup_get_http_alias_key
++ (pool, log, work->username, work->virtual_host);
++ } else {
++ key = ngx_zm_lookup_get_mail_alias_key
++ (pool, log, work->username, work->connection->addr_text);
++ }
++
++ if (key.len == 0) { /* NOMEM */
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++
++ work->alias_key = key;
++ }
++
++ mc.ctx = ctx;
++ mc.request_code = mcreq_get;
++ mc.response_code = mcres_unknown;
++ mc.on_success = ngx_zm_lookup_account_from_cache_success_handler;
++ mc.on_failure = ngx_zm_lookup_account_from_cache_failure_handler;
++
++ ctx->wait_memcache = 1;
++ ngx_memcache_post(&mc, key, NGX_EMPTY_STR,/* pool */ NULL, log);
++}
++
++static void
++ngx_zm_lookup_account_from_cache_success_handler (mc_work_t *mc)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++ ngx_str_t account_name;
++
++ ctx = (ngx_zm_lookup_ctx_t *)mc->ctx;
++ ctx->wait_memcache = 0;
++
++ account_name.data = ngx_pstrdup(ctx->pool, &mc->payload);
++ if (account_name.data != NULL)
++ {
++ account_name.len = mc->payload.len;
++ ctx->work->account_name = account_name;
++
++ ngx_log_debug2 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: user:%V aliased to account name:%V",
++ &ctx->work->username, &account_name
++ );
++
++ ctx->work->alias_check_stat = ZM_ALIAS_FOUND;
++ ngx_zm_lookup_route_from_cache(ctx);
++ }
++}
++
++static void
++ngx_zm_lookup_account_from_cache_failure_handler(mc_work_t *work)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++
++ ctx = (ngx_zm_lookup_ctx_t *)work->ctx;
++ ctx->wait_memcache = 0;
++ ctx->work->alias_check_stat = ZM_ALIAS_NOT_FOUND;
++ /* If account name is not found, take username as the account name */
++ ctx->work->account_name = ctx->work->username;
++
++ ngx_zm_lookup_route_from_cache(ctx);
++}
++
++/* lookup route by zimbra id/account name in memcache */
++static void
++ngx_zm_lookup_route_from_cache (ngx_zm_lookup_ctx_t *ctx)
++{
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++ ngx_str_t key;
++ mc_work_t mc;
++ ngx_zm_lookup_work_t *work;
++ ngx_zm_lookup_conf_t *zlcf;
++ ngx_str_t username;
++
++ zlcf = (ngx_zm_lookup_conf_t *)
++ ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ pool = ctx->pool;
++ log = ctx->log;
++ work = ctx->work;
++
++ if (work->auth_method == ZM_AUTHMETH_ZIMBRAID) {
++ key = ngx_zm_lookup_get_id_route_key(
++ pool, log, ZM_PROTO[work->protocol], work->username,
++ work->type);
++ } else {
++ if (work->alias_check_stat == ZM_ALIAS_FOUND) {
++ username = work->account_name;
++ } else {
++ username = work->username;
++ }
++
++ if (zlcf->allow_unqualified == 0 && !is_login_qualified(username)) {
++ key = ngx_zm_lookup_get_user_route_key(pool, log, ZM_PROTO[work->protocol],
++ username, work->connection->addr_text);
++ } else {
++ key = ngx_zm_lookup_get_user_route_key(pool, log, ZM_PROTO[work->protocol],
++ username, NGX_EMPTY_STR);
++ }
++ }
++
++ if (key.len == 0) { /* NOMEM */
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++
++ ctx->work->route_key = key;
++
++ mc.ctx = ctx;
++ mc.request_code = mcreq_get;
++ mc.response_code = mcres_unknown;
++ mc.on_success = ngx_zm_lookup_route_from_cache_success_handler;
++ mc.on_failure = ngx_zm_lookup_route_from_cache_failure_handler;
++
++ ctx->wait_memcache = 1;
++ ngx_memcache_post(&mc, key, NGX_EMPTY_STR,/* pool */ NULL, log);
++}
++
++static void
++ngx_zm_lookup_route_from_cache_success_handler (mc_work_t *mc)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++ ngx_str_t route_text;
++ ngx_url_t u;
++
++ ctx = (ngx_zm_lookup_ctx_t *)mc->ctx;
++ ctx->wait_memcache = 0;
++
++ route_text.data = ngx_pstrdup(ctx->pool, &mc->payload);
++
++ if (route_text.data == NULL) {
++ ctx->work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ ctx->work->on_failure(ctx->work);
++ return;
++ } else {
++ route_text.len = mc->payload.len;
++
++ ngx_log_debug2 (NGX_LOG_DEBUG_HTTP, ctx->log,0,
++ "zm lookup: fetch cached route:%V for user:%V",
++ &route_text, &ctx->work->username
++ );
++
++ ngx_memzero(&u, sizeof(u));
++ u.url = route_text;
++ u.listen = 1;
++
++ if (ngx_parse_url(ctx->pool, &u) != NGX_OK) {
++ ctx->work->result = ZM_LOOKUP_INVALID_ROUTE;
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++
++ ctx->work->route = ngx_palloc(ctx->pool, sizeof(ngx_addr_t));
++ if (ctx->work->route == NULL) {
++ ctx->work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ ctx->work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++ ctx->work->route->name = route_text;
++ ctx->work->route->socklen = u.socklen;
++ ctx->work->route->sockaddr = ngx_palloc(ctx->pool, u.socklen);
++ if(ctx->work->route->sockaddr == NULL) {
++ ctx->work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ ctx->work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++ ngx_memcpy(ctx->work->route->sockaddr, &u.sockaddr, u.socklen);
++ ctx->work->result = ZM_LOOKUP_SUCCESS;
++ ctx->work->on_success(ctx->work);
++ return;
++ }
++}
++
++static void
++ngx_zm_lookup_route_from_cache_failure_handler(mc_work_t *mc)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++ ctx = (ngx_zm_lookup_ctx_t *) mc->ctx;
++ ctx->wait_memcache = 0;
++
++ /* if alias-->account lookup succeeds, but route lookup fails,
++ * ignore the found account. Still use what user initial input
++ * do the route lookup. (bug 49283)
++ */
++ if (ctx->work->alias_check_stat == ZM_ALIAS_FOUND) {
++ ctx->work->alias_check_stat = ZM_ALIAS_IGNORED;
++ }
++
++ ngx_zm_lookup_connect (ctx);
++}
++
++#if (NGX_SSL)
++
++static void
++ngx_zm_lookup_ssl_handshake(ngx_connection_t *c)
++{
++ ngx_zm_lookup_ctx_t *ctx = c->data;
++
++ if (c->ssl->handshaked) {
++ c->read->handler = ngx_zm_lookup_dummy_handler;
++ c->write->handler = ngx_zm_lookup_connect_handler;
++ ngx_reusable_connection(c, 1);
++ c->write->handler(c->write);
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_handshake set fd:%d", c->fd);
++ } else {
++ /* when handshake fails, we should close the session */
++ ngx_zm_lookup_close_connection(ctx);
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_handshake unset fd:%d", c->fd);
++ }
++}
++
++static ngx_flag_t
++ngx_zm_lookup_ssl_init_connection(ngx_ssl_t* ssl, ngx_connection_t *c)
++{
++ ngx_int_t rc;
++ ngx_int_t marker = 20;
++ ngx_zm_lookup_ctx_t *ctx = c->data;
++
++ if (ngx_ssl_create_connection(ssl, c,
++ NGX_SSL_BUFFER|NGX_SSL_CLIENT)
++ != NGX_OK)
++ {
++ ngx_zm_lookup_close_connection(ctx);
++ return;
++ }
++
++ c->log->action = "SSL handshaking to lookup handler";
++
++ do {
++ rc = ngx_ssl_handshake(c);
++ if(rc == NGX_AGAIN)
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_ZIMBRA, c->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_init_connection ngx_ssl_handshake returned NGX_AGAIN");
++ ngx_msleep(5);
++ }
++ else if (rc == NGX_ERROR)
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_ZIMBRA, c->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_init_connection ssl event failed with NGX_ERROR");
++ ngx_zm_lookup_ssl_handshake(c);
++ return ZM_LOOKUP_SSL_EVENT_FAILED;
++ }
++ }while (rc == NGX_AGAIN && --marker > 0);
++
++ if( 0 == marker )
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_ZIMBRA, c->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_init_connection marker reached");
++ ngx_zm_lookup_ssl_handshake(c);
++ return ZM_LOOKUP_SSL_EVENT_FAILED;
++ }
++
++ ngx_log_debug0 (NGX_LOG_DEBUG_ZIMBRA, c->log, 0,
++ "zm lookup: ngx_zm_lookup_ssl_init_connection before call to ngx_zm_lookup_ssl_handshake");
++ ngx_zm_lookup_ssl_handshake(c);
++ return ZM_LOOKUP_SSL_EVENT_SUCCESS;
++}
++
++#endif
++
++static void
++ngx_zm_lookup_connect (ngx_zm_lookup_ctx_t * ctx)
++{
++ ngx_zm_lookup_conf_t *zlcf;
++ ngx_zm_lookup_handler_t *handler;
++ ngx_int_t rc;
++
++ zlcf = (ngx_zm_lookup_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: elected route handler #%d", ctx->handler_index);
++ if (ngx_zm_lookup_elect_handler(ctx, zlcf) != NGX_OK) {
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
++ "zm lookup: all lookup handlers exhausted");
++ ctx->work->result = ZM_LOOKUP_NO_VALID_HANDLER;
++ ctx->work->err = ERRMSG[ZM_LOOKUP_NO_VALID_HANDLER];
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++
++ handler = ctx->handler;
++ ctx->peer.sockaddr = handler->peer->sockaddr;
++ ctx->peer.socklen = handler->peer->socklen;
++ ctx->peer.name = &handler->peer->name;
++ ctx->peer.get = ngx_event_get_peer;
++ ctx->peer.log = ctx->log;
++ ctx->peer.log_error = NGX_ERROR_ERR;
++
++ rc = ngx_event_connect_peer(&ctx->peer);
++
++ if (rc == NGX_ERROR || rc == NGX_BUSY || rc == NGX_DECLINED) {
++ ngx_log_debug2(NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: connect to lookup handler failed, host:%V, uri:%V",
++ ctx->peer.name, &handler->uri);
++ ngx_zm_lookup_close_connection(ctx);
++
++ /* try again */
++ ngx_log_error(NGX_LOG_WARN, ctx->log, 0, "zm lookup: "
++ "connect lookup handle error, fail over to the next one");
++ ngx_zm_lookup_connect(ctx);
++ return;
++
++ }
++
++ ctx->peer.connection->data = ctx;
++ ctx->peer.connection->pool = ctx->pool;
++ ctx->peer.connection->log = ctx->log;
++ ngx_add_timer(ctx->peer.connection->read, zlcf->timeout);
++ ngx_add_timer(ctx->peer.connection->write, zlcf->timeout);
++
++#if (NGX_SSL)
++
++ if (ctx->handler->ssl && ctx->peer.connection->ssl == NULL) {
++ if(ngx_zm_lookup_ssl_init_connection(zlcf->ssl, ctx->peer.connection) == ZM_LOOKUP_SSL_EVENT_FAILED)
++ {
++ ngx_log_error(NGX_LOG_WARN, ctx->log, 0, "zm lookup: ngx_zm_lookup_connect "
++ "connect lookup handle error for host:%V, uri:%V, fail over to the next one",ctx->peer.name, &handler->uri);
++ ngx_zm_lookup_connect(ctx);
++ }
++ return;
++ }
++
++#endif
++
++ ctx->peer.connection->read->handler = ngx_zm_lookup_dummy_handler;
++ ctx->peer.connection->write->handler = ngx_zm_lookup_connect_handler;
++}
++
++static void
++ngx_zm_lookup_dummy_handler(ngx_event_t *ev)
++{
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, ev->log, 0,
++ "ngx_zm_lookup_dummy_handler()");
++}
++
++static void
++ngx_zm_lookup_connect_handler(ngx_event_t *ev)
++{
++ ngx_connection_t *c;
++ ngx_zm_lookup_ctx_t *ctx;
++ int sockerr;
++ socklen_t sockerr_len;
++ struct timeval tv;
++
++ c = ev->data;
++ ctx = c->data;
++
++ /* Add health checked as auth http? */
++
++ sockerr = 0;
++ sockerr_len = sizeof(sockerr);
++ getsockopt(c->fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerr_len);
++
++ if(sockerr == EINPROGRESS) {
++ /* expect to be reinvoked */
++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
++ "zm lookup: connect to route handler in progress");
++ return;
++ } else if (sockerr != 0) {
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
++ "zm lookup: connect to route handler error:%d, will re-elect",
++ sockerr);
++ ngx_gettimeofday(&tv);
++ ctx->handler->failure_time = tv.tv_sec;
++ ngx_close_connection(c);
++ ctx->peer.connection = NULL;
++
++ /* try again */
++ ngx_log_error(NGX_LOG_WARN, c->log, sockerr, "zm lookup: "
++ "connect lookup handle error, fail over to the next one");
++ ngx_zm_lookup_connect(ctx);
++ return;
++ } else {
++
++ if (ngx_zm_lookup_create_request(ctx) != NGX_OK) {
++ ctx->work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ ctx->work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, c->log, 0,
++ "zm lookup: begin zm lookup");
++ ctx->peer.connection->write->handler = ngx_zm_lookup_send_request_handler;
++ ctx->peer.connection->read->handler = ngx_zm_lookup_recv_response_handler;
++ ctx->lookup_response_handler = ngx_zm_lookup_process_response;
++ ctx->peer.connection->write->handler(ctx->peer.connection->write);
++ return;
++ }
++}
++
++static void
++ngx_zm_lookup_send_request_handler(ngx_event_t *wev)
++{
++ ngx_connection_t *c;
++ ngx_zm_lookup_ctx_t *ctx;
++ ngx_zm_lookup_work_t *work;
++ ngx_zm_lookup_conf_t *zlcf;
++ ssize_t size, n;
++
++ c = wev->data;
++ ctx = c->data;
++ work = ctx->work;
++ zlcf = (ngx_zm_lookup_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ if (wev->timedout) {
++ ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT,
++ "zm lookup: route handler timed out, failing over to the next one");
++ ngx_zm_lookup_close_connection(ctx);
++
++ /* try again */
++ ngx_zm_lookup_connect(ctx);
++ return;
++ }
++
++ size = ctx->lookup_req->last - ctx->lookup_req->pos;
++
++ n = c->send(c, ctx->lookup_req->pos, size);
++
++ if (n == NGX_ERROR) {
++ work->result = ZM_LOOKUP_WRITE_ERROR;
++ ngx_zm_lookup_close_connection(ctx);
++ work->on_failure(work);
++ return;
++ }
++ if (n > 0) {
++ ctx->lookup_req->pos += n;
++ if (n == size) {
++ wev->handler = ngx_zm_lookup_dummy_handler;
++ if (wev->timer_set) {
++ ngx_del_timer(wev);
++ }
++ if (ngx_handle_write_event(wev, 0) == NGX_ERROR) {
++ work->result = ZM_LOOKUP_WRITE_ERROR;
++ ngx_zm_lookup_close_connection(ctx);
++ work->on_failure(work);
++ return;
++ }
++ }
++ }
++ if (!wev->timer_set) {
++ ngx_add_timer(wev, zlcf->timeout);
++ }
++}
++
++static ngx_int_t
++ngx_zm_lookup_create_request(ngx_zm_lookup_ctx_t *ctx)
++{
++ ngx_buf_t *b;
++ size_t len;
++ ngx_pool_t *pool;
++ ngx_zm_lookup_conf_t *zlcf;
++ ngx_zm_lookup_work_t *work;
++ ngx_str_t proxy_ip, username;
++ zlcf = (ngx_zm_lookup_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++ pool = ctx->pool;
++ work = ctx->work;
++
++ if(work->alias_check_stat == ZM_ALIAS_FOUND) {
++ username = work->account_name;
++ } else {
++ username = work->username;
++ }
++
++ proxy_ip = ngx_zm_lookup_get_local_socket_addr_text (pool, work->connection->fd);
++
++ len = sizeof("GET ") - 1 + ctx->handler->uri.len + sizeof(" HTTP/1.0" CRLF) - 1
++ + sizeof("Host: ") - 1 + ctx->handler->host.len + sizeof(CRLF) - 1
++ + sizeof("Auth-Method: ") - 1 + ZM_AUTHMETH[work->auth_method].len + sizeof(CRLF) - 1
++ + sizeof("Auth-User: ") - 1 + username.len + sizeof(CRLF) - 1
++ + sizeof("Auth-Pass: ") - 1 + ngx_zm_lookup_password_placeholder.len + sizeof(CRLF) - 1
++ + sizeof("Auth-Protocol: ") - 1 + ZM_PROTO[work->protocol].len + sizeof(CRLF) - 1
++ + sizeof("Auth-Login-Attempt: ") - 1 + NGX_INT_T_LEN + sizeof(CRLF) - 1
++ + sizeof ("X-Proxy-IP: ") - 1 + proxy_ip.len + sizeof(CRLF) - 1
++ + sizeof ("Client-IP: ") - 1 + work->connection->addr_text.len + sizeof(CRLF) - 1;
++
++ if (work->type == zmauth_admin_console) {
++ len += sizeof ("Auth-Zimbra-Admin: True" CRLF) - 1;
++ } else if (work->type == zmauth_zx) {
++ len += sizeof ("Auth-Zimbra-Zx: True" CRLF) - 1;
++ }
++
++ if (IS_PROTO_WEB(work->protocol)) {
++ len += sizeof("X-Proxy-Host: ") - 1 + work->virtual_host.len + sizeof(CRLF) - 1;
++ }
++
++ if (work->auth_method == ZM_AUTHMETH_CERTAUTH ||
++ work->auth_method == ZM_AUTHMETH_GSSAPI) {
++ len += sizeof ("Auth-Admin-User: ") - 1 + zlcf->master_auth_username.len + sizeof(CRLF) - 1;
++ len += sizeof ("Auth-Admin-User: ") - 1 + zlcf->master_auth_password.len + sizeof(CRLF) - 1;
++
++ if (work->auth_method == ZM_AUTHMETH_GSSAPI) {
++ len += sizeof ("Auth-ID: ") - 1 + work->auth_id.len + sizeof(CRLF) - 1;
++ }
++ }
++
++ len += sizeof(CRLF) - 1;
++
++ b = ngx_create_temp_buf(pool, len);
++
++ if (b == NULL) {
++ return NGX_ERROR;
++ }
++
++ b->last = ngx_sprintf(b->last, "GET %V HTTP/1.0" CRLF, &ctx->handler->uri);
++ b->last = ngx_sprintf(b->last, "Host: %V" CRLF, &ctx->handler->host);
++ b->last = ngx_sprintf(b->last, "Auth-Method: %V" CRLF, &ZM_AUTHMETH[work->auth_method]);
++ b->last = ngx_sprintf(b->last, "Auth-User: %V" CRLF, &username);
++ b->last = ngx_sprintf(b->last, "Auth-Pass: %V" CRLF, &ngx_zm_lookup_password_placeholder);
++ b->last = ngx_sprintf(b->last, "Auth-Protocol: %V" CRLF, &ZM_PROTO[work->protocol]);
++ if (IS_PROTO_WEB(work->protocol)) {
++ work->login_attempts = 0; /* for web, login attempts is always 0 */
++ }
++ b->last = ngx_sprintf(b->last, "Auth-Login-Attempt: %d" CRLF, work->login_attempts);
++ b->last = ngx_sprintf(b->last, "X-Proxy-IP: %V" CRLF, &proxy_ip);
++ b->last = ngx_sprintf(b->last, "Client-IP: %V" CRLF, &work->connection->addr_text);
++ if (work->type == zmauth_admin_console) {
++ b->last = ngx_cpymem(b->last, "Auth-Zimbra-Admin: True" CRLF, sizeof("Auth-Zimbra-Admin: True" CRLF) - 1);
++ } else if (work->type == zmauth_zx) {
++ b->last = ngx_cpymem(b->last, "Auth-Zimbra-Zx: True" CRLF, sizeof("Auth-Zimbra-Zx: True" CRLF) - 1);
++ }
++
++ if (IS_PROTO_WEB(work->protocol)) {
++ b->last = ngx_sprintf(b->last, "X-Proxy-Host: %V" CRLF, &work->virtual_host);
++ }
++
++ if (work->auth_method == ZM_AUTHMETH_CERTAUTH||
++ work->auth_method == ZM_AUTHMETH_GSSAPI) {
++ b->last = ngx_sprintf(b->last, "Auth-Admin-User: %V" CRLF, &zlcf->master_auth_username);
++ b->last = ngx_sprintf(b->last, "Auth-Admin-Pass: %V" CRLF, &zlcf->master_auth_password);
++
++ if (work->auth_method == ZM_AUTHMETH_GSSAPI) {
++ b->last = ngx_sprintf(b->last, "Auth-ID: %V" CRLF, &work->auth_id);
++ }
++ }
++
++ b->last = ngx_cpymem(b->last, CRLF, sizeof(CRLF) - 1);
++
++ ctx->lookup_req = b;
++
++#if (NGX_DEBUG)
++ ngx_str_t temp;
++ temp.data = b->pos;
++ temp.len = b->last - b->pos;
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "send lookup request:\n%V", &temp);
++#endif
++
++ return NGX_OK;
++}
++
++static void
++ngx_zm_lookup_recv_response_handler(ngx_event_t *rev)
++{
++ ngx_connection_t *c;
++ ngx_zm_lookup_ctx_t *ctx;
++ ngx_zm_lookup_work_t *work;
++ ngx_zm_lookup_conf_t *zlcf;
++ ssize_t n, size;
++
++ c = rev->data;
++ ctx = c->data;
++ work = ctx->work;
++ zlcf = (ngx_zm_lookup_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ if(rev->timedout) {
++ ngx_log_debug2(NGX_LOG_DEBUG_ZIMBRA, rev->log, 0,
++ "zm_route_lookup_module: lookup handler timed out, host:%V, uri:%V",
++ &ctx->handler->peer->name, &ctx->handler->uri);
++
++ ngx_zm_lookup_close_connection(ctx);
++ work->result = ZM_LOOKUP_READ_TIMEOUT;
++ work->err = ERRMSG[ZM_LOOKUP_READ_TIMEOUT];
++ work->on_failure(work);
++ return;
++ }
++
++ if(ctx->lookup_resp == NULL) {
++ ctx->lookup_resp = ngx_create_temp_buf(ctx->pool, zlcf->buffer_size);
++
++ if (ctx->lookup_resp == NULL) {
++ ngx_zm_lookup_close_connection(ctx);
++ work->ctx = NULL;
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++ }
++
++ size = ctx->lookup_resp->end - ctx->lookup_resp->last;
++ n = c->recv(c, ctx->lookup_resp->pos, size);
++
++ ngx_log_debug1(NGX_LOG_DEBUG_ZIMBRA, rev->log, 0,
++ "zm lookup: ngx_recv() returned %d bytes", n);
++ if(n > 0) {
++ ctx->lookup_resp->last += n;
++ ctx->lookup_response_handler (ctx);
++ return;
++ }
++
++ if(n == NGX_AGAIN) {
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, rev->log, 0,
++ "zm lookup: ngx_recv() returned NGX_AGAIN");
++ return;
++ }
++
++ ngx_zm_lookup_close_connection(ctx);
++ work->ctx = NULL;
++ work->result = ZM_LOOKUP_READ_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_READ_ERROR];
++ work->on_failure(work);
++}
++
++static void
++ngx_zm_lookup_process_response(ngx_zm_lookup_ctx_t *ctx)
++{
++ u_char *p, ch, *code_start;
++ ngx_int_t code;
++ ngx_flag_t error;
++ ngx_str_t errmsg;
++
++ enum {
++ sw_start = 0,
++ sw_H,
++ sw_HT,
++ sw_HTT,
++ sw_HTTP,
++ sw_HTTPVER,
++ sw_code,
++ sw_skip,
++ sw_almost_done
++ } state;
++
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: process route discovery HTTP status");
++
++ state = ctx->state;
++
++ error = 0;
++
++ for (p = ctx->lookup_resp->pos; p < ctx->lookup_resp->last; p++)
++ {
++ ch = *p;
++
++ switch (state) {
++
++ /* "HTTP/" */
++ case sw_start:
++ if (ch == 'H') {
++ state = sw_H;
++ break;
++ }
++ goto next;
++
++ case sw_H:
++ if (ch == 'T') {
++ state = sw_HT;
++ break;
++ }
++ goto next;
++
++ case sw_HT:
++ if (ch == 'T') {
++ state = sw_HTT;
++ break;
++ }
++ goto next;
++
++ case sw_HTT:
++ if (ch == 'P') {
++ state = sw_HTTP;
++ break;
++ }
++ goto next;
++
++ case sw_HTTP:
++ if (ch == '/') {
++ state = sw_HTTPVER;
++ break;
++ }
++ goto next;
++
++ case sw_HTTPVER:
++ if (ch == ' ') {
++ state = sw_code;
++ code_start = p + 1;
++ break;
++ }
++
++ if ((ch >= '0' && ch <= '9') || ch == '.') {
++ break;
++ }
++ goto next;
++
++ case sw_code:
++ switch (ch) {
++ case ' ':
++ code = ngx_atoi(code_start, p - code_start);
++ if (code != 200) {
++ error = 1;
++ }
++ state = sw_skip;
++ break;
++ case CR:
++ state = sw_almost_done;
++ break;
++ case LF:
++ goto done;
++ }
++ break;
++
++ /* any text until end of line */
++ case sw_skip:
++ switch (ch) {
++ case CR:
++ state = sw_almost_done;
++ break;
++ case LF:
++ goto done;
++ }
++ break;
++
++ /* end of status line */
++ case sw_almost_done:
++ if (ch == LF) {
++ goto done;
++ }
++
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
++ "zm lookup: lookup handler %V sent invalid response",
++ ctx->peer.name);
++ ngx_zm_lookup_close_connection(ctx);
++ ctx->work->result = ZM_LOOKUP_INVALID_RESPONSE;
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++ }
++
++ ctx->lookup_resp->pos = p;
++ ctx->state = state;
++
++ return;
++
++next:
++
++ p = ctx->lookup_resp->start - 1;
++
++done:
++
++ if (error) {
++ errmsg.data = code_start;
++ errmsg.len = p - code_start + 1;
++ /* trim the trailing CR LF */
++ while (((*p) == CR || (*p) == LF) && p >= ctx->lookup_resp->start) {
++ errmsg.len--;
++ p--;
++ }
++
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
++ "zm lookup: lookup handler %V sent error response: %V",
++ ctx->peer.name, &errmsg);
++ ngx_zm_lookup_close_connection(ctx);
++ ctx->work->result = ZM_LOOKUP_INVALID_RESPONSE;
++ ctx->work->on_failure(ctx->work);
++ return;
++ }
++
++ ctx->lookup_resp->pos = p + 1;
++ ctx->state = 0;
++ ctx->lookup_response_handler = ngx_zm_lookup_process_response_headers;
++ ctx->lookup_response_handler (ctx);
++}
++
++static ngx_int_t
++ngx_zm_lookup_parse_response_headers(ngx_zm_lookup_ctx_t *ctx)
++{
++ u_char c, ch, *p;
++ enum {
++ sw_start = 0,
++ sw_name,
++ sw_space_before_value,
++ sw_value,
++ sw_space_after_value,
++ sw_almost_done,
++ sw_header_almost_done
++ } state;
++
++ state = ctx->state;
++
++ for (p = ctx->lookup_resp->pos; p < ctx->lookup_resp->last; p++) {
++ ch = *p;
++
++ switch (state) {
++
++ /* first char */
++ case sw_start:
++
++ switch (ch) {
++ case CR:
++ ctx->header_end = p;
++ state = sw_header_almost_done;
++ break;
++ case LF:
++ ctx->header_end = p;
++ goto header_done;
++ default:
++ state = sw_name;
++ ctx->header_name_start = p;
++
++ c = (u_char) (ch | 0x20);
++ if (c >= 'a' && c <= 'z') {
++ break;
++ }
++
++ if (ch >= '0' && ch <= '9') {
++ break;
++ }
++
++ return NGX_ERROR;
++ }
++ break;
++
++ /* header name */
++ case sw_name:
++ c = (u_char) (ch | 0x20);
++ if (c >= 'a' && c <= 'z') {
++ break;
++ }
++
++ if (ch == ':') {
++ ctx->header_name_end = p;
++ state = sw_space_before_value;
++ break;
++ }
++
++ if (ch == '-') {
++ break;
++ }
++
++ if (ch >= '0' && ch <= '9') {
++ break;
++ }
++
++ if (ch == CR) {
++ ctx->header_name_end = p;
++ ctx->header_start = p;
++ ctx->header_end = p;
++ state = sw_almost_done;
++ break;
++ }
++
++ if (ch == LF) {
++ ctx->header_name_end = p;
++ ctx->header_start = p;
++ ctx->header_end = p;
++ goto done;
++ }
++
++ return NGX_ERROR;
++
++ /* space* before header value */
++ case sw_space_before_value:
++ switch (ch) {
++ case ' ':
++ break;
++ case CR:
++ ctx->header_start = p;
++ ctx->header_end = p;
++ state = sw_almost_done;
++ break;
++ case LF:
++ ctx->header_start = p;
++ ctx->header_end = p;
++ goto done;
++ default:
++ ctx->header_start = p;
++ state = sw_value;
++ break;
++ }
++ break;
++
++ /* header value */
++ case sw_value:
++ switch (ch) {
++ case ' ':
++ ctx->header_end = p;
++ state = sw_space_after_value;
++ break;
++ case CR:
++ ctx->header_end = p;
++ state = sw_almost_done;
++ break;
++ case LF:
++ ctx->header_end = p;
++ goto done;
++ }
++ break;
++
++ /* space* before end of header line */
++ case sw_space_after_value:
++ switch (ch) {
++ case ' ':
++ break;
++ case CR:
++ state = sw_almost_done;
++ break;
++ case LF:
++ goto done;
++ default:
++ state = sw_value;
++ break;
++ }
++ break;
++
++ /* end of header line */
++ case sw_almost_done:
++ switch (ch) {
++ case LF:
++ goto done;
++ default:
++ return NGX_ERROR;
++ }
++
++ /* end of header */
++ case sw_header_almost_done:
++ switch (ch) {
++ case LF:
++ goto header_done;
++ default:
++ return NGX_ERROR;
++ }
++ }
++ }
++
++ ctx->lookup_resp->pos = p;
++ ctx->state = state;
++
++ return NGX_AGAIN;
++
++done:
++
++ ctx->lookup_resp->pos = p + 1;
++ ctx->state = sw_start;
++
++ return NGX_OK;
++
++header_done:
++
++ ctx->lookup_resp->pos = p + 1;
++ ctx->state = sw_start;
++
++ return NGX_DONE;
++}
++
++static void
++ngx_zm_lookup_process_response_headers(ngx_zm_lookup_ctx_t *ctx)
++{
++ ngx_zm_lookup_conf_t *zlcf;
++
++ size_t len;
++ ngx_int_t rc, n;
++ ngx_zm_lookup_work_t *work;
++ ngx_str_t addr; /* route ipaddr */
++ ngx_str_t port; /* route port */
++ ngx_flag_t isCacheAlias; /* whether to cache alias for the auth account */
++
++ zlcf = (ngx_zm_lookup_conf_t *)ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ work = ctx->work;
++
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: process route discovery HTTP headers");
++
++ for (;;)
++ {
++ rc = ngx_zm_lookup_parse_response_headers(ctx);
++
++ if (rc == NGX_OK)
++ {
++
++#if (NGX_DEBUG)
++ {
++ ngx_str_t key, value;
++
++ key.len = ctx->header_name_end - ctx->header_name_start;
++ key.data = ctx->header_name_start;
++ value.len = ctx->header_end - ctx->header_start;
++ value.data = ctx->header_start;
++
++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ctx->log, 0,
++ "zm_ngx_lookup_module: zm lookup http header: \"%V: %V\"",
++ &key, &value);
++ }
++#endif
++
++ len = ctx->header_name_end - ctx->header_name_start;
++
++ if (len == sizeof("Auth-Status") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Status",
++ sizeof("Auth-Status") - 1)
++ == 0)
++ {
++ len = ctx->header_end - ctx->header_start;
++
++ if (len == 2
++ && ctx->header_start[0] == 'O'
++ && ctx->header_start[1] == 'K')
++ {
++ continue;
++ }
++
++ if (len == 4
++ && ctx->header_start[0] == 'W'
++ && ctx->header_start[1] == 'A'
++ && ctx->header_start[2] == 'I'
++ && ctx->header_start[3] == 'T')
++ {
++ /* NginxLookup never return "Auth-Status: WAIT" */
++ continue;
++ }
++
++ /* Accept error msg like "Auth-Status: login failed" */
++ work->err.len = len;
++ work->err.data = ctx->header_start;
++
++ continue;
++ }
++
++ if (len == sizeof("Auth-Server") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Server",
++ sizeof("Auth-Server") - 1)
++ == 0)
++ {
++ addr.len = ctx->header_end - ctx->header_start;
++ addr.data = ctx->header_start;
++
++ continue;
++ }
++
++ if (len == sizeof("Auth-Port") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Port",
++ sizeof("Auth-Port") - 1)
++ == 0)
++ {
++ port.len = ctx->header_end - ctx->header_start;
++ port.data = ctx->header_start;
++
++ continue;
++ }
++
++ if (len == sizeof("Auth-Cache-Alias") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Cache-Alias",
++ sizeof("Auth-Cache-Alias") - 1)
++ == 0)
++ {
++ len = ctx->header_end - ctx->header_start;
++
++ if (len == 4
++ && ctx->header_start[0] == 'T'
++ && ctx->header_start[1] == 'R'
++ && ctx->header_start[2] == 'U'
++ && ctx->header_start[3] == 'E')
++ {
++ /* cache the alias if True*/
++ isCacheAlias = 1;
++ } else {
++ isCacheAlias = 0;
++ }
++ continue;
++ }
++ if (len == sizeof("Auth-User") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-User",
++ sizeof("Auth-User") - 1)
++ == 0)
++ {
++ work->account_name.len = ctx->header_end - ctx->header_start;
++ work->account_name.data = ctx->header_start;
++
++ continue;
++ }
++
++ if (len == sizeof("Auth-Pass") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Pass",
++ sizeof("Auth-Pass") - 1)
++ == 0)
++ {
++ /* client cert auth will return zm_auth_token in
++ Auth-Pass
++ */
++ if (work->auth_method == ZM_AUTHMETH_GSSAPI ||
++ work->auth_method == ZM_AUTHMETH_CERTAUTH) {
++ work->zm_auth_token.len = ctx->header_end - ctx->header_start;
++ work->zm_auth_token.data = ctx->header_start;
++ }
++
++ continue;
++ }
++
++ if (len == sizeof("Auth-ID") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-ID",
++ sizeof("Auth-ID") - 1)
++ == 0)
++ {
++ /* just for GSSAPI */
++ if (work->auth_method == ZM_AUTHMETH_GSSAPI) {
++ work->auth_id.len = ctx->header_end - ctx->header_start;
++ work->auth_id.data = ctx->header_start;
++ }
++
++ continue;
++ }
++
++
++ if (len == sizeof("Auth-Wait") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Wait",
++ sizeof("Auth-Wait") - 1)
++ == 0)
++ {
++ n = ngx_atoi(ctx->header_start,
++ ctx->header_end - ctx->header_start);
++
++ if (n != NGX_ERROR) {
++ work->wait_time = n;
++ }
++
++ continue;
++ }
++
++
++ if (len == sizeof("Auth-Error-Code") - 1
++ && ngx_strncasecmp(ctx->header_name_start,
++ (u_char *) "Auth-Error-Code",
++ sizeof("Auth-Error-Code") - 1)
++ == 0)
++ {
++ /* NginxLookup never return this header */
++ }
++
++ continue;
++ }
++
++ if (rc == NGX_AGAIN ) {
++ return;
++ }
++
++ /* close connection to the lookup handler */
++ ngx_zm_lookup_close_connection(ctx);
++ work->ctx = NULL; /* avoid duplicate clean up */
++
++ if (rc == NGX_DONE){
++ ngx_log_debug0(NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: done processing lookup headers");
++ if (work->err.len) {
++ /* Login failed */
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0, "zm lookup: an error is "
++ "returned by zimbra lookup handler: %V", &work->err);
++ work->result = ZM_LOOKUP_LOGIN_FAILED;
++ work->on_failure(work);
++ return;
++
++ } else {
++ if (IS_LOOKUP_ROUTE(work->auth_method)) {
++
++ ngx_log_debug3(NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "zm lookup: lookup handler %V sent route %V:%V",
++ ctx->peer.name, &addr, &port);
++ if (addr.len == 0 || port.len == 0) {
++ work->result = ZM_LOOKUP_INVALID_ROUTE;
++ work->on_failure(work);
++ return;
++ } else {
++ /* retrieve route */
++ work->route = ngx_palloc(ctx->pool, sizeof(ngx_addr_t));
++ if (work->route == NULL) { /* NO MEM */
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++ if (ngx_zm_lookup_retrieve_route (ctx->pool,
++ &addr, &port, work->route) == NGX_ERROR) {
++
++ /* route retrival error */
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
++ "Error occurs when retrieve route info from lookup handler, "
++ "addr=%V, port=%V", &addr, &port);
++ work->result = ZM_LOOKUP_INVALID_ROUTE;
++ work->err = ERRMSG[ZM_LOOKUP_INVALID_ROUTE];
++ work->on_failure(work);
++ return;
++ } else {
++
++ /* route retrival succeed */
++ if (zlcf->caching &&
++ ctx->work->auth_method != ZM_AUTHMETH_GSSAPI &&
++ ctx->work->auth_method != ZM_AUTHMETH_CERTAUTH) {
++ /* add alias-->account && account-->route caching */
++ if (ctx->work->alias_check_stat != ZM_ALIAS_FOUND &&
++ ctx->work->alias_check_stat != ZM_ALIAS_IGNORED && isCacheAlias) {
++ /* only cache alias-->account when the account is unavailable from cache */
++ /* cache alias-->account with default domain */
++ ngx_zm_lookup_cache_alias(ctx, work->username, work->account_name);
++ }
++
++ if (work->account_name.len > 0) {
++ ngx_zm_lookup_cache_route(ctx, work->account_name, work->route->name);
++ } else {
++ ngx_zm_lookup_cache_route(ctx, work->username, work->route->name);
++ }
++ }
++ work->result = ZM_LOOKUP_SUCCESS;
++ work->on_success(work);
++ return;
++ }
++ }
++ } else {
++ /* non-route lookup, such as certauth */
++ work->result = ZM_LOOKUP_SUCCESS;
++ work->on_success(work);
++ return;
++ }
++ }
++ }
++
++ /* rc == NGX_ERROR */
++ ngx_log_error(NGX_LOG_ERR, ctx->log, 0,
++ "zm lookup: route handler %V sent invalid header in response",
++ ctx->peer.name);
++
++ return;
++ }
++}
++
++
++static ngx_int_t
++ngx_zm_lookup_retrieve_route (ngx_pool_t * pool, ngx_str_t * addr_text,
++ ngx_str_t * port_text, ngx_addr_t * route)
++{
++ ngx_int_t rc;
++ size_t i;
++ ngx_flag_t ipv6, domainName;
++ ngx_url_t u;
++ u_char c;
++
++ ipv6 = 0, domainName = 0;
++ for (i = 0; i < addr_text->len; i++) {
++ c = addr_text->data[i];
++ if (c == ':') {
++ /* an addr containing ":" may be IPv6 */
++ domainName = 0;
++ ipv6 = 1;
++ break;
++ } else if (c >= 'A' && c != '.') {
++ domainName = 1;
++ // try to look for ":". if found it must be ipv6
++ }
++ }
++
++ ngx_memzero(&u, sizeof(ngx_url_t));
++ u.uri_part = 0;
++
++ if(ipv6) {
++ u.url.len = addr_text->len + port_text->len + 3;
++ u.url.data = ngx_palloc(pool, u.url.len);
++ ngx_sprintf(u.url.data, "[%V]:%V", addr_text, port_text);
++ } else { /* ipv4 or domain name */
++ u.url.len = addr_text->len + port_text->len + 1;
++ u.url.data = ngx_palloc(pool, u.url.len);
++ ngx_sprintf(u.url.data, "%V:%V", addr_text, port_text);
++ }
++
++ if(!domainName) {
++ u.listen = 1; // set this will only parse the IP but not resolve addr
++ }
++
++ rc = ngx_parse_url(pool, &u);
++
++ if(rc != NGX_OK) {
++ return rc;
++ }
++
++ route->name = u.url;
++ route->socklen = u.socklen;
++ route->sockaddr = ngx_palloc(pool, route->socklen);
++ ngx_memcpy(route->sockaddr, &u.sockaddr, route->socklen);
++
++ return NGX_OK;
++}
++
++static void
++ngx_zm_lookup_close_connection(ngx_zm_lookup_ctx_t * ctx) {
++ if (ctx->peer.connection) {
++ ngx_log_debug2 (NGX_LOG_DEBUG_ZIMBRA, ctx->log, 0,
++ "close connection %p to nginx lookup handler %V",
++ ctx->peer.connection, ctx->peer.name);
++#if (NGX_SSL)
++
++ if (ctx->handler->ssl && ctx->peer.connection->ssl) {
++ ctx->peer.connection->ssl->no_wait_shutdown = 1;
++ ngx_ssl_shutdown(ctx->peer.connection);
++ }
++
++#endif
++ ngx_close_connection(ctx->peer.connection);
++ ctx->peer.connection = NULL;
++ }
++}
++
++void
++ngx_zm_lookup_finalize(ngx_zm_lookup_work_t * work)
++{
++ ngx_zm_lookup_ctx_t *ctx;
++
++ if (work == NULL) {
++ return;
++ }
++
++ ctx = work->ctx;
++
++ if(ctx != NULL) {
++ if(ctx->wait_memcache) {
++ ngx_memcache_ignore_work_by_ctx(ctx);
++ work->ctx = NULL;
++ return;
++ }
++
++ ngx_zm_lookup_close_connection(ctx);
++ work->ctx = NULL;
++ return;
++ }
++}
++
++/*
++ * Giving a socket, return its local addr string representation IP. The
++ * string will be allocated on "pool".
++ */
++ngx_str_t
++ngx_zm_lookup_get_local_socket_addr_text (ngx_pool_t *pool, ngx_socket_t s)
++{
++ int family;
++ static ngx_str_t res;
++ struct sockaddr_in *sin;
++#if (NGX_HAVE_INET6)
++ struct sockaddr_in6 *sin6;
++#endif
++ u_char *p;
++ socklen_t len, strlen;
++ u_char sockaddr[NGX_SOCKADDRLEN];
++
++ len = NGX_SOCKADDRLEN;
++ ngx_memzero(sockaddr, len);
++ getsockname(s, (struct sockaddr*)sockaddr, &len);
++
++ family = ((struct sockaddr *)sockaddr)->sa_family;
++ if (family == AF_INET) {
++ sin = (struct sockaddr_in *)sockaddr;
++ p = ngx_palloc(pool, NGX_INET_ADDRSTRLEN);
++ strlen = ngx_inet_ntop (family, &(sin->sin_addr.s_addr), p,
++ NGX_INET_ADDRSTRLEN);
++
++#if (NGX_HAVE_INET6)
++ } else {
++ sin6 = (struct sockaddr_in6 *)sockaddr;
++ p = ngx_palloc(pool, NGX_INET6_ADDRSTRLEN);
++ strlen = ngx_inet_ntop (family, &(sin6->sin6_addr.s6_addr),
++ p, NGX_INET6_ADDRSTRLEN);
++#endif
++
++ }
++
++ res.data = p;
++ res.len = strlen;
++
++ return res;
++}
++
++/* make the cache "alias-->account" */
++static void
++ngx_zm_lookup_cache_alias(ngx_zm_lookup_ctx_t *ctx, ngx_str_t alias,
++ ngx_str_t account_name) {
++ mc_work_t mc;
++ ngx_str_t key;
++ ngx_log_t *log;
++ ngx_zm_lookup_work_t *work;
++ ngx_pool_t *pool;
++ const u_char *p;
++
++ log = ctx->log;
++ work = ctx->work;
++ pool = ctx->pool;
++
++ if (alias.len == account_name.len &&
++ ngx_memcmp(alias.data, account_name.data, alias.len) == 0
++ ) {
++ /* bug 66469, try to take the part before '@' as alias */
++ p = ngx_zm_strchr(alias, '@');
++ if (p == NULL) {
++ return;
++ }
++
++ alias.len = p - alias.data;
++
++ if (work->alias_key.len > 0) {
++ ngx_str_null(&work->alias_key); /* reset it and force regeneration later */
++ }
++ }
++
++ if (work->alias_key.len > 0) {
++ key = work->alias_key;
++
++ } else {
++ if (IS_PROTO_WEB(work->protocol)) {
++ key = ngx_zm_lookup_get_http_alias_key
++ (pool, log, alias, work->virtual_host);
++ } else {
++ key = ngx_zm_lookup_get_mail_alias_key
++ (pool, log, alias, work->connection->addr_text);
++ }
++
++ if (key.len == 0) { /* NOMEM */
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++
++ work->alias_key = key;
++ }
++
++ mc.ctx = ctx;
++ mc.request_code = mcreq_add;
++ mc.response_code = mcres_unknown;
++ mc.on_success = ngx_zm_lookup_cache_dummy_handler;
++ mc.on_failure = ngx_zm_lookup_cache_dummy_handler;
++
++ //no need to set ctx->wait_memcache_response since w.ctx won't be
++ //destroyed before response comes
++ ngx_memcache_post(&mc, key, account_name, NULL, log);
++}
++
++/*
++ * make the cache account-->route/id-->route
++ * user: account_name/zimbra id
++ */
++static void
++ngx_zm_lookup_cache_route(ngx_zm_lookup_ctx_t *ctx, ngx_str_t user, ngx_str_t route)
++{
++ mc_work_t mc;
++ ngx_log_t *log;
++ ngx_str_t key;
++ ngx_zm_lookup_work_t *work;
++ ngx_zm_lookup_conf_t *zlcf;
++
++ zlcf = (ngx_zm_lookup_conf_t *)
++ ngx_get_conf(ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++
++ log = ctx->log;
++ work = ctx->work;
++
++ if (work->auth_method == ZM_AUTHMETH_ZIMBRAID) {
++ key = ngx_zm_lookup_get_id_route_key(
++ ctx->pool, log,
++ ZM_PROTO[work->protocol], user, work->type);
++ } else {
++ if (zlcf->allow_unqualified == 0 && !is_login_qualified(user)) {
++ key = ngx_zm_lookup_get_user_route_key(ctx->pool, log,
++ ZM_PROTO[work->protocol], user, work->connection->addr_text);
++ } else {
++ key = ngx_zm_lookup_get_user_route_key(ctx->pool, log,
++ ZM_PROTO[work->protocol], user, NGX_EMPTY_STR);
++ }
++ }
++
++ if (key.len == 0) { /* NOMEM */
++ work->result = ZM_LOOKUP_MEM_ALLOC_ERROR;
++ work->err = ERRMSG[ZM_LOOKUP_MEM_ALLOC_ERROR];
++ work->on_failure(work);
++ return;
++ }
++
++ ctx->work->route_key = key;
++
++ mc.ctx = ctx;
++ mc.request_code = mcreq_add;
++ mc.response_code = mcres_unknown;
++ mc.on_success = ngx_zm_lookup_cache_dummy_handler;
++ mc.on_failure = ngx_zm_lookup_cache_dummy_handler;
++
++ //no need to set ctx->wait_memcache_response because nothing
++ //will be disposed
++ ngx_memcache_post(&mc, key, route, NULL, log);
++}
++
++static void
++ngx_zm_lookup_cache_dummy_handler (mc_work_t *work)
++{
++ /* do nothing */
++}
++
++static ngx_str_t
++ngx_zm_lookup_get_user_route_key(ngx_pool_t *pool, ngx_log_t *log,
++ ngx_str_t proto, ngx_str_t account_name, ngx_str_t client_ip)
++{
++ ngx_str_t key;
++ size_t len;
++ u_char *p;
++
++ len = sizeof("route:") - 1 +
++ sizeof("proto=") - 1 +
++ proto.len +
++ sizeof(";") - 1 +
++ sizeof("user=") - 1 +
++ account_name.len;
++
++ if (client_ip.len > 0) {
++ len += sizeof("@") - 1 + client_ip.len;
++ }
++
++ key.data = ngx_palloc(pool, len);
++ if (key.data == NULL) {
++ key.len = 0;
++ return key;
++ }
++
++ p = key.data;
++ p = ngx_cpymem(p, "route:", sizeof("route:") - 1);
++ p = ngx_cpymem(p, "proto=", sizeof("proto=") - 1);
++ p = ngx_cpymem(p, proto.data, proto.len);
++ *p++ = ';';
++ p = ngx_cpymem(p, "user=", sizeof("user=") - 1);
++ p = ngx_cpymem(p, account_name.data, account_name.len);
++
++ if (client_ip.len > 0) {
++ *p++ = '@';
++ p = ngx_cpymem(p, client_ip.data, client_ip.len);
++ }
++
++ key.len = p - key.data;
++
++ return key;
++}
++
++ngx_str_t
++ngx_zm_lookup_get_mail_alias_key (ngx_pool_t *pool, ngx_log_t *log,
++ ngx_str_t alias, ngx_str_t ip)
++{
++ ngx_str_t key;
++ size_t len;
++ u_char *p;
++
++ len = sizeof("alias:") - 1 +
++ sizeof("user=") - 1 +
++ alias.len +
++ sizeof(";") - 1 +
++ sizeof("ip=") - 1 +
++ ip.len;
++
++ key.data = ngx_palloc(pool, len);
++ if (key.data == NULL) {
++ key.len = 0;
++ return key;
++ }
++
++ p = key.data;
++ p = ngx_cpymem(p, "alias:", sizeof("alias:") - 1);
++ p = ngx_cpymem(p, "user=", sizeof("user=") - 1);
++ p = ngx_cpymem(p, alias.data, alias.len);
++ *p++ = ';';
++ p = ngx_cpymem(p,"ip=", sizeof("ip=") - 1);
++ p = ngx_cpymem(p, ip.data, ip.len);
++
++ key.len = p - key.data;
++
++ return key;
++}
++
++ngx_str_t
++ngx_zm_lookup_get_http_alias_key (ngx_pool_t *pool, ngx_log_t *log,
++ ngx_str_t alias, ngx_str_t vhost)
++{
++ ngx_str_t key;
++ size_t len;
++ u_char *p;
++
++ len = sizeof("alias:") - 1 +
++ sizeof("user=") - 1 +
++ alias.len +
++ sizeof(";") - 1 +
++ sizeof("vhost=") - 1 +
++ vhost.len;
++
++ key.data = ngx_palloc(pool, len);
++ if (key.data == NULL) {
++ key.len = 0;
++ return key;
++ }
++
++ p = key.data;
++ p = ngx_cpymem(p, "alias:", sizeof("alias:") - 1);
++ p = ngx_cpymem(p, "user=", sizeof("user=") - 1);
++ p = ngx_cpymem(p, alias.data, alias.len);
++ *p++ = ';';
++ p = ngx_cpymem(p, "vhost=", sizeof("vhost=") - 1);
++ p = ngx_cpymem(p, vhost.data, vhost.len);
++
++ key.len = p - key.data;
++
++ return key;
++}
++
++static ngx_str_t
++ngx_zm_lookup_get_id_route_key(ngx_pool_t *pool, ngx_log_t *log,
++ ngx_str_t proto, ngx_str_t id, ngx_http_zmauth_t type)
++{
++ ngx_str_t key;
++ size_t len;
++ u_char *p;
++
++ len = sizeof("route:") - 1 +
++ sizeof("proto=") - 1 +
++ proto.len +
++ sizeof(";") - 1 +
++ sizeof("id=") - 1 +
++ id.len;
++
++ if (type == zmauth_admin_console) {
++ len += sizeof("admin=1;") - 1;
++ } else if (type == zmauth_zx) {
++ len += sizeof("zx=1;") - 1;
++ }
++
++ key.data = ngx_palloc(pool, len);
++ if (key.data == NULL) {
++ key.len = 0;
++ return key;
++ }
++
++ p = key.data;
++ p = ngx_cpymem(p, "route:", sizeof("route:") - 1);
++ p = ngx_cpymem(p, "proto=", sizeof("proto=") - 1);
++ p = ngx_cpymem(p, proto.data, proto.len);
++ *p++ = ';';
++ if (type == zmauth_admin_console) {
++ p = ngx_cpymem(p, "admin=1;", sizeof("admin=1;") - 1);
++ } else if (type == zmauth_zx) {
++ p = ngx_cpymem(p, "zx=1;", sizeof("zx=1;") - 1);
++ }
++ p = ngx_cpymem(p, "id=", sizeof("id=") - 1);
++ p = ngx_cpymem(p, id.data, id.len);
++
++ key.len = p - key.data;
++
++ return key;
++}
++
++/*
++ * delete alias-->account & account-->route cache from memcache
++ * after auth failure
++ */
++void
++ngx_zm_lookup_delete_cache(ngx_str_t alias_key, ngx_str_t route_key)
++{
++ mc_work_t w;
++ ngx_log_t *log;
++ ngx_flag_t delete_alias_cache, delete_route_cache;
++
++ delete_alias_cache = 0;
++ delete_route_cache = 0;
++
++ if (alias_key.len > 0) {
++ delete_alias_cache = 1;
++ }
++
++ if (route_key.len > 0) {
++ delete_route_cache = 1;
++ }
++
++ if (delete_alias_cache == 0 && delete_route_cache == 0) {
++ return;
++ }
++
++ log = ngx_cycle->log;
++
++ w.request_code = mcreq_delete;
++ w.response_code = mcres_unknown;
++ w.on_success = ngx_zm_lookup_delete_cache_handler;
++ w.on_failure = ngx_zm_lookup_delete_cache_handler;
++
++ if (delete_alias_cache) {
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, log, 0,
++ "delete cached alias, key:%V", &alias_key);
++ ngx_memcache_post(&w, alias_key, NGX_EMPTY_STR, /* pool */ NULL, log);
++ }
++
++ if (delete_route_cache) {
++ ngx_log_debug1 (NGX_LOG_DEBUG_ZIMBRA, log, 0,
++ "delete cached route, key:%V", &route_key);
++
++ ngx_memcache_post (&w, route_key, NGX_EMPTY_STR, /* pool */ NULL, log);
++ }
++}
++
++static void
++ngx_zm_lookup_delete_cache_handler (mc_work_t *work)
++{
++ /* do nothing */
++}
++
++/* Utility function to check whether a login name is fully qualified
++ Return value is boolean (ngx_flag_t for portability)
++ */
++ngx_flag_t
++is_login_qualified (ngx_str_t login)
++{
++ /* we cannot use the crt strchr because login is not 0 terminated,
++ * neither we have no strnchr to use
++ */
++
++ size_t i, len;
++ len = login.len - 1; /* if the last symbol is @, it's not qualified */
++
++ for (i = 0; i < len; ++i) {
++ if (login.data[i] == '@') {
++ return 1;
++ }
++ }
++
++ return 0;
++}
++
++static const u_char *
++ngx_zm_strchr (ngx_str_t str, int chr) {
++ const u_char *end;
++ u_char *p;
++ u_char c;
++
++ end = str.data + str.len;
++ p = str.data;
++ c = (u_char)chr;
++ do {
++ if (*p == c) {
++ return p;
++ }
++ } while (++p <= end);
++
++ return NULL;
++}
+diff -urN nginx/src/core/ngx_zm_lookup.h nginx/src/core/ngx_zm_lookup.h
+--- nginx/src/core/ngx_zm_lookup.h 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/core/ngx_zm_lookup.h 2023-03-04 13:25:59.843350100 +0530
+@@ -0,0 +1,207 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#ifndef _NGX_ZM_LOOKUP_H_INCLUDED_
++#define _NGX_ZM_LOOKUP_H_INCLUDED_
++
++#include
++#include
++#include
++#include
++
++#define NGX_ZM_LOOKUP_CONF 0x02000000
++
++typedef struct {
++ ngx_addr_t *peer;
++ ngx_str_t host;
++ ngx_str_t uri;
++ time_t failure_time; /* the time of last connection failure
++ to this handler peer, 0 means the
++ peer is now available */
++ ngx_uint_t ssl; /* whether handler talks SSL or plain http */
++} ngx_zm_lookup_handler_t;
++
++typedef struct {
++ ngx_pool_t *pool; /* main pool where self resides */
++ ngx_log_t *log;
++ ngx_array_t handlers; /* ngx_zm_lookup_handler_t*[] */
++ ngx_uint_t handler_index; /* current index of round robin */
++ ngx_msec_t retry_interval; /* time to retry to connect a handler after a failure (in ms) */
++ ngx_msec_t timeout; /* timeout to fetch the result from nginx lookup handler (in ms) */
++ ngx_str_t master_auth_username;
++ ngx_str_t master_auth_password;
++ ngx_str_t url;
++ ngx_flag_t caching; /* whether to add and check the alias/route in memcache */
++ ngx_flag_t allow_unqualified; /* whether to append client ip to the "account-->route" caching key,
++ when the alias part is an unqualified name*/
++ size_t buffer_size;
++ ngx_ssl_t *ssl;
++} ngx_zm_lookup_conf_t;
++
++struct ngx_zm_lookup_work_s;
++
++typedef void (*ngx_zm_lookup_callback)(struct ngx_zm_lookup_work_s *);
++
++/* zmauth type */
++typedef enum {
++ zmauth_web_client,
++ zmauth_admin_console,
++ zmauth_zx
++} ngx_http_zmauth_t;
++
++
++struct ngx_zm_lookup_work_s {
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++
++ /* input */
++ ngx_str_t username; /* the original username given by user */
++ ngx_str_t auth_id; /* GSSAPI auth id (principal) */
++
++ ngx_http_zmauth_t type; /* whether is web, admin or /zx/ */
++
++ ngx_uint_t protocol:3; /* protocol */
++ ngx_uint_t auth_method:4; /* auth method */
++ ngx_uint_t alias_check_stat:2; /* the alias-->account caching lookup status */
++ ngx_uint_t login_attempts; /* only used for mail */
++ ngx_str_t virtual_host; /* only used for web */
++ ngx_connection_t * connection; /* client connection */
++ ngx_str_t salt; /* only used for mail */
++ ngx_str_t route_key; /* the key for "account-->route" cache */
++
++ /* output */
++ ngx_addr_t *route; /* fetched route */
++ ngx_str_t err; /* error message */
++ time_t wait_time; /* wait time if login failed */
++
++ /* input & output */
++ ngx_str_t zm_auth_token; /* for web route lookup, this will be input;
++ for client cert auth, this will be output
++ */
++ ngx_str_t account_name; /* for mail route lookup, account name is
++ always returned
++ */
++ ngx_str_t alias_key; /* the key for "alias-->account" cache */
++
++ ngx_zm_lookup_callback on_success;
++ ngx_zm_lookup_callback on_failure;
++
++ ngx_int_t result;
++
++ void *data; /* context such as http request or mail session */
++ void *ctx; /* zm_lookup_ctx */
++};
++
++typedef struct ngx_zm_lookup_work_s ngx_zm_lookup_work_t;
++
++extern ngx_module_t ngx_zm_lookup_module;
++
++struct ngx_zm_lookup_ctx_s;
++
++typedef void (*ngx_zm_lookup_response_handler_t) (struct ngx_zm_lookup_ctx_s * ctx);
++
++struct ngx_zm_lookup_ctx_s {
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++
++ /* for lookup handler elect */
++ ngx_uint_t tries;
++ ngx_uint_t handler_index;
++
++ ngx_zm_lookup_handler_t *handler; /*current handler to be used */
++ ngx_peer_connection_t peer;
++
++ /* for request send & response processing */
++ ngx_buf_t *lookup_req; /* lookup request buffer */
++ ngx_buf_t *lookup_resp; /* lookup response buffer */
++ ngx_uint_t state; /* response parse state */
++ u_char *header_name_start;
++ u_char *header_name_end;
++ u_char *header_start;
++ u_char *header_end;
++ ngx_zm_lookup_response_handler_t lookup_response_handler;
++
++ ngx_zm_lookup_work_t *work;
++
++ ngx_uint_t wait_memcache; /* whether memcache request is
++ posted but response doesn't come */
++ ngx_event_t *wait_ev;
++};
++
++typedef struct ngx_zm_lookup_ctx_s ngx_zm_lookup_ctx_t;
++
++/* lookup result */
++#define ZM_LOOKUP_SUCCESS 0
++#define ZM_LOOKUP_MEM_ALLOC_ERROR 1
++#define ZM_LOOKUP_WRITE_ERROR 2
++#define ZM_LOOKUP_READ_ERROR 3
++#define ZM_LOOKUP_WRITE_TIMEOUT 4
++#define ZM_LOOKUP_READ_TIMEOUT 5
++#define ZM_LOOKUP_NO_VALID_HANDLER 6
++#define ZM_LOOKUP_INVALID_ROUTE 7
++#define ZM_LOOKUP_LOGIN_FAILED 8
++#define ZM_LOOKUP_INVALID_RESPONSE 9
++#define ZM_LOOKUP_CLIENT_CONNECTION_CLOSE 10
++#define ZM_LOOKUP_OTHER_ERROR 50
++#define ZM_LOOKUP_SSL_EVENT_SUCCESS 0
++#define ZM_LOOKUP_SSL_EVENT_FAILED 1
++
++/* the protocols nginx lookup can serve for */
++#define ZM_PROTO_UNKNOWN 0
++#define ZM_PROTO_HTTP 1
++#define ZM_PROTO_HTTPS 2
++#define ZM_PROTO_POP3 3
++#define ZM_PROTO_POP3S 4
++#define ZM_PROTO_IMAP 5
++#define ZM_PROTO_IMAPS 6
++
++#define IS_PROTO_MAIL(proto) (proto == ZM_PROTO_POP3 || \
++ proto == ZM_PROTO_POP3S || \
++ proto == ZM_PROTO_IMAP || \
++ proto == ZM_RPOTO_IMAPS)
++
++#define IS_PROTO_WEB(proto) (proto == ZM_PROTO_HTTP || \
++ proto == ZM_PROTO_HTTPS)
++
++/* alias-->account caching check state */
++#define ZM_ALIAS_NOT_CHECKED 0 /* need to be checked but not done yet */
++#define ZM_ALIAS_FOUND 1 /* has been checked and found */
++#define ZM_ALIAS_NOT_FOUND 2 /* has been checked and not found */
++#define ZM_ALIAS_IGNORED 3 /* has been checked and found, but ignored */
++
++/* the auth method supported */
++#define ZM_AUTHMETH_USERNAME 0 /* get route by user name */
++#define ZM_AUTHMETH_GSSAPI 1 /* get route and account id by kerberos v5 */
++#define ZM_AUTHMETH_ZIMBRAID 2 /* get route by zimbra account id */
++#define ZM_AUTHMETH_CERTAUTH 3 /* get account id by client certificate */
++
++#define IS_LOOKUP_ROUTE(auth_meth) (!(auth_meth == ZM_AUTHMETH_CERTAUTH))
++
++void ngx_zm_lookup(ngx_zm_lookup_work_t * work);
++void ngx_zm_lookup_delete_cache(ngx_str_t alias_key, ngx_str_t route_key);
++void ngx_zm_lookup_finalize(ngx_zm_lookup_work_t * work);
++ngx_flag_t ngx_zm_lookup_check_broken_connection(ngx_event_t *ev,
++ ngx_zm_lookup_work_t *work);
++
++/* utility */
++ngx_flag_t is_login_qualified (ngx_str_t login);
++
++/* memcache key create */
++ngx_str_t ngx_zm_lookup_get_http_alias_key(ngx_pool_t *pool,
++ ngx_log_t *log, ngx_str_t alias, ngx_str_t vhost);
++ngx_str_t ngx_zm_lookup_get_mail_alias_key(ngx_pool_t *pool,
++ ngx_log_t *log, ngx_str_t user, ngx_str_t ip);
++
++#endif
diff --git a/thirdparty/nginx/patches/nginx_src_event.patch b/thirdparty/nginx/patches/nginx_src_event.patch
new file mode 100644
index 000000000..b790f61b1
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_event.patch
@@ -0,0 +1,45 @@
+diff -urN nginx/src/event/ngx_event_openssl.c nginx/src/event/ngx_event_openssl.c
+--- nginx/src/event/ngx_event_openssl.c 2023-10-01 23:06:48.920736200 +0530
++++ nginx/src/event/ngx_event_openssl.c 2023-10-01 23:19:50.724583800 +0530
+@@ -3203,9 +3203,9 @@
+ ngx_uint_t tries;
+
+ rc = NGX_OK;
+-
+- ngx_ssl_ocsp_cleanup(c);
+-
++// Zimbra customizations start here (Jira Tickets: )
++// ngx_ssl_ocsp_cleanup(c);
++// Zimbra customizations end here
+ if (SSL_in_init(c->ssl->connection)) {
+ /*
+ * OpenSSL 1.0.2f complains if SSL_shutdown() is called during
+@@ -3216,6 +3216,9 @@
+ goto done;
+ }
+
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_ssl_ocsp_cleanup(c);
++// Zimbra customizations end here
+ if (c->timedout || c->error || c->buffered) {
+ mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
+ SSL_set_quiet_shutdown(c->ssl->connection, 1);
+diff -urN nginx/src/event/ngx_event_udp.h nginx/src/event/ngx_event_udp.h
+--- nginx/src/event/ngx_event_udp.h 2023-08-18 17:02:49.289936600 +0530
++++ nginx/src/event/ngx_event_udp.h 2023-09-19 12:57:46.301787700 +0530
+@@ -33,10 +33,11 @@
+ #if (NGX_HAVE_IP_PKTINFO)
+ struct in_pktinfo pkt;
+ #endif
+-
+-#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
+- struct in6_pktinfo pkt6;
+-#endif
++// AMB : Code is commented in order to move compilation forward and detect any errors that arise.
++// See https://trac.nginx.org/nginx/ticket/2312
++//#if (NGX_HAVE_INET6 && NGX_HAVE_IPV6_RECVPKTINFO)
++// struct in6_pktinfo pkt6;
++//#endif
+ } ngx_addrinfo_t;
+
+ size_t ngx_set_srcaddr_cmsg(struct cmsghdr *cmsg,
diff --git a/thirdparty/nginx/patches/nginx_src_http.patch b/thirdparty/nginx/patches/nginx_src_http.patch
new file mode 100644
index 000000000..675e1b47e
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_http.patch
@@ -0,0 +1,1687 @@
+diff -urN nginx/src/http/ngx_http.h nginx/src/http/ngx_http.h
+--- nginx/src/http/ngx_http.h 2023-08-18 17:02:49.306835700 +0530
++++ nginx/src/http/ngx_http.h 2023-09-14 18:47:12.444732400 +0530
+@@ -32,6 +32,9 @@
+ #include
+ #include
+ #include
++// Zimbra customizations start here (Jira Tickets: )
++#include
++// Zimbra customizations end here
+ #include
+ #include
+
+diff -urN nginx/src/http/ngx_http_core_module.c nginx/src/http/ngx_http_core_module.c
+--- nginx/src/http/ngx_http_core_module.c 2023-08-18 17:02:49.309830000 +0530
++++ nginx/src/http/ngx_http_core_module.c 2023-10-02 01:02:04.912075500 +0530
+@@ -777,7 +777,14 @@
+ NULL },
+
+ #endif
+-
++// Zimbra customizations start here (Jira Tickets: )
++ { ngx_string("exact_version_check"),
++ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
++ ngx_conf_set_flag_slot,
++ NGX_HTTP_LOC_CONF_OFFSET,
++ offsetof(ngx_http_core_loc_conf_t, exact_version_check),
++ NULL },
++// Zimbra customizations end here
+ ngx_null_command
+ };
+
+@@ -3630,7 +3637,9 @@
+ clcf->open_file_cache_min_uses = NGX_CONF_UNSET_UINT;
+ clcf->open_file_cache_errors = NGX_CONF_UNSET;
+ clcf->open_file_cache_events = NGX_CONF_UNSET;
+-
++// Zimbra customizations start here (Jira Tickets: )
++ clcf->exact_version_check = NGX_CONF_UNSET;
++// Zimbra customizations end here
+ #if (NGX_HTTP_GZIP)
+ clcf->gzip_vary = NGX_CONF_UNSET;
+ clcf->gzip_http_version = NGX_CONF_UNSET_UINT;
+diff -urN nginx/src/http/ngx_http_core_module.h nginx/src/http/ngx_http_core_module.h
+--- nginx/src/http/ngx_http_core_module.h 2023-08-18 17:02:49.313817300 +0530
++++ nginx/src/http/ngx_http_core_module.h 2023-10-02 01:02:51.567052200 +0530
+@@ -404,6 +404,9 @@
+ ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */
+ ngx_flag_t etag; /* etag */
+
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_flag_t exact_version_check; /* added by zimbra for version check */
++// Zimbra customizations end here
+ #if (NGX_HTTP_GZIP)
+ ngx_flag_t gzip_vary; /* gzip_vary */
+
+diff -urN nginx/src/http/ngx_http_upstream.c nginx/src/http/ngx_http_upstream.c
+--- nginx/src/http/ngx_http_upstream.c 2023-08-18 17:02:49.329775600 +0530
++++ nginx/src/http/ngx_http_upstream.c 2023-10-02 01:18:32.519472600 +0530
+@@ -8,7 +8,9 @@
+ #include
+ #include
+ #include
+-
++// Zimbra customizations start here (Jira Tickets: )
++#include
++// Zimbra customizations end here
+
+ #if (NGX_HTTP_CACHE)
+ static ngx_int_t ngx_http_upstream_cache(ngx_http_request_t *r,
+@@ -546,6 +548,9 @@
+ {
+ ngx_str_t *host;
+ ngx_uint_t i;
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_int_t rc;
++// Zimbra customizations end here
+ ngx_resolver_ctx_t *ctx, temp;
+ ngx_http_cleanup_t *cln;
+ ngx_http_upstream_t *u;
+@@ -794,8 +799,11 @@
+ #if (NGX_HTTP_SSL)
+ u->ssl_name = uscf->host;
+ #endif
+-
+- if (uscf->peer.init(r, uscf) != NGX_OK) {
++// Zimbra customizations start here (Jira Tickets: )
++ rc = uscf->peer.init(r, uscf);
++ if (rc != NGX_OK) {
++ if (rc == NGX_AGAIN) return; /* added by zimbra to support async peer init */
++// Zimbra customizations start here (Jira Tickets: )
+ ngx_http_upstream_finalize_request(r, u,
+ NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+@@ -1552,7 +1560,9 @@
+ }
+
+ if (rc == NGX_DECLINED) {
+- ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_HTTP_403);
++// Zimbra customizations end here
+ return;
+ }
+
+@@ -1682,6 +1692,9 @@
+ return;
+ }
+
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_http_upstream_rr_peer_data_t *rrp = (ngx_http_upstream_rr_peer_data_t *)(u->peer.data);
++// Zimbra customizations end here
+ if (u->conf->ssl_server_name || u->conf->ssl_verify) {
+ if (ngx_http_upstream_ssl_name(r, u, c) != NGX_OK) {
+ ngx_http_upstream_finalize_request(r, u,
+@@ -1701,8 +1714,9 @@
+ return;
+ }
+ }
+-
+- if (u->conf->ssl_session_reuse) {
++// Zimbra customizations start here (Jira Tickets: )
++ if (u->conf->ssl_session_reuse && rrp->current != NGX_INVALID_ARRAY_INDEX) {
++// Zimbra customizations end here
+ c->ssl->save_session = ngx_http_upstream_ssl_save_session;
+
+ if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
+@@ -4302,7 +4316,9 @@
+ {
+ ngx_msec_t timeout;
+ ngx_uint_t status, state;
+-
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_zm_lookup_conf_t *zlcf;
++// Zimbra customizations end here
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http next upstream, %xi", ft_type);
+
+@@ -4386,11 +4402,19 @@
+ {
+ ft_type |= NGX_HTTP_UPSTREAM_FT_NON_IDEMPOTENT;
+ }
+-
++// Zimbra customizations start here (Jira Tickets: )
++ zlcf = (ngx_zm_lookup_conf_t *)
++ ngx_get_conf (ngx_cycle->conf_ctx, ngx_zm_lookup_module);
++// Zimbra customizations end here
+ if (u->peer.tries == 0
+ || ((u->conf->next_upstream & ft_type) != ft_type)
+ || (u->request_sent && r->request_body_no_buffering)
+- || (timeout && ngx_current_msec - u->peer.start_time >= timeout))
++// Zimbra customizations start here (Jira Tickets: )
++ || (timeout && ngx_current_msec - u->peer.start_time >= timeout)
++ || (r->method == NGX_HTTP_POST && !((r->uri.len == 1 &&
++ r->uri.data[r->uri.len - 1] == '/') ||
++ (ngx_strncasecmp(r->uri.data, zlcf->url.data, zlcf->url.len) == 0))))
++// Zimbra customizations end here
+ {
+ #if (NGX_HTTP_CACHE)
+
+@@ -6034,7 +6058,10 @@
+ |NGX_HTTP_UPSTREAM_MAX_FAILS
+ |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
+ |NGX_HTTP_UPSTREAM_DOWN
+- |NGX_HTTP_UPSTREAM_BACKUP);
++ |NGX_HTTP_UPSTREAM_BACKUP
++// Zimbra customizations start here (Jira Tickets: )
++ |NGX_HTTP_UPSTREAM_VERSION);
++// Zimbra customizations end here
+ if (uscf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+@@ -6120,6 +6147,9 @@
+ return NGX_CONF_ERROR;
+ }
+
++// Zimbra customizations start here (Jira Tickets: ) /* added by zimbra to support async upstream peer choose */
++ uscf->connect = ngx_http_upstream_connect;
++// Zimbra customizations end here
+ return rv;
+ }
+
+@@ -6130,7 +6160,9 @@
+ ngx_http_upstream_srv_conf_t *uscf = conf;
+
+ time_t fail_timeout;
+- ngx_str_t *value, s;
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_str_t *value, s, version;
++// Zimbra customizations end here
+ ngx_url_t u;
+ ngx_int_t weight, max_conns, max_fails;
+ ngx_uint_t i;
+@@ -6149,7 +6181,10 @@
+ max_conns = 0;
+ max_fails = 1;
+ fail_timeout = 10;
+-
++// Zimbra customizations start here (Jira Tickets: )
++ version.len = 0;
++ version.data = NULL;
++// Zimbra customizations end here
+ for (i = 2; i < cf->args->nelts; i++) {
+
+ if (ngx_strncmp(value[i].data, "weight=", 7) == 0) {
+@@ -6236,7 +6271,21 @@
+
+ continue;
+ }
++// Zimbra customizations start here (Jira Tickets: )
++ if (ngx_strncmp(value[i].data, "version=", 8) == 0) {
+
++ if (!(uscf->flags & NGX_HTTP_UPSTREAM_VERSION)) {
++ goto invalid;
++ }
++
++ s.len = value[i].len - 8;
++ s.data = &value[i].data[8];
++
++ version = s;
++
++ continue;
++ }
++// Zimbra customizations end here
+ goto invalid;
+ }
+
+@@ -6261,7 +6310,9 @@
+ us->max_conns = max_conns;
+ us->max_fails = max_fails;
+ us->fail_timeout = fail_timeout;
+-
++// Zimbra customizations start here (Jira Tickets: )
++ us->version = version;
++// Zimbra customizations start here (Jira Tickets: )
+ return NGX_CONF_OK;
+
+ invalid:
+diff -urN nginx/src/http/ngx_http_upstream.h nginx/src/http/ngx_http_upstream.h
+--- nginx/src/http/ngx_http_upstream.h 2023-07-23 13:21:27.083727300 +0530
++++ nginx/src/http/ngx_http_upstream.h 2023-09-14 18:47:12.557564900 +0530
+@@ -99,6 +99,9 @@
+ ngx_uint_t max_conns;
+ ngx_uint_t max_fails;
+ time_t fail_timeout;
++// Zimbra customizations start here (Jira Tickets: )
++ ngx_str_t version;
++// Zimbra customizations end here
+ ngx_msec_t slow_start;
+ ngx_uint_t down;
+
+@@ -115,6 +118,9 @@
+ #define NGX_HTTP_UPSTREAM_FAIL_TIMEOUT 0x0008
+ #define NGX_HTTP_UPSTREAM_DOWN 0x0010
+ #define NGX_HTTP_UPSTREAM_BACKUP 0x0020
++// Zimbra customizations start here (Jira Tickets: )
++#define NGX_HTTP_UPSTREAM_VERSION 0x0040
++// Zimbra customizations end here
+ #define NGX_HTTP_UPSTREAM_MAX_CONNS 0x0100
+
+
+@@ -131,6 +137,9 @@
+ in_port_t port;
+ ngx_uint_t no_port; /* unsigned no_port:1 */
+
++// Zimbra customizations start here (Jira Tickets: ) // added by zimbra to support async upstream peer init
++ void (* connect)(ngx_http_request_t *r, ngx_http_upstream_t *u);
++// Zimbra customizations end here
+ #if (NGX_HTTP_UPSTREAM_ZONE)
+ ngx_shm_zone_t *shm_zone;
+ #endif
+diff -urN nginx/src/http/ngx_http_upstream_fair.c nginx/src/http/ngx_http_upstream_fair.c
+--- nginx/src/http/ngx_http_upstream_fair.c 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/http/ngx_http_upstream_fair.c 2023-03-04 13:25:59.915137900 +0530
+@@ -0,0 +1,1295 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#include
++#include
++#include
++
++#if 0
++static char *ngx_http_upstream_fair(ngx_conf_t *cf, ngx_command_t *cmd,
++ void *conf);
++static ngx_chain_t *ngx_http_upstream_fair_report_status(ngx_http_request_t *r,
++ ngx_int_t *length);
++#endif
++
++#if (NGX_HTTP_SSL)
++static ngx_int_t ngx_http_upstream_fair_set_session(ngx_peer_connection_t *pc,
++ void *data);
++static void ngx_http_upstream_fair_save_session(ngx_peer_connection_t *pc,
++ void *data);
++#endif
++
++static ngx_http_module_t ngx_http_upstream_fair_module_ctx = {
++ NULL, /* preconfiguration */
++ NULL, /* postconfiguration */
++
++ NULL, /* create main configuration */
++ NULL, /* init main configuration */
++
++ NULL, /* create server configuration */
++ NULL, /* merge server configuration */
++
++ NULL, /* create location configuration */
++ NULL, /* merge location configuration */
++
++#if 0
++ ngx_http_upstream_fair_report_status,
++#endif
++};
++
++
++ngx_module_t ngx_http_upstream_fair_module = {
++ NGX_MODULE_V1,
++ &ngx_http_upstream_fair_module_ctx, /* module context */
++ NULL, /* 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
++};
++
++static ngx_uint_t ngx_http_upstream_fair_shm_size;
++static ngx_shm_zone_t * ngx_http_upstream_fair_shm_zone;
++static ngx_rbtree_t * ngx_http_upstream_fair_rbtree;
++static ngx_uint_t ngx_http_upstream_fair_generation;
++
++ngx_uint_t *shm_size = &ngx_http_upstream_fair_shm_size;
++
++static int
++ngx_http_upstream_fair_compare_rbtree_node(const ngx_rbtree_node_t *v_left,
++ const ngx_rbtree_node_t *v_right)
++{
++ ngx_http_upstream_fair_shm_block_t *left, *right;
++
++ left = (ngx_http_upstream_fair_shm_block_t *) v_left;
++ right = (ngx_http_upstream_fair_shm_block_t *) v_right;
++
++ if (left->generation < right->generation) {
++ return -1;
++ } else if (left->generation > right->generation) {
++ return 1;
++ } else { /* left->generation == right->generation */
++ if (left->peers < right->peers) {
++ return -1;
++ } else if (left->peers > right->peers) {
++ return 1;
++ } else {
++ return 0;
++ }
++ }
++}
++
++/*
++ * generic functions start here
++ */
++static void
++ngx_rbtree_generic_insert(ngx_rbtree_node_t *temp,
++ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel,
++ int (*compare)(const ngx_rbtree_node_t *left, const ngx_rbtree_node_t *right))
++{
++ for ( ;; ) {
++ if (node->key < temp->key) {
++
++ if (temp->left == sentinel) {
++ temp->left = node;
++ break;
++ }
++
++ temp = temp->left;
++
++ } else if (node->key > temp->key) {
++
++ if (temp->right == sentinel) {
++ temp->right = node;
++ break;
++ }
++
++ temp = temp->right;
++
++ } else { /* node->key == temp->key */
++ if (compare(node, temp) < 0) {
++
++ if (temp->left == sentinel) {
++ temp->left = node;
++ break;
++ }
++
++ temp = temp->left;
++
++ } else {
++
++ if (temp->right == sentinel) {
++ temp->right = node;
++ break;
++ }
++
++ temp = temp->right;
++ }
++ }
++ }
++
++ node->parent = temp;
++ node->left = sentinel;
++ node->right = sentinel;
++ ngx_rbt_red(node);
++}
++
++#define NGX_BITVECTOR_ELT_SIZE (sizeof(uintptr_t) * 8)
++
++static uintptr_t *
++ngx_bitvector_alloc(ngx_pool_t *pool, ngx_uint_t size, uintptr_t *small)
++{
++ ngx_uint_t nelts = (size + NGX_BITVECTOR_ELT_SIZE - 1) / NGX_BITVECTOR_ELT_SIZE;
++
++ if (small && nelts == 1) {
++ *small = 0;
++ return small;
++ }
++
++ return ngx_pcalloc(pool, nelts * NGX_BITVECTOR_ELT_SIZE);
++}
++
++static ngx_int_t
++ngx_bitvector_test(uintptr_t *bv, ngx_uint_t bit)
++{
++ ngx_uint_t n, m;
++
++ n = bit / NGX_BITVECTOR_ELT_SIZE;
++ m = 1 << (bit % NGX_BITVECTOR_ELT_SIZE);
++
++ return bv[n] & m;
++}
++
++static void
++ngx_bitvector_set(uintptr_t *bv, ngx_uint_t bit)
++{
++ ngx_uint_t n, m;
++
++ n = bit / NGX_BITVECTOR_ELT_SIZE;
++ m = 1 << (bit % NGX_BITVECTOR_ELT_SIZE);
++
++ bv[n] |= m;
++}
++
++/*
++ * generic functions end here
++ */
++
++static void
++ngx_http_upstream_fair_rbtree_insert(ngx_rbtree_node_t *temp,
++ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) {
++
++ ngx_rbtree_generic_insert(temp, node, sentinel,
++ ngx_http_upstream_fair_compare_rbtree_node);
++}
++
++
++static ngx_int_t
++ngx_http_upstream_fair_init_shm_zone(ngx_shm_zone_t *shm_zone, void *data)
++{
++ ngx_slab_pool_t *shpool;
++ ngx_rbtree_t *tree;
++ ngx_rbtree_node_t *sentinel;
++
++ if (data) {
++ shm_zone->data = data;
++ return NGX_OK;
++ }
++
++ shpool = (ngx_slab_pool_t *) shm_zone->shm.addr;
++ tree = ngx_slab_alloc(shpool, sizeof *tree);
++ if (tree == NULL) {
++ return NGX_ERROR;
++ }
++
++ sentinel = ngx_slab_alloc(shpool, sizeof *sentinel);
++ if (sentinel == NULL) {
++ return NGX_ERROR;
++ }
++
++ ngx_rbtree_sentinel_init(sentinel);
++ tree->root = sentinel;
++ tree->sentinel = sentinel;
++ tree->insert = ngx_http_upstream_fair_rbtree_insert;
++ shm_zone->data = tree;
++ ngx_http_upstream_fair_rbtree = tree;
++
++ return NGX_OK;
++}
++
++#if 0
++static char *
++ngx_http_upstream_fair(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ ngx_http_upstream_srv_conf_t *uscf;
++ ngx_uint_t i;
++ ngx_uint_t extra_peer_flags = 0;
++
++ for (i = 1; i < cf->args->nelts; i++) {
++ ngx_str_t *value = cf->args->elts;
++ if (ngx_strcmp(value[i].data, "no_rr") == 0) {
++ extra_peer_flags |= NGX_HTTP_UPSTREAM_FAIR_NO_RR;
++ } else if (ngx_strcmp(value[i].data, "weight_mode=peak") == 0) {
++ if (extra_peer_flags & NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_MASK) {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "weight_mode= options are mutually exclusive");
++ return NGX_CONF_ERROR;
++ }
++ extra_peer_flags |= NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_PEAK;
++ } else if (ngx_strcmp(value[i].data, "weight_mode=idle") == 0) {
++ if (extra_peer_flags & NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_MASK) {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "weight_mode= options are mutually exclusive");
++ return NGX_CONF_ERROR;
++ }
++ extra_peer_flags |= NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_IDLE;
++ } else {
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "Invalid `fair' parameter `%V'", &value[i]);
++ return NGX_CONF_ERROR;
++ }
++ }
++
++ uscf = ngx_http_conf_get_module_srv_conf(cf, ngx_http_upstream_module);
++
++ uscf->peer.init_upstream = ngx_http_upstream_init_fair;
++
++ uscf->flags = NGX_HTTP_UPSTREAM_CREATE
++ |NGX_HTTP_UPSTREAM_WEIGHT
++ |NGX_HTTP_UPSTREAM_MAX_FAILS
++ |NGX_HTTP_UPSTREAM_FAIL_TIMEOUT
++ |NGX_HTTP_UPSTREAM_DOWN
++ |NGX_HTTP_UPSTREAM_VERSION
++ |extra_peer_flags;
++
++ return NGX_CONF_OK;
++}
++#endif
++
++static ngx_int_t
++ngx_http_upstream_cmp_servers(const void *one, const void *two)
++{
++ const ngx_http_upstream_fair_peer_t *first, *second;
++
++ first = one;
++ second = two;
++
++ return (first->weight < second->weight);
++}
++
++
++/* TODO: Actually support backup servers */
++static ngx_int_t
++ngx_http_upstream_init_fair_rr(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
++{
++ ngx_url_t u;
++ ngx_uint_t i, j, n;
++ ngx_http_upstream_server_t *server;
++ ngx_http_upstream_fair_peers_t *peers, *backup;
++
++ if (us->servers) {
++ server = us->servers->elts;
++
++ n = 0;
++
++ for (i = 0; i < us->servers->nelts; i++) {
++ if (server[i].backup) {
++ continue;
++ }
++
++ n += server[i].naddrs;
++ }
++
++ peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_fair_peers_t)
++ + sizeof(ngx_http_upstream_fair_peer_t) * (n - 1));
++ if (peers == NULL) {
++ return NGX_ERROR;
++ }
++
++ peers->number = n;
++ peers->name = &us->host;
++
++ n = 0;
++
++ for (i = 0; i < us->servers->nelts; i++) {
++ for (j = 0; j < server[i].naddrs; j++) {
++ if (server[i].backup) {
++ continue;
++ }
++
++ peers->peer[n].sockaddr = server[i].addrs[j].sockaddr;
++ peers->peer[n].socklen = server[i].addrs[j].socklen;
++ peers->peer[n].name = server[i].addrs[j].name;
++ peers->peer[n].max_fails = server[i].max_fails;
++ peers->peer[n].fail_timeout = server[i].fail_timeout;
++ peers->peer[n].down = server[i].down;
++ peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
++ peers->peer[n].version = server[i].version;
++ n++;
++ }
++ }
++
++ us->peer.data = peers;
++
++ ngx_sort(&peers->peer[0], (size_t) n,
++ sizeof(ngx_http_upstream_fair_peer_t),
++ ngx_http_upstream_cmp_servers);
++
++ /* backup servers */
++
++ n = 0;
++
++ for (i = 0; i < us->servers->nelts; i++) {
++ if (!server[i].backup) {
++ continue;
++ }
++
++ n += server[i].naddrs;
++ }
++
++ if (n == 0) {
++ return NGX_OK;
++ }
++
++ backup = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_fair_peers_t)
++ + sizeof(ngx_http_upstream_fair_peer_t) * (n - 1));
++ if (backup == NULL) {
++ return NGX_ERROR;
++ }
++
++ backup->number = n;
++ backup->name = &us->host;
++
++ n = 0;
++
++ for (i = 0; i < us->servers->nelts; i++) {
++ for (j = 0; j < server[i].naddrs; j++) {
++ if (!server[i].backup) {
++ continue;
++ }
++
++ backup->peer[n].sockaddr = server[i].addrs[j].sockaddr;
++ backup->peer[n].socklen = server[i].addrs[j].socklen;
++ backup->peer[n].name = server[i].addrs[j].name;
++ backup->peer[n].weight = server[i].weight;
++ backup->peer[n].max_fails = server[i].max_fails;
++ backup->peer[n].fail_timeout = server[i].fail_timeout;
++ backup->peer[n].down = server[i].down;
++ backup->peer[n].version = server[i].version;
++ n++;
++ }
++ }
++
++ peers->next = backup;
++
++ ngx_sort(&backup->peer[0], (size_t) n,
++ sizeof(ngx_http_upstream_fair_peer_t),
++ ngx_http_upstream_cmp_servers);
++
++ return NGX_OK;
++ }
++
++
++ /* an upstream implicitly defined by proxy_pass, etc. */
++
++ if (us->port == 0) {
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "no port in upstream \"%V\" in %s:%ui",
++ &us->host, us->file_name, us->line);
++ return NGX_ERROR;
++ }
++
++ ngx_memzero(&u, sizeof(ngx_url_t));
++
++ u.host = us->host;
++ u.port = (in_port_t) us->port;
++
++ if (ngx_inet_resolve_host(cf->pool, &u) != NGX_OK) {
++ if (u.err) {
++ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
++ "%s in upstream \"%V\" in %s:%ui",
++ u.err, &us->host, us->file_name, us->line);
++ }
++
++ return NGX_ERROR;
++ }
++
++ n = u.naddrs;
++
++ peers = ngx_pcalloc(cf->pool, sizeof(ngx_http_upstream_fair_peers_t)
++ + sizeof(ngx_http_upstream_fair_peer_t) * (n - 1));
++ if (peers == NULL) {
++ return NGX_ERROR;
++ }
++
++ peers->number = n;
++ peers->name = &us->host;
++
++ for (i = 0; i < u.naddrs; i++) {
++ peers->peer[i].sockaddr = u.addrs[i].sockaddr;
++ peers->peer[i].socklen = u.addrs[i].socklen;
++ peers->peer[i].name = u.addrs[i].name;
++ peers->peer[i].weight = 1;
++ peers->peer[i].max_fails = 1;
++ peers->peer[i].fail_timeout = 10;
++ peers->peer[n].version.len = 0;
++ peers->peer[n].version.data = NULL;
++ }
++
++ us->peer.data = peers;
++
++ /* implicitly defined upstream has no backup servers */
++
++ return NGX_OK;
++}
++
++ngx_int_t
++ngx_http_upstream_init_fair(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
++{
++ ngx_http_upstream_fair_peers_t *peers;
++ ngx_uint_t n;
++ ngx_str_t *shm_name;
++
++ /* do the dirty work using rr module */
++ if (ngx_http_upstream_init_fair_rr(cf, us) != NGX_OK) {
++ return NGX_ERROR;
++ }
++
++ /* setup our wrapper around rr */
++ peers = ngx_palloc(cf->pool, sizeof *peers);
++ if (peers == NULL) {
++ return NGX_ERROR;
++ }
++ peers = us->peer.data;
++ n = peers->number;
++
++ shm_name = ngx_palloc(cf->pool, sizeof *shm_name);
++ shm_name->len = sizeof("upstream_fair") - 1;
++ shm_name->data = (unsigned char *) "upstream_fair";
++
++ if (ngx_http_upstream_fair_shm_size == 0) {
++ ngx_log_error(NGX_LOG_DEBUG_ZIMBRA, cf->log, 0, "The upstream_fair_shm_size is 0. The upstream_fair_shm_size value must be at least %udKiB", (8 * ngx_pagesize) >> 10);
++ ngx_http_upstream_fair_shm_size = 8 * ngx_pagesize;
++ }
++
++ ngx_log_error(NGX_LOG_DEBUG_ZIMBRA, cf->log, 0, "The upstream_fair_shm_size value is %udKiB", ngx_http_upstream_fair_shm_size >> 10);
++
++ ngx_http_upstream_fair_shm_zone = ngx_shared_memory_add(
++ cf, shm_name, ngx_http_upstream_fair_shm_size, &ngx_http_upstream_fair_module);
++ if (ngx_http_upstream_fair_shm_zone == NULL) {
++ return NGX_ERROR;
++ }
++ ngx_http_upstream_fair_shm_zone->init = ngx_http_upstream_fair_init_shm_zone;
++
++ peers->shared = NULL;
++ peers->current = n - 1;
++ peers->no_rr = 1;
++ peers->weight_mode = WM_PEAK;
++ peers->size_err = 0;
++ ngx_http_upstream_fair_generation++;
++
++ us->peer.init = ngx_http_upstream_init_fair_peer;
++
++ return NGX_OK;
++}
++
++
++static void
++ngx_http_upstream_fair_update_nreq(ngx_http_upstream_fair_peer_data_t *fp, int delta, ngx_log_t *log)
++{
++#if (NGX_DEBUG)
++ ngx_uint_t nreq;
++ ngx_uint_t total_nreq;
++
++ nreq = (fp->peers->peer[fp->current].shared->nreq += delta);
++ total_nreq = (fp->peers->shared->total_nreq += delta);
++
++ ngx_log_debug6(NGX_LOG_DEBUG_HTTP, log, 0,
++ "[upstream_fair] nreq for peer %ui @ %p/%p now %d, total %d, delta %d",
++ fp->current, fp->peers, fp->peers->peer[fp->current].shared, nreq,
++ total_nreq, delta);
++#endif
++}
++
++/*
++ * SCHED_COUNTER_BITS is the portion of an ngx_uint_t which represents
++ * the req_delta part (number of requests serviced on _other_
++ * backends). The rest (top bits) represents the number of currently
++ * processed requests.
++ *
++ * The value is not too critical because overflow is handled via
++ * saturation. With the default value of 20, scheduling is exact for
++ * fewer than 4k concurrent requests per backend (on 32-bit
++ * architectures) and fewer than 1M concurrent requests to all backends
++ * together. Beyond these limits, the algorithm essentially falls back
++ * to pure weighted round-robin.
++ *
++ * A higher score means less suitable.
++ *
++ * The `delta' parameter is bit-negated so that high values yield low
++ * scores and get chosen more often.
++ */
++
++#define SCHED_COUNTER_BITS 20
++#define SCHED_NREQ_MAX ((~0UL) >> SCHED_COUNTER_BITS)
++#define SCHED_COUNTER_MAX ((1 << SCHED_COUNTER_BITS) - 1)
++#define SCHED_SCORE(nreq,delta) (((nreq) << SCHED_COUNTER_BITS) | (~(delta) & SCHED_COUNTER_MAX))
++#define ngx_upstream_fair_min(a,b) (((a) < (b)) ? (a) : (b))
++
++static ngx_uint_t
++ngx_http_upstream_fair_sched_score(ngx_peer_connection_t *pc,
++ ngx_http_upstream_fair_peer_data_t *fp,
++ ngx_uint_t n)
++{
++ ngx_http_upstream_fair_peer_t *peer = &fp->peers->peer[n];
++ ngx_http_upstream_fair_shared_t *fs = peer->shared;
++ ngx_uint_t req_delta = fp->peers->shared->total_requests - fs->last_req_id;
++
++ /* sanity check */
++ if ((ngx_int_t)fs->nreq < 0) {
++ ngx_log_error(NGX_LOG_WARN, pc->log, 0, "[upstream_fair] upstream %ui has negative nreq (%i)", n, fs->nreq);
++ return SCHED_SCORE(0, req_delta);
++ }
++
++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] peer %ui: nreq = %i, req_delta = %ui", n, fs->nreq, req_delta);
++
++ return SCHED_SCORE(
++ ngx_upstream_fair_min(fs->nreq, SCHED_NREQ_MAX),
++ ngx_upstream_fair_min(req_delta, SCHED_COUNTER_MAX));
++}
++
++/*
++ * the core of load balancing logic
++ */
++
++static ngx_int_t
++ngx_http_upstream_fair_try_peer(ngx_peer_connection_t *pc,
++ ngx_http_upstream_fair_peer_data_t *fp,
++ ngx_uint_t peer_id)
++{
++ ngx_http_upstream_fair_peer_t *peer;
++
++ if (ngx_bitvector_test(fp->tried, peer_id))
++ return NGX_BUSY;
++
++ peer = &fp->peers->peer[peer_id];
++
++ if (!peer->down) {
++ if (peer->max_fails == 0 || peer->shared->fails < peer->max_fails) {
++ return NGX_OK;
++ }
++
++ if (ngx_time() - peer->accessed > peer->fail_timeout) {
++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] resetting fail count for peer %d, time delta %d > %d",
++ peer_id, ngx_time() - peer->accessed, peer->fail_timeout);
++ peer->shared->fails = 0;
++ return NGX_OK;
++ }
++ }
++
++ return NGX_BUSY;
++}
++
++static ngx_uint_t
++ngx_http_upstream_choose_fair_peer_idle(ngx_peer_connection_t *pc,
++ ngx_http_upstream_fair_peer_data_t *fp)
++{
++ ngx_uint_t i, n;
++ ngx_uint_t npeers = fp->peers->number;
++ ngx_uint_t weight_mode = fp->peers->weight_mode;
++ ngx_uint_t best_idx = NGX_PEER_INVALID;
++ ngx_uint_t best_nreq = ~0U;
++
++ for (i = 0, n = fp->current; i < npeers; i++, n = (n + 1) % npeers) {
++ ngx_uint_t nreq = fp->peers->peer[n].shared->nreq;
++ ngx_uint_t weight = fp->peers->peer[n].weight;
++ ngx_http_upstream_fair_peer_t *peer;
++ peer = &fp->peers->peer[n];
++
++ if (fp->peers->peer[n].shared->fails > 0)
++ continue;
++
++ if (nreq >= weight || (nreq > 0 && weight_mode != WM_IDLE)) {
++ continue;
++ }
++
++ if (ngx_http_upstream_fair_try_peer(pc, fp, n) != NGX_OK) {
++ continue;
++ }
++
++ if (ngx_http_upstream_fair_peer_version_allowed(peer, fp, pc->log) == 0) {
++ continue;
++ }
++
++ /* not in WM_IDLE+no_rr mode: the first completely idle backend gets chosen */
++ if (weight_mode != WM_IDLE || !fp->peers->no_rr) {
++ best_idx = n;
++ break;
++ }
++
++ /* in WM_IDLE+no_rr mode we actually prefer slightly loaded backends
++ * to totally idle ones, under the assumption that they're spawned
++ * on demand and can handle up to 'weight' concurrent requests
++ */
++ if (best_idx == NGX_PEER_INVALID || nreq) {
++ if (best_nreq <= nreq) {
++ continue;
++ }
++ best_idx = n;
++ best_nreq = nreq;
++ }
++ }
++
++ return best_idx;
++}
++
++static ngx_int_t
++ngx_http_upstream_choose_fair_peer_busy(ngx_peer_connection_t *pc,
++ ngx_http_upstream_fair_peer_data_t *fp)
++{
++ ngx_uint_t i, n;
++ ngx_uint_t npeers = fp->peers->number;
++ ngx_uint_t weight_mode = fp->peers->weight_mode;
++ ngx_uint_t best_idx = NGX_PEER_INVALID;
++ ngx_uint_t sched_score;
++ ngx_uint_t best_sched_score = ~0UL;
++
++ /*
++ * calculate sched scores for all the peers, choosing the lowest one
++ */
++ for (i = 0, n = fp->current; i < npeers; i++, n = (n + 1) % npeers) {
++ ngx_http_upstream_fair_peer_t *peer;
++ ngx_uint_t nreq;
++ ngx_uint_t weight;
++
++ peer = &fp->peers->peer[n];
++ nreq = fp->peers->peer[n].shared->nreq;
++
++ if (weight_mode == WM_PEAK && nreq >= peer->weight) {
++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] backend %d has nreq %ui >= weight %ui in WM_PEAK mode", n, nreq, peer->weight);
++ continue;
++ }
++
++ if (ngx_http_upstream_fair_try_peer(pc, fp, n) != NGX_OK) {
++ if (!pc->tries) {
++ ngx_log_debug(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] all backends exhausted");
++ return NGX_PEER_INVALID;
++ }
++
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] backend %d already tried", n);
++ continue;
++ }
++
++ if (ngx_http_upstream_fair_peer_version_allowed(peer, fp, pc->log) == 0) {
++ continue;
++ }
++
++ sched_score = ngx_http_upstream_fair_sched_score(pc, fp, n);
++
++ if (weight_mode == WM_DEFAULT) {
++ /*
++ * take peer weight into account
++ */
++ weight = peer->shared->current_weight;
++ if (peer->max_fails) {
++ ngx_uint_t mf = peer->max_fails;
++ weight = peer->shared->current_weight * (mf - peer->shared->fails) / mf;
++ }
++ if (weight > 0) {
++ sched_score /= weight;
++ }
++ ngx_log_debug8(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] bss = %ui, ss = %ui (n = %d, w = %d/%d, f = %d/%d, weight = %d)",
++ best_sched_score, sched_score, n, peer->shared->current_weight, peer->weight, peer->shared->fails, peer->max_fails, weight);
++ }
++
++ if (sched_score <= best_sched_score) {
++ best_idx = n;
++ best_sched_score = sched_score;
++ }
++ }
++
++ return best_idx;
++}
++
++static ngx_int_t
++ngx_http_upstream_choose_fair_peer(ngx_peer_connection_t *pc,
++ ngx_http_upstream_fair_peer_data_t *fp, ngx_uint_t *peer_id)
++{
++ ngx_uint_t npeers;
++ ngx_uint_t best_idx = NGX_PEER_INVALID;
++ ngx_uint_t weight_mode;
++
++ npeers = fp->peers->number;
++ weight_mode = fp->peers->weight_mode;
++
++ /* just a single backend */
++ if (npeers == 1) {
++ *peer_id = 0;
++ return NGX_OK;
++ }
++
++ /* any idle backends? */
++ best_idx = ngx_http_upstream_choose_fair_peer_idle(pc, fp);
++ if (best_idx != NGX_PEER_INVALID) {
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] peer %i is idle", best_idx);
++ goto chosen;
++ }
++
++ /* no idle backends, choose the least loaded one */
++ best_idx = ngx_http_upstream_choose_fair_peer_busy(pc, fp);
++ if (best_idx != NGX_PEER_INVALID) {
++ goto chosen;
++ }
++
++ return NGX_BUSY;
++
++chosen:
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] chose peer %i", best_idx);
++ *peer_id = best_idx;
++ ngx_bitvector_set(fp->tried, best_idx);
++
++ if (weight_mode == WM_DEFAULT) {
++ ngx_http_upstream_fair_peer_t *peer = &fp->peers->peer[best_idx];
++
++ if (peer->shared->current_weight-- == 0) {
++ peer->shared->current_weight = peer->weight;
++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] peer %d expired weight, reset to %d", best_idx, peer->weight);
++ }
++ }
++ return NGX_OK;
++}
++
++ngx_int_t
++ngx_http_upstream_get_fair_peer(ngx_peer_connection_t *pc, void *data)
++{
++ ngx_int_t ret;
++ ngx_uint_t peer_id, i;
++ ngx_http_upstream_fair_peer_data_t *fp = data;
++ ngx_http_upstream_fair_peer_t *peer;
++ ngx_atomic_t *lock;
++
++ peer_id = fp->current;
++ fp->current = (fp->current + 1) % fp->peers->number;
++
++ lock = &fp->peers->shared->lock;
++ ngx_spinlock(lock, ngx_pid, 1024);
++ ret = ngx_http_upstream_choose_fair_peer(pc, fp, &peer_id);
++ ngx_log_debug3(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] fp->current = %d, peer_id = %d, ret = %d",
++ fp->current, peer_id, ret);
++
++ if (pc)
++ pc->tries--;
++
++ if (ret == NGX_BUSY) {
++ for (i = 0; i < fp->peers->number; i++) {
++ fp->peers->peer[i].shared->fails = 0;
++ }
++
++ pc->name = fp->peers->name;
++ fp->current = NGX_PEER_INVALID;
++ ngx_spinlock_unlock(lock);
++ return NGX_BUSY;
++ }
++
++ /* assert(ret == NGX_OK); */
++ peer = &fp->peers->peer[peer_id];
++ fp->current = peer_id;
++ if (!fp->peers->no_rr) {
++ fp->peers->current = peer_id;
++ }
++ pc->sockaddr = peer->sockaddr;
++ pc->socklen = peer->socklen;
++ pc->name = &peer->name;
++
++ peer->shared->last_req_id = fp->peers->shared->total_requests;
++ ngx_http_upstream_fair_update_nreq(fp, 1, pc->log);
++ peer->shared->total_req++;
++ ngx_spinlock_unlock(lock);
++ return ret;
++}
++
++
++void
++ngx_http_upstream_free_fair_peer(ngx_peer_connection_t *pc, void *data,
++ ngx_uint_t state)
++{
++ ngx_http_upstream_fair_peer_data_t *fp = data;
++ ngx_http_upstream_fair_peer_t *peer;
++ ngx_atomic_t *lock;
++
++ ngx_log_debug4(NGX_LOG_DEBUG_HTTP, pc->log, 0, "[upstream_fair] fp->current = %d, state = %ui, pc->tries = %d, pc->data = %p",
++ fp->current, state, pc->tries, pc->data);
++
++ if (fp->current == NGX_PEER_INVALID) {
++ return;
++ }
++
++ lock = &fp->peers->shared->lock;
++ ngx_spinlock(lock, ngx_pid, 1024);
++ if (!ngx_bitvector_test(fp->done, fp->current)) {
++ ngx_bitvector_set(fp->done, fp->current);
++ ngx_http_upstream_fair_update_nreq(fp, -1, pc->log);
++ }
++
++ if (fp->peers->number == 1) {
++ pc->tries = 0;
++ }
++
++ if (state & NGX_PEER_FAILED) {
++ peer = &fp->peers->peer[fp->current];
++
++ peer->shared->fails++;
++ peer->accessed = ngx_time();
++ }
++ ngx_spinlock_unlock(lock);
++}
++
++/*
++ * walk through the rbtree, removing old entries and looking for
++ * a matching one -- compared by (cycle, peers) pair
++ *
++ * no attempt at optimisation is made, for two reasons:
++ * - the tree will be quite small, anyway
++ * - being called once per worker startup per upstream block,
++ * this code isn't really the hot path
++ */
++static ngx_http_upstream_fair_shm_block_t *
++ngx_http_upstream_fair_walk_shm(
++ ngx_slab_pool_t *shpool,
++ ngx_rbtree_node_t *node,
++ ngx_rbtree_node_t *sentinel,
++ ngx_http_upstream_fair_peers_t *peers)
++{
++ ngx_http_upstream_fair_shm_block_t *uf_node;
++ ngx_http_upstream_fair_shm_block_t *found_node = NULL;
++ ngx_http_upstream_fair_shm_block_t *tmp_node;
++
++ if (node == sentinel) {
++ return NULL;
++ }
++
++ /* visit left node */
++ if (node->left != sentinel) {
++ tmp_node = ngx_http_upstream_fair_walk_shm(shpool, node->left,
++ sentinel, peers);
++ if (tmp_node) {
++ found_node = tmp_node;
++ }
++ }
++
++ /* visit right node */
++ if (node->right != sentinel) {
++ tmp_node = ngx_http_upstream_fair_walk_shm(shpool, node->right,
++ sentinel, peers);
++ if (tmp_node) {
++ found_node = tmp_node;
++ }
++ }
++
++ /* visit current node */
++ uf_node = (ngx_http_upstream_fair_shm_block_t *) node;
++ if (uf_node->generation != ngx_http_upstream_fair_generation) {
++ ngx_spinlock(&uf_node->lock, ngx_pid, 1024);
++ if (uf_node->total_nreq == 0) {
++ /* don't bother unlocking */
++ ngx_rbtree_delete(ngx_http_upstream_fair_rbtree, node);
++ ngx_slab_free_locked(shpool, node);
++ }
++ ngx_spinlock_unlock(&uf_node->lock);
++ } else if (uf_node->peers == (uintptr_t) peers) {
++ found_node = uf_node;
++ }
++
++ return found_node;
++}
++
++static ngx_int_t
++ngx_http_upstream_fair_shm_alloc(ngx_http_upstream_fair_peers_t *usfp, ngx_log_t *log)
++{
++ ngx_slab_pool_t *shpool;
++ ngx_uint_t i;
++
++ if (usfp->shared) {
++ return NGX_OK;
++ }
++
++ shpool = (ngx_slab_pool_t *)ngx_http_upstream_fair_shm_zone->shm.addr;
++
++ ngx_shmtx_lock(&shpool->mutex);
++
++ usfp->shared = ngx_http_upstream_fair_walk_shm(shpool,
++ ngx_http_upstream_fair_rbtree->root,
++ ngx_http_upstream_fair_rbtree->sentinel,
++ usfp);
++
++ if (usfp->shared) {
++ ngx_shmtx_unlock(&shpool->mutex);
++ return NGX_OK;
++ }
++
++ usfp->shared = ngx_slab_alloc_locked(shpool,
++ sizeof(ngx_http_upstream_fair_shm_block_t) +
++ (usfp->number - 1) * sizeof(ngx_http_upstream_fair_shared_t));
++
++ if (!usfp->shared) {
++ ngx_shmtx_unlock(&shpool->mutex);
++ if (!usfp->size_err) {
++ ngx_log_error(NGX_LOG_EMERG, log, 0,
++ "upstream_fair_shm_size too small (current value is %udKiB)",
++ ngx_http_upstream_fair_shm_size >> 10);
++ usfp->size_err = 1;
++ }
++ return NGX_ERROR;
++ }
++
++ usfp->shared->node.key = ngx_crc32_short((u_char *) &ngx_cycle, sizeof ngx_cycle) ^
++ ngx_crc32_short((u_char *) &usfp, sizeof(usfp));
++
++ usfp->shared->generation = ngx_http_upstream_fair_generation;
++ usfp->shared->peers = (uintptr_t) usfp;
++ usfp->shared->total_nreq = 0;
++ usfp->shared->total_requests = 0;
++
++ for (i = 0; i < usfp->number; i++) {
++ usfp->shared->stats[i].nreq = 0;
++ usfp->shared->stats[i].last_req_id = 0;
++ usfp->shared->stats[i].total_req = 0;
++ }
++
++ ngx_rbtree_insert(ngx_http_upstream_fair_rbtree, &usfp->shared->node);
++
++ ngx_shmtx_unlock(&shpool->mutex);
++ return NGX_OK;
++}
++
++ngx_int_t
++ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
++ ngx_http_upstream_srv_conf_t *us)
++{
++ ngx_http_upstream_fair_peer_data_t *fp;
++ ngx_http_upstream_fair_peers_t *usfp;
++ ngx_uint_t n;
++ ngx_http_core_loc_conf_t *clcf;
++
++ fp = r->upstream->peer.data;
++
++ if (fp == NULL) {
++ fp = ngx_palloc(r->pool, sizeof(ngx_http_upstream_fair_peer_data_t));
++ if (fp == NULL) {
++ return NGX_ERROR;
++ }
++
++ r->upstream->peer.data = fp;
++ }
++
++ usfp = us->peer.data;
++ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
++ if (clcf) {
++ fp->exact_version_check = clcf->exact_version_check;
++ }
++ fp->version.data = (u_char*) "";
++ fp->version.len = 0;
++
++ fp->tried = ngx_bitvector_alloc(r->pool, usfp->number, &fp->data);
++ fp->done = ngx_bitvector_alloc(r->pool, usfp->number, &fp->data2);
++
++ if (fp->tried == NULL || fp->done == NULL) {
++ return NGX_ERROR;
++ }
++
++ /* set up shared memory area */
++ ngx_http_upstream_fair_shm_alloc(usfp, r->connection->log);
++
++ fp->current = usfp->current;
++ fp->peers = usfp;
++ usfp->shared->total_requests++;
++
++ for (n = 0; n < usfp->number; n++) {
++ usfp->peer[n].shared = &usfp->shared->stats[n];
++ }
++
++ r->upstream->peer.get = ngx_http_upstream_get_fair_peer;
++ r->upstream->peer.free = ngx_http_upstream_free_fair_peer;
++ r->upstream->peer.tries = usfp->number;
++#if (NGX_HTTP_SSL)
++ r->upstream->peer.set_session =
++ ngx_http_upstream_fair_set_session;
++ r->upstream->peer.save_session =
++ ngx_http_upstream_fair_save_session;
++#endif
++
++ return NGX_OK;
++}
++
++/* check if this upstream peer is allowed (same exact version/same major-minor version based on exact_version_check flag)
++ * return 1 if allowed, 0 if not */
++ngx_flag_t
++ngx_http_upstream_fair_peer_version_allowed(ngx_http_upstream_fair_peer_t *peer, void* data,
++ ngx_log_t* log) {
++ ngx_http_upstream_fair_peer_data_t* fp = data;
++ ngx_uint_t peer_version[2], auth_token_version[2];
++ ngx_flag_t f = 1;
++ ngx_uint_t j = 0;
++ char *ptr = NULL;
++
++ /* Version check enforcement when the auth_token contains a version */
++ if (fp->version.len && peer->version.len == 0) {
++ // Peer does not have version set in nginx conf
++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
++ "auth_token has a version but the peer doesn't, skipping peer");
++ return 0;
++ } else if (fp->version.len && peer->version.len) {
++ // Peer has version set in nginx conf
++ if (fp->exact_version_check) {
++ // if the server version check is non-permissive (needs to be an exact match)
++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
++ "exact_version_check is on");
++ if (fp->version.len != peer->version.len || ngx_memcmp(fp->version.data, peer->version.data, fp->version.len)) {
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
++ "skipping peer at a different version %V", &peer->version);
++ f = 0;
++ }
++ } else {
++ // if the server version check is permissive (eg. all 8.5.x will be treated same by nginx)
++ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0,
++ "exact_version_check is off");
++
++ ptr = strtok ((char *)fp->version.data,".");
++ while (ptr != NULL && (j < 2)) {
++ auth_token_version[j] = atoi(ptr);
++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
++ "auth_token_version[%d] = %d", j, auth_token_version[j]);
++ ptr = strtok (NULL, ".");
++ j++;
++ }
++ j = 0;
++ ptr = strtok ((char *)peer->version.data,".");
++ while (ptr != NULL && (j < 2)) {
++ peer_version[j] = atoi(ptr);
++ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, log, 0,
++ "peer_version[%d] = %d", j, peer_version[j]);
++ ptr = strtok (NULL, ".");
++ j++;
++ }
++ // Compare if the major and minor revisions are same
++ for (j = 0; j < 2; j++) {
++ if (auth_token_version[j] != peer_version[j]) {
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
++ "skipping peer at a different major/minor version %V", &peer->version);
++ f = 0;
++ }
++ }
++ }
++ }
++
++ return f;
++}
++
++#if (NGX_HTTP_SSL)
++static ngx_int_t
++ngx_http_upstream_fair_set_session(ngx_peer_connection_t *pc, void *data)
++{
++ ngx_http_upstream_fair_peer_data_t *fp = data;
++
++ ngx_int_t rc;
++ ngx_ssl_session_t *ssl_session;
++ ngx_http_upstream_fair_peer_t *peer;
++
++ if (fp->current == NGX_PEER_INVALID)
++ return NGX_OK;
++
++ peer = &fp->peers->peer[fp->current];
++
++ /* TODO: threads only mutex */
++ /* ngx_lock_mutex(fp->peers->mutex); */
++
++ ssl_session = peer->ssl_session;
++
++ rc = ngx_ssl_set_session(pc->connection, ssl_session);
++
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,"set session: %p", ssl_session);
++ /* ngx_unlock_mutex(fp->peers->mutex); */
++
++ return rc;
++}
++
++static void
++ngx_http_upstream_fair_save_session(ngx_peer_connection_t *pc, void *data)
++{
++ ngx_http_upstream_fair_peer_data_t *fp = data;
++
++ ngx_ssl_session_t *old_ssl_session, *ssl_session;
++ ngx_http_upstream_fair_peer_t *peer;
++
++ if (fp->current == NGX_PEER_INVALID)
++ return;
++
++ ssl_session = ngx_ssl_get_session(pc->connection);
++
++ if (ssl_session == NULL) {
++ return;
++ }
++
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,"save session: %p", ssl_session);
++ peer = &fp->peers->peer[fp->current];
++
++ /* TODO: threads only mutex */
++ /* ngx_lock_mutex(fp->peers->mutex); */
++
++ old_ssl_session = peer->ssl_session;
++ peer->ssl_session = ssl_session;
++
++ /* ngx_unlock_mutex(fp->peers->mutex); */
++
++ if (old_ssl_session) {
++
++ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,"old session: %p", old_ssl_session);
++ /* TODO: may block */
++
++ ngx_ssl_free_session(old_ssl_session);
++ }
++}
++
++#endif
++
++#if 0
++static void
++ngx_http_upstream_fair_walk_status(ngx_pool_t *pool, ngx_chain_t *cl, ngx_int_t *length,
++ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
++{
++ ngx_http_upstream_fair_shm_block_t *s_node = (ngx_http_upstream_fair_shm_block_t *) node;
++ ngx_http_upstream_fair_peers_t *peers;
++ ngx_chain_t *new_cl;
++ ngx_buf_t *b;
++ ngx_uint_t size, i;
++
++ if (node == sentinel) {
++ return;
++ }
++
++ if (node->left != sentinel) {
++ ngx_http_upstream_fair_walk_status(pool, cl, length, node->left, sentinel);
++ }
++
++ if (s_node->generation != ngx_http_upstream_fair_generation) {
++ size = 100;
++ peers = NULL;
++ } else {
++ /* this is rather ugly (casting an uintptr_t back into a pointer
++ * but as long as the generation is still the same (verified above),
++ * it should be still safe
++ */
++ peers = (ngx_http_upstream_fair_peers_t *) s_node->peers;
++ if (!peers->shared) {
++ goto next;
++ }
++
++ size = 200 + peers->number * 120; /* LOTS of slack */
++ }
++
++ b = ngx_create_temp_buf(pool, size);
++ if (!b) {
++ goto next;
++ }
++
++ new_cl = ngx_alloc_chain_link(pool);
++ if (!new_cl) {
++ goto next;
++ }
++
++ new_cl->buf = b;
++ new_cl->next = NULL;
++
++ while (cl->next) {
++ cl = cl->next;
++ }
++ cl->next = new_cl;
++
++ if (peers) {
++ b->last = ngx_sprintf(b->last, "upstream %V (%p): current peer %d/%d, total requests: %ui\n", peers->name, (void*) node, peers->current, peers->number, s_node->total_requests);
++ for (i = 0; i < peers->number; i++) {
++ ngx_http_upstream_fair_peer_t *peer = &peers->peer[i];
++ ngx_http_upstream_fair_shared_t *sh = peer->shared;
++ b->last = ngx_sprintf(b->last, " peer %d: %V weight: %d/%d, fails: %d/%d, acc: %d, down: %d, nreq: %d, total_req: %ui, last_req: %ui\n",
++ i, &peer->name, sh->current_weight, peer->weight, sh->fails, peer->max_fails, peer->accessed, peer->down,
++ sh->nreq, sh->total_req, sh->last_req_id);
++ }
++ } else {
++ b->last = ngx_sprintf(b->last, "upstream %p: gen %ui != %ui, total_nreq = %ui", (void*) node, s_node->generation, ngx_http_upstream_fair_generation, s_node->total_nreq);
++ }
++ b->last = ngx_sprintf(b->last, "\n");
++ b->last_buf = 1;
++
++ *length += b->last - b->pos;
++
++ if (cl->buf) {
++ cl->buf->last_buf = 0;
++ }
++
++ cl = cl->next;
++next:
++
++ if (node->right != sentinel) {
++ ngx_http_upstream_fair_walk_status(pool, cl, length, node->right, sentinel);
++ }
++}
++
++static ngx_chain_t*
++ngx_http_upstream_fair_report_status(ngx_http_request_t *r, ngx_int_t *length)
++{
++ ngx_buf_t *b;
++ ngx_chain_t *cl;
++ ngx_slab_pool_t *shpool;
++
++ b = ngx_create_temp_buf(r->pool, sizeof("\nupstream_fair status report:\n"));
++ if (!b) {
++ return NULL;
++ }
++
++ cl = ngx_alloc_chain_link(r->pool);
++ if (!cl) {
++ return NULL;
++ }
++ cl->next = NULL;
++ cl->buf = b;
++
++ b->last = ngx_cpymem(b->last, "\nupstream_fair status report:\n",
++ sizeof("\nupstream_fair status report:\n") - 1);
++
++ *length = b->last - b->pos;
++
++ shpool = (ngx_slab_pool_t *)ngx_http_upstream_fair_shm_zone->shm.addr;
++
++ ngx_shmtx_lock(&shpool->mutex);
++
++ ngx_http_upstream_fair_walk_status(r->pool, cl,
++ length,
++ ngx_http_upstream_fair_rbtree->root,
++ ngx_http_upstream_fair_rbtree->sentinel);
++
++ ngx_shmtx_unlock(&shpool->mutex);
++
++ if (!cl->next || !cl->next->buf) {
++ /* no upstream_fair status to report */
++ return NULL;
++ }
++
++ return cl;
++}
++#endif
++
++/* vim: set et ts=4 sw=4: */
+diff -urN nginx/src/http/ngx_http_upstream_fair.h nginx/src/http/ngx_http_upstream_fair.h
+--- nginx/src/http/ngx_http_upstream_fair.h 1970-01-01 05:30:00.000000000 +0530
++++ nginx/src/http/ngx_http_upstream_fair.h 2023-03-04 13:25:59.919145900 +0530
+@@ -0,0 +1,113 @@
++/*
++ * ***** BEGIN LICENSE BLOCK *****
++ * Zimbra Collaboration Suite Server
++ * Copyright (C) 2011 Zimbra Software, LLC.
++ *
++ * The contents of this file are subject to the Zimbra Public License
++ * Version 1.4 ("License"); you may not use this file except in
++ * compliance with the License. You may obtain a copy of the License at
++ * http://www.zimbra.com/license.
++ *
++ * Software distributed under the License is distributed on an "AS IS"
++ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
++ * ***** END LICENSE BLOCK *****
++ */
++
++#ifndef _NGX_HTTP_UPSTREAM_FAIR_H_INCLUDED_
++#define _NGX_HTTP_UPSTREAM_FAIR_H_INCLUDED_
++
++
++#include
++#include
++#include
++
++typedef struct {
++ ngx_uint_t nreq;
++ ngx_uint_t total_req;
++ ngx_uint_t last_req_id;
++ ngx_uint_t fails;
++ ngx_uint_t current_weight;
++} ngx_http_upstream_fair_shared_t;
++
++typedef struct ngx_http_upstream_fair_peers_s ngx_http_upstream_fair_peers_t;
++
++typedef struct {
++ ngx_rbtree_node_t node;
++ ngx_uint_t generation;
++ uintptr_t peers; /* forms a unique cookie together with generation */
++ ngx_uint_t total_nreq;
++ ngx_uint_t total_requests;
++ ngx_atomic_t lock;
++ ngx_http_upstream_fair_shared_t stats[1];
++} ngx_http_upstream_fair_shm_block_t;
++
++/* ngx_spinlock is defined without a matching unlock primitive */
++#define ngx_spinlock_unlock(lock) (void) ngx_atomic_cmp_set(lock, ngx_pid, 0)
++
++typedef struct {
++ ngx_http_upstream_fair_shared_t *shared;
++ struct sockaddr *sockaddr;
++ socklen_t socklen;
++ ngx_str_t name;
++
++ ngx_uint_t weight;
++ ngx_uint_t max_fails;
++ time_t fail_timeout;
++
++ time_t accessed;
++ ngx_uint_t down:1;
++ ngx_str_t version; /* upstream server version */
++
++#if (NGX_HTTP_SSL)
++ ngx_ssl_session_t *ssl_session; /* local to a process */
++#endif
++
++} ngx_http_upstream_fair_peer_t;
++
++#define NGX_HTTP_UPSTREAM_FAIR_NO_RR (1<<26)
++#define NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_IDLE (1<<27)
++#define NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_PEAK (1<<28)
++#define NGX_HTTP_UPSTREAM_FAIR_WEIGHT_MODE_MASK ((1<<27) | (1<<28))
++
++enum { WM_DEFAULT = 0, WM_IDLE, WM_PEAK };
++
++struct ngx_http_upstream_fair_peers_s {
++ ngx_http_upstream_fair_shm_block_t *shared;
++ ngx_uint_t current;
++ ngx_uint_t size_err:1;
++ ngx_uint_t no_rr:1;
++ ngx_uint_t weight_mode:2;
++ ngx_uint_t number;
++ ngx_str_t *name;
++ ngx_http_upstream_fair_peers_t *next; /* for backup peers support, not really used yet */
++ ngx_http_upstream_fair_peer_t peer[1];
++};
++
++
++#define NGX_PEER_INVALID (~0UL)
++
++typedef struct {
++ ngx_http_upstream_fair_peers_t *peers;
++ ngx_uint_t current;
++ uintptr_t *tried;
++ uintptr_t *done;
++ uintptr_t data;
++ uintptr_t data2;
++ ngx_str_t version;
++ ngx_flag_t exact_version_check;
++} ngx_http_upstream_fair_peer_data_t;
++
++extern ngx_uint_t *shm_size;
++
++ngx_int_t ngx_http_upstream_init_fair(ngx_conf_t *cf,
++ ngx_http_upstream_srv_conf_t *us);
++ngx_int_t ngx_http_upstream_init_fair_peer(ngx_http_request_t *r,
++ ngx_http_upstream_srv_conf_t *us);
++ngx_int_t ngx_http_upstream_get_fair_peer(ngx_peer_connection_t *pc,
++ void *data);
++void ngx_http_upstream_free_fair_peer(ngx_peer_connection_t *pc,
++ void *data, ngx_uint_t state);
++ngx_flag_t ngx_http_upstream_fair_peer_version_allowed(ngx_http_upstream_fair_peer_t *peer,
++ void* data, ngx_log_t* log);
++
++#endif /* _NGX_HTTP_UPSTREAM_FAIR_H_INCLUDED_ */
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail.patch
new file mode 100644
index 000000000..ccc2801ef
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail.patch
@@ -0,0 +1,260 @@
+--- nginx/src/mail/ngx_mail.h 2023-03-07 16:26:44.702481300 +0530
++++ nginx/src/mail/ngx_mail.h 2023-10-02 14:46:14.229251500 +0530
+@@ -18,7 +18,7 @@
+ #include
+ #endif
+
+-
++#include
+
+ typedef struct {
+ void **main_conf;
+@@ -117,6 +117,17 @@
+
+ ngx_uint_t max_errors;
+
++ ngx_str_t master_auth_username;
++ ngx_str_t master_auth_password;
++
++ ngx_str_t sasl_app_name;
++ ngx_str_t sasl_service_name;
++ ngx_flag_t sasl_host_from_ip;
++
++ ngx_msec_t auth_wait_intvl;
++
++ ngx_str_t default_realm;
++
+ ngx_str_t server_name;
+
+ u_char *file_name;
+@@ -134,13 +145,16 @@
+
+ typedef enum {
+ ngx_pop3_start = 0,
++ ngx_pop3_xoip,
+ ngx_pop3_user,
+ ngx_pop3_passwd,
+ ngx_pop3_auth_login_username,
+ ngx_pop3_auth_login_password,
+ ngx_pop3_auth_plain,
++ ngx_pop3_auth_plain_response,
+ ngx_pop3_auth_cram_md5,
+- ngx_pop3_auth_external
++ ngx_pop3_auth_external,
++ ngx_pop3_auth_gssapi
+ } ngx_pop3_state_e;
+
+
+@@ -149,7 +163,10 @@
+ ngx_imap_auth_login_username,
+ ngx_imap_auth_login_password,
+ ngx_imap_auth_plain,
++ ngx_imap_auth_plain_ir,
++ ngx_imap_auth_gssapi,
+ ngx_imap_auth_cram_md5,
++ ngx_imap_id,
+ ngx_imap_auth_external,
+ ngx_imap_login,
+ ngx_imap_user,
+@@ -162,9 +179,11 @@
+ ngx_smtp_auth_login_username,
+ ngx_smtp_auth_login_password,
+ ngx_smtp_auth_plain,
++ ngx_smtp_auth_gssapi,
+ ngx_smtp_auth_cram_md5,
+ ngx_smtp_auth_external,
+ ngx_smtp_helo,
++ ngx_smtp_noxclient,
+ ngx_smtp_helo_xclient,
+ ngx_smtp_helo_auth,
+ ngx_smtp_helo_from,
+@@ -176,6 +195,12 @@
+ ngx_smtp_to
+ } ngx_smtp_state_e;
+
++/* sasl auth mechanisms */
++typedef enum {
++ ngx_auth_unknown = 0,
++ ngx_auth_plain,
++ ngx_auth_gssapi,
++} ngx_auth_e;
+
+ typedef struct {
+ ngx_peer_connection_t upstream;
+@@ -183,6 +208,15 @@
+ ngx_uint_t proxy_protocol; /* unsigned proxy_protocol:1; */
+ } ngx_mail_proxy_ctx_t;
+
++typedef void (*ngx_mail_cleanup_pt)(void *data);
++
++typedef struct ngx_mail_cleanup_s ngx_mail_cleanup_t;
++
++struct ngx_mail_cleanup_s {
++ ngx_mail_cleanup_pt handler;
++ void *data;
++ ngx_mail_cleanup_t *next;
++};
+
+ typedef struct {
+ uint32_t signature; /* "MAIL" */
+@@ -202,6 +236,8 @@
+
+ ngx_uint_t mail_state;
+
++ ngx_str_t greetings[3];
++
+ unsigned ssl:1;
+ unsigned protocol:3;
+ unsigned blocked:1;
+@@ -211,10 +247,26 @@
+ unsigned no_sync_literal:1;
+ unsigned starttls:1;
+ unsigned esmtp:1;
+- unsigned auth_method:3;
++ unsigned auth_method:4;
+ unsigned auth_wait:1;
+
+- ngx_str_t login;
++ unsigned sendquitmsg:1;
++
++ unsigned vlogin:2; /* vlogin = 0 fqdn is not looked up;
++ vlogin = 1 fqdn has been looked up but not found;
++ vlogin = 2 fqdn has been looked up and assigned to "login"
++ */
++
++ ngx_str_t login; /* keep the original user input login */
++
++ ngx_str_t qlogin; /* initially equal to 'login', then hold account name
++ after successful alias cache fetch or route lookup
++ this value is finally used to login the upstream
++ mail server*/
++ ngx_str_t zlogin; /* the hack suffix "/wm" or "/ni" or "/tb" */
++ ngx_str_t id_name; /* the value of "name" field in IMAP ID */
++ ngx_str_t id_version; /* the value of "version" field in IMAP ID */
++
+ ngx_str_t passwd;
+
+ ngx_str_t salt;
+@@ -243,11 +295,31 @@
+ u_char *cmd_start;
+ u_char *arg_start;
+ ngx_uint_t literal_len;
++ ngx_uint_t eargs; /* expected #args for command */
++
++ /* SASL */
++ ngx_flag_t usedauth;
++ ngx_flag_t qualifydauth;
++ ngx_str_t dusr;
++ ngx_str_t zusr;
++ ngx_str_t dpasswd;
++ ngx_auth_e authmech;
++ ngx_flag_t saslfr;
++ sasl_conn_t *saslconn;
++ ngx_str_t authid; /* SASL authenticating user */
++
++ /* memcache keys */
++ ngx_str_t key_alias;
++ ngx_str_t key_route;
++
++ /* clean up */
++ ngx_mail_cleanup_t *cleanup;
+ } ngx_mail_session_t;
+
+
+ typedef struct {
+ ngx_str_t *client;
++ ngx_uint_t client_port;
+ ngx_mail_session_t *session;
+ } ngx_mail_log_ctx_t;
+
+@@ -275,9 +347,10 @@
+ #define NGX_IMAP_NOOP 4
+ #define NGX_IMAP_STARTTLS 5
+
+-#define NGX_IMAP_NEXT 6
++#define NGX_IMAP_ID 6
+
+ #define NGX_IMAP_AUTHENTICATE 7
++#define NGX_IMAP_NEXT 8
+
+
+ #define NGX_SMTP_HELO 1
+@@ -302,6 +375,11 @@
+ #define NGX_MAIL_AUTH_CRAM_MD5 4
+ #define NGX_MAIL_AUTH_EXTERNAL 5
+ #define NGX_MAIL_AUTH_NONE 6
++/* zimbra auth definitions */
++#define NGX_MAIL_AUTH_PASSWD 7
++#define NGX_MAIL_AUTH_PLAIN_IR 8
++#define NGX_MAIL_AUTH_GSSAPI 9
++#define NGX_MAIL_AUTH_GSSAPI_IR 10
+
+
+ #define NGX_MAIL_AUTH_PLAIN_ENABLED 0x0002
+@@ -309,10 +387,19 @@
+ #define NGX_MAIL_AUTH_APOP_ENABLED 0x0008
+ #define NGX_MAIL_AUTH_CRAM_MD5_ENABLED 0x0010
+ #define NGX_MAIL_AUTH_EXTERNAL_ENABLED 0x0020
+-#define NGX_MAIL_AUTH_NONE_ENABLED 0x0040
++#define NGX_MAIL_AUTH_GSSAPI_ENABLED 0x0040
++#define NGX_MAIL_AUTH_NONE_ENABLED 0x0080
+
+
+ #define NGX_MAIL_PARSE_INVALID_COMMAND 20
++#define NGX_MAIL_PARSE_INVALID_AUTH_MECH 30
++#define NGX_MAIL_AUTH_ABORT 40
++#define NGX_MAIL_AUTH_ARGUMENT 50
++#define NGX_MAIL_AUTH_FAILED 60
++#define NGX_MAIL_LOGIN_FAILED 70
++
++#define NGX_MAIL_MAX_LOGIN_LEN 256
++#define NGX_MAIL_MAX_PASSWORD_LEN 1024
+
+
+ typedef void (*ngx_mail_init_session_pt)(ngx_mail_session_t *s,
+@@ -336,6 +423,7 @@
+ ngx_str_t internal_server_error;
+ ngx_str_t cert_error;
+ ngx_str_t no_cert;
++ ngx_str_t quit_msg;
+ };
+
+
+@@ -397,13 +485,27 @@
+ ngx_int_t ngx_mail_auth_cram_md5(ngx_mail_session_t *s, ngx_connection_t *c);
+ ngx_int_t ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
+ ngx_uint_t n);
++ngx_int_t ngx_mail_auth_gssapi(ngx_mail_session_t *s, ngx_connection_t *c, ngx_str_t * output);
+ ngx_int_t ngx_mail_auth_parse(ngx_mail_session_t *s, ngx_connection_t *c);
+
+ void ngx_mail_send(ngx_event_t *wev);
+ ngx_int_t ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c);
++void ngx_mail_set_imap_parse_state_start(ngx_mail_session_t * s);
++void ngx_mail_set_pop3_parse_state_start(ngx_mail_session_t * s);
++void ngx_mail_set_smtp_parse_state_start(ngx_mail_session_t * s);
++void ngx_mail_set_imap_parse_state_argument(ngx_mail_session_t * s);
++void ngx_mail_set_pop3_parse_state_argument(ngx_mail_session_t * s);
++void ngx_mail_set_smtp_parse_state_argument(ngx_mail_session_t * s);
++void ngx_mail_reset_parse_buffer(ngx_mail_session_t * s);
+ void ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c);
++void ngx_mail_do_auth(ngx_mail_session_t *s, ngx_connection_t *c); /* Zimbra mail auth portal */
+ void ngx_mail_close_connection(ngx_connection_t *c);
+ void ngx_mail_session_internal_server_error(ngx_mail_session_t *s);
++void ngx_mail_end_session(ngx_mail_session_t *s);
++ngx_str_t ngx_mail_session_getquitmsg(ngx_mail_session_t *s);
++ngx_str_t ngx_mail_session_geterrmsg(ngx_mail_session_t *s);
++ngx_str_t ngx_mail_get_socket_local_addr_str (ngx_pool_t *pool, ngx_socket_t s);
++ngx_int_t ngx_mail_decode_auth_plain(ngx_mail_session_t *s, ngx_str_t *encoded);
+ u_char *ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len);
+
+
+@@ -416,6 +518,9 @@
+ ngx_int_t ngx_mail_realip_handler(ngx_mail_session_t *s);
+ /**/
+
++ngx_mail_cleanup_t * ngx_mail_cleanup_add(ngx_mail_session_t * s, size_t size);
++
++ngx_flag_t ngx_mail_get_proxy_ssl(ngx_mail_session_t *s);
+
+ extern ngx_uint_t ngx_mail_max_module;
+ extern ngx_module_t ngx_mail_core_module;
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_auth_http_module.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_auth_http_module.patch
new file mode 100644
index 000000000..7919aea3f
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_auth_http_module.patch
@@ -0,0 +1,18 @@
+--- nginx/src/mail/ngx_mail_auth_http_module.c 2023-03-07 16:26:44.704430400 +0530
++++ nginx/src/mail/ngx_mail_auth_http_module.c 2023-09-14 18:47:12.605101100 +0530
+@@ -1536,6 +1536,7 @@
+ conf->host_header = prev->host_header;
+ conf->uri = prev->uri;
+
++ /* zimbra uses zmauth, so no auth_http
+ if (conf->peer == NULL) {
+ ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
+ "no \"auth_http\" is defined for server in %s:%ui",
+@@ -1543,6 +1544,7 @@
+
+ return NGX_CONF_ERROR;
+ }
++ */
+ }
+
+ ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000);
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_core_module.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_core_module.patch
new file mode 100644
index 000000000..3370c3de5
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_core_module.patch
@@ -0,0 +1,160 @@
+--- nginx/src/mail/ngx_mail_core_module.c 2023-07-23 13:21:27.107626300 +0530
++++ nginx/src/mail/ngx_mail_core_module.c 2023-09-14 18:47:12.612942300 +0530
+@@ -92,6 +92,41 @@
+ offsetof(ngx_mail_core_srv_conf_t, max_errors),
+ NULL },
+
++ { ngx_string("sasl_app_name"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_core_srv_conf_t, sasl_app_name),
++ NULL },
++
++ { ngx_string("sasl_service_name"),
++ NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_core_srv_conf_t, sasl_service_name),
++ NULL },
++
++ { ngx_string("zm_auth_wait"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_core_srv_conf_t, auth_wait_intvl),
++ NULL },
++
++ { ngx_string("default_realm"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_core_srv_conf_t, default_realm),
++ NULL },
++
++ { ngx_string("sasl_host_from_ip"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_core_srv_conf_t, sasl_host_from_ip),
++ NULL },
++
+ ngx_null_command
+ };
+
+@@ -167,12 +202,15 @@
+ * cscf->error_log = NULL;
+ */
+
++ cscf->protocol = NGX_CONF_UNSET_PTR;
+ cscf->timeout = NGX_CONF_UNSET_MSEC;
+ cscf->resolver_timeout = NGX_CONF_UNSET_MSEC;
+
+ cscf->max_errors = NGX_CONF_UNSET_UINT;
+
+ cscf->resolver = NGX_CONF_UNSET_PTR;
++ cscf->auth_wait_intvl = NGX_CONF_UNSET_MSEC;
++ cscf->sasl_host_from_ip = NGX_CONF_UNSET;
+
+ cscf->file_name = cf->conf_file->file.name.data;
+ cscf->line = cf->conf_file->line;
+@@ -192,6 +230,27 @@
+ 30000);
+
+ ngx_conf_merge_uint_value(conf->max_errors, prev->max_errors, 5);
++ ngx_conf_merge_str_value(
++ conf->sasl_app_name, prev->sasl_app_name, "nginx");
++
++ ngx_conf_merge_str_value(
++ conf->sasl_service_name, prev->sasl_service_name, "");
++/* TO BE HANDLED */
++ if (conf->sasl_service_name.len == 0) {
++ if (conf->protocol->type == NGX_MAIL_IMAP_PROTOCOL) {
++ conf->sasl_service_name.data = (u_char *)"imap";
++ conf->sasl_service_name.len = sizeof("imap") - 1;
++ } else if (conf->protocol->type == NGX_MAIL_POP3_PROTOCOL) {
++ conf->sasl_service_name.data = (u_char *)"pop";
++ conf->sasl_service_name.len = sizeof("pop") - 1;
++ } else if (conf->protocol->type == NGX_MAIL_SMTP_PROTOCOL) {
++ conf->sasl_service_name.data = (u_char *)"smtp";
++ conf->sasl_service_name.len = sizeof("smtp") - 1;
++ } else {
++ conf->sasl_service_name.data = (u_char *)"unknown";
++ conf->sasl_service_name.len = sizeof("unknown") - 1;
++ }
++ }
+
+ ngx_conf_merge_str_value(conf->server_name, prev->server_name, "");
+
+@@ -214,6 +273,17 @@
+ }
+ }
+
++ /*
++ * master_auth_username and master_auth_password is already set in ngx_zm_lookup module
++ *
++ * ngx_conf_merge_str_value(conf->master_auth_username, prev->master_auth_username, "");
++ * ngx_conf_merge_str_value(conf->master_auth_password, prev->master_auth_password, "");
++ */
++ ngx_conf_merge_msec_value (conf->auth_wait_intvl, prev->auth_wait_intvl, 10000);
++
++ ngx_conf_merge_str_value (conf->default_realm, prev->default_realm,"");
++ ngx_conf_merge_value (conf->sasl_host_from_ip, prev->sasl_host_from_ip, 0);
++
+ ngx_conf_merge_ptr_value(conf->resolver, prev->resolver, NULL);
+
+ return NGX_CONF_OK;
+@@ -597,7 +667,7 @@
+ nls->wildcard = ngx_inet_wildcard(nls->sockaddr);
+
+ als = cmcf->listen.elts;
+-
++ /* Zimbra ports can be same
+ for (i = 0; i < cmcf->listen.nelts - 1; i++) {
+
+ if (ngx_cmp_sockaddr(als[i].sockaddr, als[i].socklen,
+@@ -612,7 +682,7 @@
+ &nls->addr_text);
+ return NGX_CONF_ERROR;
+ }
+-
++ */
+ next:
+ continue;
+ }
+@@ -714,3 +784,35 @@
+
+ return NGX_CONF_OK;
+ }
++
++
++ngx_mail_cleanup_t *
++ngx_mail_cleanup_add(ngx_mail_session_t *s, size_t size)
++{
++ ngx_mail_cleanup_t *cln;
++
++ cln = ngx_palloc(s->connection->pool, sizeof(ngx_mail_cleanup_t));
++ if (cln == NULL) {
++ return NULL;
++ }
++
++ if (size) {
++ cln->data = ngx_palloc(s->connection->pool, size);
++ if (cln->data == NULL) {
++ return NULL;
++ }
++
++ } else {
++ cln->data = NULL;
++ }
++
++ cln->handler = NULL;
++ cln->next = s->cleanup;
++
++ s->cleanup = cln;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "mail cleanup add: %p", cln);
++
++ return cln;
++}
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_handler.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_handler.patch
new file mode 100644
index 000000000..205b01ae8
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_handler.patch
@@ -0,0 +1,1490 @@
+--- nginx/src/mail/ngx_mail_handler.c 2023-08-18 17:02:49.358696000 +0530
++++ nginx/src/mail/ngx_mail_handler.c 2023-10-02 15:28:39.963273000 +0530
+@@ -10,10 +10,20 @@
+ #include
+ #include
+
++#include
++#include
++#include
++#include
++#include
++#include
+
+ static void ngx_mail_proxy_protocol_handler(ngx_event_t *rev);
+ static void ngx_mail_init_session_handler(ngx_event_t *rev);
+ static void ngx_mail_init_session(ngx_connection_t *c);
++static void ngx_mail_choke_session(throttle_callback_t *cb);
++static void ngx_mail_allow_session(throttle_callback_t *cb);
++static void ngx_mail_allow_userauth(throttle_callback_t *cb);
++static void ngx_mail_choke_userauth(throttle_callback_t *cb);
+
+ #if (NGX_MAIL_SSL)
+ static void ngx_mail_ssl_init_connection(ngx_ssl_t *ssl, ngx_connection_t *c);
+@@ -22,12 +32,25 @@
+ ngx_connection_t *c);
+ #endif
+
++static int ngx_mail_create_sasl_context(ngx_connection_t *s);
++static void ngx_mail_dispose_sasl_context(ngx_mail_session_t *s);
++static int ngx_mail_initialize_sasl(ngx_connection_t *c);
++static int ngx_mail_sasl_startstep(ngx_connection_t *c, const char *mech,
++ ngx_str_t *response, ngx_str_t *challenge);
++static int ngx_mail_sasl_log(void *context, int level, const char * message);
++static int ngx_mail_sasl_pauthorize(sasl_conn_t *conn, void *context,
++ const char *authz, unsigned authzlen, const char *authc, unsigned authclen,
++ const char *realm, unsigned rlen, struct propctx *propctx);
++
++static ngx_str_t krb5_cooked_password = ngx_string("KKK");
++
++static ngx_flag_t sasl_initialized = 0;
+
+ void
+ ngx_mail_init_connection(ngx_connection_t *c)
+ {
+- size_t len;
+ ngx_uint_t i;
++ ngx_uint_t remote_port=0;
+ ngx_event_t *rev;
+ ngx_mail_port_t *port;
+ struct sockaddr *sa;
+@@ -37,7 +60,7 @@
+ ngx_mail_session_t *s;
+ ngx_mail_addr_conf_t *addr_conf;
+ ngx_mail_core_srv_conf_t *cscf;
+- u_char text[NGX_SOCKADDR_STRLEN];
++ //u_char text[NGX_SOCKADDR_STRLEN];
+ #if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+ ngx_mail_in6_addr_t *addr6;
+@@ -145,10 +168,28 @@
+
+ ngx_set_connection_log(c, cscf->error_log);
+
+- len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
++ //len = ngx_sock_ntop(c->sockaddr, c->socklen, text, NGX_SOCKADDR_STRLEN, 1);
+
+- ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%uA client %*s connected to %V",
+- c->number, len, text, s->addr_text);
++ switch (c->sockaddr->sa_family) {
++#if (NGX_HAVE_INET6)
++ case AF_INET6:
++ sin6 = (struct sockaddr_in6 *) c->sockaddr;
++ remote_port = ntohs(sin6->sin6_port);
++ break;
++#endif
++ default:
++ sin = (struct sockaddr_in *) c->sockaddr;
++ remote_port = ntohs(sin->sin_port);
++ break;
++ }
++
++ if (remote_port && remote_port < 65536) {
++ ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V:%ui connected to %V",
++ c->number, &c->addr_text, remote_port, s->addr_text);
++ } else {
++ ngx_log_error(NGX_LOG_INFO, c->log, 0, "*%ui client %V connected to %V",
++ c->number, &c->addr_text, s->addr_text);
++ }
+
+ ctx = ngx_palloc(c->pool, sizeof(ngx_mail_log_ctx_t));
+ if (ctx == NULL) {
+@@ -157,6 +198,7 @@
+ }
+
+ ctx->client = &c->addr_text;
++ ctx->client_port = remote_port;
+ ctx->session = s;
+
+ c->log->connection = c->number;
+@@ -379,7 +421,7 @@
+ ngx_mail_init_session(c);
+ return;
+ }
+-
++
+ ngx_mail_close_connection(c);
+ }
+
+@@ -456,26 +498,260 @@
+ {
+ ngx_mail_session_t *s;
+ ngx_mail_core_srv_conf_t *cscf;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ throttle_callback_t *cb;
++ ngx_uint_t login_ip_max;
+
+ s = c->data;
+
+ c->log->action = "sending client greeting line";
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
+
+ s->protocol = cscf->protocol->type;
+
++ if(s->ctx != NULL) {
++ return;
++ }
++
+ s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_mail_max_module);
+ if (s->ctx == NULL) {
+ ngx_mail_session_internal_server_error(s);
+ return;
+ }
+
++ s->cleanup = NULL;
++
++ /* throttle */
++ cb = ngx_pcalloc(c->pool, sizeof(throttle_callback_t));
++ if(cb == NULL) {
++ ngx_mail_session_internal_server_error(s);
++ return;
++ }
++
++ ngx_memset(cb, 0, sizeof(throttle_callback_t));
++ cb->session = s;
++ cb->connection = c;
++ cb->log = ngx_cycle->log;
++ cb->pool = c->pool;
++ cb->on_allow = ngx_mail_allow_session;
++ cb->on_deny = ngx_mail_choke_session;
++
++ login_ip_max = ngx_mail_throttle_ip_max_for_protocol(tscf, s->protocol);
++ if (login_ip_max == 0) {
++ cb->on_allow(cb); //unlimited, direct allow session
++ } else {
++ ngx_mail_throttle_whitelist_ip(c->addr_text, cb);
++ }
++}
++
++static void
++ngx_mail_choke_session(throttle_callback_t *cb)
++{
++ ngx_connection_t *c;
++ ngx_mail_session_t *s;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_str_t bye, msg;
++ u_char *p;
++
++ c = (ngx_connection_t *)cb->connection;
++ s = c->data;
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
++ msg = tscf->mail_login_ip_rejectmsg;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log,0,
++ "ip throttle:%V choking mail session", &c->addr_text);
++
++ if(s->protocol == NGX_MAIL_IMAP_PROTOCOL) {
++ bye.data =
++ ngx_palloc(c->pool,
++ sizeof("* BYE ")- 1 +
++ msg.len +
++ sizeof(CRLF) - 1
++ );
++ if (bye.data == NULL) {
++ ngx_str_set(&bye, "* BYE" CRLF);
++ } else {
++ p = bye.data;
++ p = ngx_cpymem(p, "* BYE ", sizeof("* BYE ") - 1);
++ p = ngx_cpymem(p, msg.data, msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p - bye.data;
++ }
++ } else if(s->protocol == NGX_MAIL_POP3_PROTOCOL) {
++ bye.data = ngx_palloc(c->pool,
++ sizeof("-ERR ") - 1 +
++ msg.len +
++ sizeof(CRLF) - 1);
++ if (bye.data == NULL) {
++ ngx_str_set(&bye, "-ERR" CRLF);
++ } else {
++ p = bye.data;
++ p = ngx_cpymem(p,"-ERR ",sizeof("-ERR ") - 1);
++ p = ngx_cpymem(p, msg.data, msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p - bye.data;
++ }
++ } else {
++ /* TODO SMTP is not (yet) relevant for zimbra, but how do we reject it ? */
++ ngx_str_set(&bye, "");
++ }
++
++ s->out = bye;
++ s->quit = 1;
++
++ ngx_mail_send(c->write);
++
++ return;
++}
++
++static void
++ngx_mail_allow_session(throttle_callback_t *cb)
++{
++ ngx_connection_t *c;
++ ngx_mail_session_t *s;
++ ngx_mail_core_srv_conf_t *cscf;
++
++ c = (ngx_connection_t*)cb->connection;
++ s = c->data;
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++
+ c->write->handler = ngx_mail_send;
+
+ cscf->protocol->init_session(s, c);
+ }
+
++static void
++ngx_mail_choke_userauth(throttle_callback_t *cb)
++{
++ ngx_connection_t *c;
++ ngx_mail_session_t *s;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_str_t bye, msg, umsg;
++ size_t l;
++ u_char *p;
++
++ c = (ngx_connection_t *)cb->connection;
++ s = c->data;
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
++ msg = tscf->mail_login_user_rejectmsg;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "user throttle:%V choking mail session", &s->login);
++
++ if(s->protocol == NGX_MAIL_IMAP_PROTOCOL)
++ {
++ bye.data = ngx_palloc(c->pool, sizeof("* BYE ") - 1 +
++ msg.len + sizeof(CRLF) - 1);
++ if (bye.data == NULL) {
++ ngx_str_set(&bye, "* BYE" CRLF);
++ } else {
++ p = bye.data;
++ p = ngx_cpymem(p, "* BYE ", sizeof("* BYE ") - 1);
++ p = ngx_cpymem(p, msg.data, msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p - bye.data;
++ }
++ s->out = bye;
++ s->quit = 0; /* don't quit just yet */
++ ngx_mail_send(c->write);
++
++ /* for IMAP, we also want to send back a tagged NO response */
++ l = s->tag.len + 1 /*for space*/ +
++ sizeof("NO ") - 1 +
++ sizeof(" failed") - 1 + /* ?? "failed" or "rejected" ?? */
++ sizeof(CRLF) - 1;
++
++ if (s->command == NGX_IMAP_LOGIN) {
++ l += (sizeof("LOGIN ") - 1);
++ } else if (s->command == NGX_IMAP_AUTHENTICATE) {
++ l += (sizeof("AUTHENTICATE ") - 1);
++ }
++
++ umsg.data = ngx_palloc(c->pool,l);
++
++ if (umsg.data == NULL) {
++ ngx_str_set(&umsg, "");
++ } else {
++ p = umsg.data;
++ p = ngx_cpymem(p, s->tag.data, s->tag.len);
++ *p++=' ';
++ p = ngx_cpymem(p, "NO ", sizeof("NO ") - 1);
++ if (s->command == NGX_IMAP_LOGIN) {
++ p = ngx_cpymem(p, "LOGIN ", sizeof("LOGIN ") - 1);
++ } else if (s->command == NGX_IMAP_AUTHENTICATE) {
++ p = ngx_cpymem(p, "AUTHENTICATE ", sizeof("AUTHENTICATE ") - 1);
++ }
++ p = ngx_cpymem(p, "failed", sizeof("failed") - 1);
++ *p++ = CR;
++ *p++ = LF;
++ umsg.len = p - umsg.data;
++ }
++
++ s->out = umsg;
++ s->quit = 1;
++ ngx_mail_send(c->write);
++
++ return;
++ }
++ else if(s->protocol == NGX_MAIL_POP3_PROTOCOL)
++ {
++ bye.data =
++ ngx_palloc(c->pool,
++ sizeof("-ERR ")-1+msg.len+sizeof(CRLF)-1);
++ if (bye.data == NULL) {
++ bye.data = (u_char*)("-ERR" CRLF);
++ bye.len = sizeof("-ERR" CRLF)-1;
++ } else {
++ p = bye.data;
++ p = ngx_cpymem(p,"-ERR ",sizeof("-ERR ")-1);
++ p = ngx_cpymem(p,msg.data,msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p-bye.data;
++ }
++ s->out = bye;
++ s->quit = 1;
++ ngx_mail_send(c->write);
++ return;
++ }
++ else
++ {
++ /* TODO SMTP is not (yet) relevant for zimbra, but how do we reject it ? */
++ ngx_str_set(&bye, "");
++ s->out = bye;
++ s->quit = 1;
++ ngx_mail_send(c->write);
++ return;
++ }
++}
++
++static void
++ngx_mail_allow_userauth(throttle_callback_t *cb)
++{
++ ngx_connection_t *c;
++ ngx_mail_session_t *s;
++
++ c = (ngx_connection_t *)cb->connection;
++ s = c->data;
++
++ /* remainder code is the erstwhile ngx_mail_do_auth(s);*/
++ s->args.nelts = 0;
++ s->buffer->pos = s->buffer->start;
++ s->buffer->last = s->buffer->start;
++ s->state = 0;
++
++ if (s->connection->read->timer_set) {
++ ngx_del_timer(s->connection->read);
++ }
++
++ s->login_attempt++;
++ ngx_mail_zmauth_init(s);
++}
+
+ ngx_int_t
+ ngx_mail_salt(ngx_mail_session_t *s, ngx_connection_t *c,
+@@ -520,14 +796,42 @@
+ #endif
+
+
++/* Decode an SASL PLAIN challenge (RFC 4616)
++ If AUTHZ is empty:
++ set s->usedauth = 0,
++ set s->login = AUTHC
++ If AUTHZ is present:
++ set s->usedauth = 1
++ set s->dusr = AUTHC
++ set s->login = AUTHZ
++ */
+ ngx_int_t
+ ngx_mail_auth_plain(ngx_mail_session_t *s, ngx_connection_t *c, ngx_uint_t n)
+ {
+ u_char *p, *last;
+- ngx_str_t *arg, plain;
++ ngx_str_t *arg, plain, temp;
+
+ arg = s->args.elts;
+
++#if (NGX_MAIL_SSL)
++ if(ngx_mail_starttls_only(s, c)) {
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++#endif
++
++ /* check if the auth exchange is being aborted */
++ if (s->args.nelts > 0 &&
++ arg[n].len == 1 &&
++ arg[n].data[0] == '*'
++ )
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "auth:abort SASL PLAIN");
++
++ ngx_mail_dispose_sasl_context(s);
++ return NGX_MAIL_AUTH_ABORT;
++ }
++
+ #if (NGX_DEBUG_MAIL_PASSWD)
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "mail auth plain: \"%V\"", &arg[n]);
+@@ -544,6 +848,8 @@
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
++ s->auth_method = NGX_MAIL_AUTH_PLAIN;
++
+ p = plain.data;
+ last = p + plain.len;
+
+@@ -555,6 +861,9 @@
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
++ s->dusr.data = plain.data;
++ s->dusr.len = p - plain.data - 1;
++
+ s->login.data = p;
+
+ while (p < last && *p) { p++; }
+@@ -570,11 +879,29 @@
+ s->passwd.len = last - p;
+ s->passwd.data = p;
+
++ if (s->login.len > NGX_MAIL_MAX_LOGIN_LEN ||
++ s->dusr.len > NGX_MAIL_MAX_LOGIN_LEN ||
++ s->passwd.len > NGX_MAIL_MAX_PASSWORD_LEN) {
++ return NGX_MAIL_AUTH_FAILED;
++ }
++
+ #if (NGX_DEBUG_MAIL_PASSWD)
+ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "mail auth plain: \"%V\" \"%V\"", &s->login, &s->passwd);
+ #endif
+
++ if (s->dusr.len == 0) {
++ /* s->dusr = s->login; */
++ s->usedauth = 0;
++ } else {
++ s->usedauth = 1;
++ temp = s->dusr;
++ s->dusr = s->login;
++ s->login = temp;
++ }
++
++ s->dpasswd = s->passwd;
++
+ return NGX_DONE;
+ }
+
+@@ -590,6 +917,22 @@
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "mail auth login username: \"%V\"", &arg[n]);
+
++ /* check if the auth exchange is being aborted */
++ if (s->args.nelts > 0 &&
++ arg[n].len == 1 &&
++ arg[n].data[0] == '*'
++ )
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "auth:abort SASL LOGIN");
++
++ ngx_mail_dispose_sasl_context(s);
++ return NGX_MAIL_AUTH_ABORT;
++ }
++
++ if (ngx_base64_decoded_length(arg->len) > NGX_MAIL_MAX_LOGIN_LEN) {
++ return NGX_MAIL_AUTH_FAILED;
++ }
+ s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len));
+ if (s->login.data == NULL) {
+ return NGX_ERROR;
+@@ -604,7 +947,7 @@
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "mail auth login username: \"%V\"", &s->login);
+
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
+ }
+
+
+@@ -619,7 +962,21 @@
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "mail auth login password: \"%V\"", &arg[0]);
+ #endif
++ /* check if the auth exchange is being aborted */
++ if (s->args.nelts > 0 &&
++ arg[0].len == 1 &&
++ arg[0].data[0] == '*'
++ ) {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "auth:abort SASL LOGIN");
++
++ ngx_mail_dispose_sasl_context(s);
++ return NGX_MAIL_AUTH_ABORT;
++ }
+
++ if(ngx_base64_decoded_length(arg[0].len) > NGX_MAIL_MAX_PASSWORD_LEN) {
++ return NGX_MAIL_AUTH_FAILED;
++ }
+ s->passwd.data = ngx_pnalloc(c->pool,
+ ngx_base64_decoded_length(arg[0].len));
+ if (s->passwd.data == NULL) {
+@@ -637,6 +994,9 @@
+ "mail auth login password: \"%V\"", &s->passwd);
+ #endif
+
++ s->auth_method = NGX_MAIL_AUTH_LOGIN;
++ s->usedauth = 0;
++
+ return NGX_DONE;
+ }
+
+@@ -714,12 +1074,640 @@
+ "mail auth cram-md5: \"%V\" \"%V\"", &s->login, &s->passwd);
+
+ s->auth_method = NGX_MAIL_AUTH_CRAM_MD5;
++ s->usedauth = 0;
+
+ return NGX_DONE;
+ }
+
+
+ ngx_int_t
++ngx_mail_auth_gssapi(ngx_mail_session_t *s, ngx_connection_t *c, ngx_str_t * output)
++{
++ ngx_str_t *args, *arg;
++ ngx_uint_t narg;
++ ngx_mail_core_srv_conf_t *cscf;
++ int saslrc;
++
++ args = s->args.elts;
++ narg = s->args.nelts;
++ arg = args + narg - 1;
++
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++
++ /* check if the auth exchange is being aborted */
++ if (narg > 0 &&
++ arg->len == 1 &&
++ arg->data[0] == '*'
++ )
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL,c->log,0,
++ "auth:abort SASL GSSAPI");
++
++ ngx_mail_dispose_sasl_context(s);
++ return NGX_MAIL_AUTH_ABORT;
++ }
++
++ /* Initialize SASL once per process */
++ saslrc = ngx_mail_initialize_sasl (c);
++
++ if (saslrc != SASL_OK) {
++ return NGX_ERROR;
++ }
++
++ /* create one sasl authentication object per connection */
++ saslrc = ngx_mail_create_sasl_context (c);
++
++ if (saslrc != SASL_OK) {
++ return NGX_ERROR;
++ }
++
++ saslrc = ngx_mail_sasl_startstep(c,"gssapi", arg, output);
++
++ if (saslrc == SASL_CONTINUE)
++ {
++ return NGX_MAIL_AUTH_ARGUMENT;
++ }
++ else if (saslrc == SASL_OK)
++ {
++ s->dusr = cscf->master_auth_username;
++ s->dpasswd = cscf->master_auth_password;
++ s->auth_method = NGX_MAIL_AUTH_GSSAPI;
++ s->passwd = krb5_cooked_password;
++ s->usedauth = 1;
++ return NGX_DONE;
++ }
++ else
++ {
++ return NGX_ERROR;
++ }
++}
++
++/* Perform a once-per-process initialization of the sasl library */
++static int
++ngx_mail_initialize_sasl (ngx_connection_t *c)
++{
++ ngx_mail_session_t *s;
++ ngx_mail_core_srv_conf_t *cscf;
++ int rc = SASL_OK;
++ char *app;
++
++ if (!sasl_initialized)
++ {
++ s = c->data;
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++
++ app = ngx_palloc(c->pool, cscf->sasl_app_name.len + 1);
++
++ if (app == NULL) { return SASL_FAIL; }
++
++ ngx_memcpy (app, cscf->sasl_app_name.data, cscf->sasl_app_name.len);
++ ngx_memcpy (app + cscf->sasl_app_name.len, "\x0", 1);
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "Initializing SASL library, app:%s", app);
++
++ rc = sasl_server_init (NULL, app);
++
++ if (rc != SASL_OK)
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "Cannot initialize SASL library: err:%d, %s",
++ rc, sasl_errstring(rc,NULL,NULL)
++ );
++ }
++ else
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "Initialized SASL library");
++ sasl_initialized = 1;
++ }
++ }
++
++ return rc;
++}
++
++static int
++ngx_mail_sasl_pauthorize (sasl_conn_t *conn, void *context, const char *authz,
++ unsigned authzlen, const char *authc, unsigned authclen, const char *realm,
++ unsigned rlen, struct propctx *propctx)
++{
++ /* This function is called when we need to indicate whether the authz/authc
++ relationship should be allowed or not i.e can authc access authz's mailbox
++ since that decision must be made in the lookup servlet (which will happen later),
++ we need to defer that decision to the route lookup phase, and simply indicate our consent here
++ */
++
++ ngx_connection_t *c = context;
++ ngx_str_t nauthz = ngx_string(""),
++ nauthc = ngx_string(""),
++ nrealm = ngx_string("");
++
++ (void)c;
++ if (authz != NULL && authzlen > 0) {
++ nauthz.data = (u_char *)authz;
++ nauthz.len = authzlen;
++ }
++ if (authc != NULL && authclen > 0) {
++ nauthc.data = (u_char *)authc;
++ nauthc.len = authclen;
++ }
++ if (realm != NULL && rlen > 0) {
++ nrealm.data = (u_char *)realm;
++ nrealm.len = rlen;
++ }
++
++ ngx_log_debug3(NGX_LOG_DEBUG_MAIL,c->log,0,
++ "sasl: indicating proxy policy ok, authz:%V,authc:%V,realm:%V",
++ &nauthz,&nauthc,&nrealm
++ );
++
++ return SASL_OK;
++}
++
++static int
++ngx_mail_sasl_log (void *context, int level, const char *message)
++{
++ ngx_connection_t *c = context;
++
++ (void)c;
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "%s", message == NULL ? "null" : message);
++
++ return SASL_OK;
++}
++
++
++/* create a new SASL server authentication object (once per connection) */
++static int
++ngx_mail_create_sasl_context (ngx_connection_t *c)
++{
++ ngx_mail_session_t *s;
++ ngx_mail_core_srv_conf_t *cscf;
++ char *service;
++ int rc = SASL_OK;
++ sasl_security_properties_t rsec;
++ sasl_callback_t *callbacks;
++ ngx_uint_t i;
++ const char *fqdn = NULL;
++ struct hostent *host;
++ struct sockaddr_in sa;
++ socklen_t salen;
++ u_char *octets;
++
++ s = c->data;
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++
++ if (s->saslconn == NULL)
++ {
++ service = ngx_palloc (c->pool, cscf->sasl_service_name.len + 1);
++ if (service == NULL) {
++ return SASL_FAIL;
++ }
++
++ callbacks = ngx_palloc(c->pool,sizeof(sasl_callback_t) * 8);
++ if (callbacks == NULL) {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "cannot alloc memory for SASL callbacks"
++ );
++ return SASL_NOMEM;
++ }
++
++ i =0 ;
++
++ callbacks[i].id = SASL_CB_LOG;
++ callbacks[i].proc = (sasl_callback_ft)&ngx_mail_sasl_log;
++ callbacks[i].context = c;
++ ++i;
++
++ callbacks[i].id = SASL_CB_PROXY_POLICY;
++ callbacks[i].proc = (sasl_callback_ft)&ngx_mail_sasl_pauthorize;
++ callbacks[i].context = c;
++ ++i;
++
++ callbacks[i].id = SASL_CB_LIST_END;
++ callbacks[i].proc = NULL;
++ callbacks[i].context = NULL;
++ ++i;
++
++ ngx_memcpy (service, cscf->sasl_service_name.data,
++ cscf->sasl_service_name.len);
++ service[cscf->sasl_service_name.len] = 0;
++
++ /* The second argument to sasl_server_new is the FQDN of the server
++ If the srvprinc_from_ip configuration parameter is true, then
++ */
++
++ if (cscf->sasl_host_from_ip)
++ {
++ ngx_log_error (NGX_LOG_WARN, c->log, 0,
++ "will use IP address to resolve service principal");
++
++ salen = sizeof(sa);
++ if (
++ getsockname(s->connection->fd, (struct sockaddr*)&sa, &salen)
++ == 0
++ )
++ {
++ if (sa.sin_family != AF_INET || salen != sizeof(sa))
++ {
++ ngx_log_error(NGX_LOG_ERR, c->log, 0,
++ "non-ipv4 local address of mail connection ignored");
++ }
++ else
++ {
++ octets = (u_char *)&sa.sin_addr.s_addr;
++
++ ngx_log_error (NGX_LOG_WARN, c->log, 0,
++ "entering blocking network call (gethostbyaddr)");
++
++ host = gethostbyaddr(
++ &sa.sin_addr,
++ sizeof(sa.sin_addr),
++ AF_INET);
++
++ if (host == NULL)
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "cannot lookup host by IP address, err:%d",
++ h_errno);
++ }
++ else
++ {
++ ngx_log_error (NGX_LOG_INFO, c->log, 0,
++ "resolved incoming IP %d.%d.%d.%d to host:%s",
++ octets[0],
++ octets[1],
++ octets[2],
++ octets[3],
++ host->h_name);
++
++ fqdn = host->h_name;
++ }
++ }
++ }
++ else
++ {
++ ngx_log_error(NGX_LOG_ERR, c->log, 0,
++ "cannot get local address of mail connection, err:%d",
++ ngx_errno);
++ }
++ }
++
++ rc = sasl_server_new
++ (
++ service,
++ fqdn,
++ NULL,
++ NULL,
++ NULL,
++ callbacks,
++ 0,
++ &s->saslconn
++ );
++
++ if (rc != SASL_OK)
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "cannot create SASL context (%V), err:%d,%s",
++ &cscf->sasl_service_name,
++ rc, sasl_errstring (rc,NULL,NULL)
++ );
++ s->saslconn = NULL;
++ }
++ else
++ {
++ const char * mechlist;
++ unsigned menLen;
++ int num;
++ rc = sasl_listmech(s->saslconn, NULL, "{", ", ", "}", &mechlist, &menLen, &num);
++ ngx_log_error(NGX_LOG_INFO, c->log,0, "mech list is: %s", mechlist);
++ ngx_log_debug2 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "created SASL context (%V), 0x%p",
++ &cscf->sasl_service_name,
++ s->saslconn
++ );
++
++ rsec.min_ssf = 0;
++ rsec.max_ssf = 0;
++ rsec.maxbufsize = 4096;
++ rsec.property_names = NULL;
++ rsec.property_values = NULL;
++ rsec.security_flags = 0;
++
++ rc = sasl_setprop(s->saslconn, SASL_SEC_PROPS, &rsec);
++ }
++ }
++
++ return rc;
++}
++
++static void
++ngx_mail_dispose_sasl_context (ngx_mail_session_t *s)
++{
++ if (s->saslconn != NULL)
++ {
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL,s->connection->log,0,
++ "disposing SASL context:%p",s->saslconn);
++ sasl_dispose(&s->saslconn);
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL,s->connection->log,0,
++ "disposed SASL context:%p",s->saslconn);
++ s->saslconn = NULL;
++ }
++ return;
++}
++
++static int
++ngx_mail_sasl_startstep (
++ ngx_connection_t *c,
++ const char *mech,
++ ngx_str_t *response,
++ ngx_str_t *challenge
++ )
++{
++ ngx_mail_session_t *s;
++ ngx_str_t r;
++ int rc;
++ const char *saslstr,*authc,*authz;
++ unsigned sasls;
++ ngx_str_t ch64, ch;
++ ngx_mail_core_srv_conf_t *cscf;
++ u_char *p;
++ ngx_flag_t inheritAuthZ, needRealm;
++ size_t len;
++
++ s = c->data;
++ cscf = ngx_mail_get_module_srv_conf(s,ngx_mail_core_module);
++
++ /* saslfr (fr = first response) indicates whether the client has
++ issued at least one SASL response to the server
++ saslfr starts out as 0, and is immediately set to 1 when the
++ server starts processing the client responses
++ */
++ if (!s->saslfr)
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "beginning SASL auth negotiation");
++
++ if (response == NULL)
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "using NULL client response");
++
++ r.data = NULL;
++ r.len = 0;
++ }
++ else
++ {
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "using response %V", response);
++
++ r.len = ngx_base64_decoded_length (response->len);
++ r.data = ngx_palloc (c->pool, r.len);
++
++ if (r.data == NULL) {
++ return SASL_FAIL;
++ }
++
++ if (ngx_decode_base64 (&r, response) != NGX_OK)
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "invalid base64 response sent by client");
++
++ return SASL_FAIL;
++ }
++ else
++ {
++ ngx_log_debug2 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "%d bytes of base64-challenge decoded to %d sasl-bytes",
++ response->len, r.len);
++ }
++ }
++
++ rc = sasl_server_start
++ (
++ s->saslconn,
++ mech,
++ (char *)r.data,
++ r.len,
++ &saslstr,
++ &sasls
++ );
++
++ s->saslfr = 1;
++ }
++ else
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "continuing SASL auth negotiation");
++
++ r.len = ngx_base64_decoded_length (response->len);
++ r.data = ngx_palloc (c->pool, r.len);
++
++ if (r.data == NULL) {
++ return SASL_FAIL;
++ }
++
++ if (ngx_decode_base64 (&r, response) != NGX_OK)
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "invalid base64 response sent by client");
++
++ return SASL_FAIL;
++ }
++
++ rc = sasl_server_step
++ (
++ s->saslconn,
++ (char *)r.data,
++ r.len,
++ &saslstr,
++ &sasls
++ );
++ }
++
++ if ((rc != SASL_OK) && (rc != SASL_CONTINUE))
++ {
++ ngx_log_error (NGX_LOG_ERR, c->log, 0,
++ "SASL auth negotiation failed, err:%d (%s)",
++ rc, sasl_errstring(rc,NULL,NULL));
++ }
++ else
++ {
++ /* construct the challenge depending upon the protocol */
++
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "constructing protocol specific response for %d bytes of challenge",
++ sasls);
++
++ if (saslstr == NULL || sasls == 0)
++ {
++ ch64.data = (u_char *)"";
++ ch64.len = 0;
++ }
++ else
++ {
++ ch.len = sasls;
++ ch.data = (u_char *)saslstr;
++
++ ch64.len = ngx_base64_encoded_length(ch.len);
++ ch64.data = ngx_palloc (c->pool, ch64.len);
++
++ if (ch64.data == NULL) {
++ return SASL_FAIL;
++ }
++
++ ngx_encode_base64 (&ch64, &ch);
++ }
++
++ if (rc == SASL_CONTINUE)
++ {
++ /* For IMAP/POP, we need to send "+" SP CRLF */
++ if (s->protocol == NGX_MAIL_IMAP_PROTOCOL ||
++ s->protocol == NGX_MAIL_POP3_PROTOCOL
++ )
++ {
++ challenge->len = sizeof("+ ") -1 + ch64.len + sizeof(CRLF) -1;
++ challenge->data = ngx_palloc (c->pool,challenge->len);
++
++ if (challenge->data == NULL) {
++ return SASL_FAIL;
++ }
++
++ memcpy (challenge->data,"+ ",sizeof("+ ") - 1);
++ memcpy (challenge->data+sizeof("+ ")-1,ch64.data,ch64.len);
++ memcpy (challenge->data+sizeof("+ ")-1+ch64.len,CRLF,
++ sizeof(CRLF)-1);
++ }
++ else
++ {
++ challenge->data = ch64.data;
++ challenge->len = ch64.len;
++ }
++ }
++ else /* SASL_OK */
++ {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "SASL auth negotiation complete");
++
++ authc = NULL;
++ authz = NULL;
++
++ sasl_getprop(s->saslconn, SASL_AUTHUSER, (const void **)&authc);
++ sasl_getprop(s->saslconn, SASL_USERNAME, (const void **)&authz);
++
++ ngx_log_debug2 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "sasl: authc=%s,authz=%s",
++ authc == NULL ? "null" : authc,
++ authz == NULL ? "null" : authz
++ );
++
++ /* authc must always be present
++ if authc doesn't end in @realm, then we append the default realm
++ from the config file
++ */
++
++ /* s->login is authz if present, otherwise it is authc
++ */
++
++ if (authc == NULL)
++ {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL,c->log,0,
++ "sasl: cannot get authc, authentication will fail");
++ rc = SASL_BADAUTH;
++ }
++ else
++ {
++ if (strrchr(authc,'@') == NULL) {
++ needRealm = 1;
++ } else {
++ needRealm = 0;
++ }
++
++ if ((authz == NULL) || (ngx_strcmp(authc,authz) == 0)) {
++ inheritAuthZ = 1;
++ } else {
++ inheritAuthZ = 0;
++ }
++
++ len = ngx_strlen(authc);
++
++ if (needRealm) {
++ if (cscf->default_realm.len > 0) {
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL,c->log,0,
++ "No realm found in AUTHC, using config default %V", &cscf->default_realm);
++ len += (1 + cscf->default_realm.len);
++ } else {
++ ngx_log_error(NGX_LOG_ERR,c->log, 0,
++ "SASL realm required, but no realm found in authenticating principal");
++ ngx_log_error(NGX_LOG_ERR,c->log, 0,
++ "Authentication will fail. Set the `default_realm' variable to the default kerberos realm");
++ }
++ }
++
++ s->authid.data = ngx_palloc(c->pool,len);
++ if (s->authid.data == NULL) {
++ s->authid.data = (u_char *)"";
++ s->authid.len = 0;
++ rc = SASL_NOMEM;
++ } else {
++ s->authid.len = len;
++ p = s->authid.data;
++ p = ngx_cpymem (p,authc,strlen(authc));
++
++ if (needRealm) {
++ if (cscf->default_realm.len > 0) {
++ *p++ = '@';
++ p = ngx_cpymem (p,cscf->default_realm.data,cscf->default_realm.len);
++ }
++ }
++ }
++
++ if (inheritAuthZ) {
++ /* no separate authz was specified, or authz was same as authc
++ therefore the same changes made to authc must apply to authz
++ */
++ s->login.data = ngx_pstrdup(c->pool,&s->authid);
++ if (s->login.data == NULL) {
++ s->login.data = (u_char*)"";
++ s->login.len = 0;
++ rc = SASL_NOMEM;
++ } else {
++ s->login.len = s->authid.len;
++ }
++ } else {
++ /* a separate authz was specified */
++ s->login.len = ngx_strlen(authz);
++ s->login.data = ngx_palloc(c->pool,s->login.len);
++ if (s->login.data == NULL) {
++ s->login.data = (u_char*)"";
++ s->login.len = 0;
++ rc = SASL_NOMEM;
++ } else {
++ ngx_memcpy(s->login.data,authz,s->login.len);
++ }
++ }
++ }
++
++ if(rc == SASL_OK)
++ {
++ ngx_log_debug2(NGX_LOG_DEBUG_MAIL,c->log,0,
++ "sasl: auth exchange completed, login:%V, authc:%V",
++ &s->login, &s->authid);
++ }
++
++ /* we don't need the SASL object after authentication because
++ we don't negotiate a security layer with any ssf
++ */
++
++ ngx_mail_dispose_sasl_context(s);
++ }
++ }
++
++ return rc;
++}
++
++
++ngx_int_t
+ ngx_mail_auth_external(ngx_mail_session_t *s, ngx_connection_t *c,
+ ngx_uint_t n)
+ {
+@@ -794,7 +1782,7 @@
+ }
+
+ if (s->quit) {
+- ngx_mail_close_connection(c);
++ ngx_mail_end_session(s);
+ return;
+ }
+
+@@ -825,6 +1813,84 @@
+ }
+
+
++void
++ngx_mail_do_auth(ngx_mail_session_t *s, ngx_connection_t *c)
++{
++ throttle_callback_t *callback;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_mail_zmauth_conf_t *zmcf;
++
++ zmcf = (ngx_mail_zmauth_conf_t *)ngx_mail_get_module_srv_conf(s, ngx_mail_zmauth_module);
++ if (zmcf->use_zmauth != 1) {
++ s->qlogin = s->login;
++ ngx_mail_auth(s, c);
++ return;
++ }
++
++ /* all auth mechanisms for all protocols pass through ngx_mail_do_auth()
++ here. Therefore, it is best to just look at the zimbra extensions
++ *once* at this point, rather than peppering that code all across
++ */
++
++ if (has_zimbra_extensions(s->login)) {
++ s->zlogin = get_zimbra_extension(s->login);
++ s->login.len -= s->zlogin.len;
++ } else {
++ s->zlogin.data = (u_char *)"";
++ s->zlogin.len = 0;
++ }
++
++ if (s->usedauth)
++ {
++ if (has_zimbra_extensions(s->dusr)) {
++ s->zusr = get_zimbra_extension(s->dusr);
++ s->dusr.len -= s->zusr.len;
++ } else {
++ s->zusr.data = (u_char *)"";
++ s->zusr.len = 0;
++ }
++ }
++
++ if (s->usedauth) {
++ /* technically, zimbra extensions are not allowed in authc
++ but it is too troublesome to reject the login appropriately
++ at this point (with the correct message), therefore it is
++ less bother to just pass the authc + {wm,ni,tb} to upstream
++ */
++ if (s->login.len == s->dusr.len &&
++ ngx_memcmp(s->login.data, s->dusr.data, s->login.len) == 0) {
++ s->qualifydauth = 1;
++ }
++ }
++
++ callback = ngx_pcalloc(c->pool, sizeof(throttle_callback_t));
++ if (callback == NULL) {
++ ngx_mail_session_internal_server_error(s);
++ return;
++ }
++
++ callback->check_only = 1; /* just check the counter's value */
++ callback->session = s;
++ callback->connection = c;
++ callback->log = ngx_cycle->log;
++ callback->pool = c->pool;
++ callback->on_allow = ngx_mail_allow_userauth;
++ callback->on_deny = ngx_mail_choke_userauth;
++
++ /* because of DOS attacks against legitimate users, throttling is
++ postponed till after authentication
++ */
++ tscf = ngx_mail_get_module_srv_conf (s, ngx_mail_throttle_module);
++ if (tscf->mail_login_user_max == 0) {
++ callback->on_allow(callback);
++ } else {
++ ngx_mail_throttle_user(s->login, callback);
++ }
++
++ /* previous body of ngx_mail_do_auth() now in ngx_mail_allow_userauth */
++}
++
++
+ ngx_int_t
+ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
+ {
+@@ -922,17 +1988,72 @@
+ }
+
+
++/* send a protocol-suitable internal error message to downstream
++ close the downstream connection immediately afterwards
++ */
+ void
+ ngx_mail_session_internal_server_error(ngx_mail_session_t *s)
+ {
+ ngx_mail_core_srv_conf_t *cscf;
++ ngx_connection_t *c;
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
+
+ s->out = cscf->protocol->internal_server_error;
+- s->quit = 1;
+
++ c = s->connection->write->data;
+ ngx_mail_send(s->connection->write);
++ if (c->destroyed) {
++ return;
++ }
++ /* clean up */
++ ngx_mail_cleanup_t * cln = s->cleanup;
++ while (cln != NULL) {
++ cln->handler(cln->data);
++ cln = cln->next;
++ }
++
++ ngx_mail_close_connection (s->connection);
++}
++
++
++/* send a protocol-suitable bye message to downstream
++ close the downstream connection immediately afterwards
++ */
++void
++ngx_mail_end_session(ngx_mail_session_t *s)
++{
++ ngx_str_t bye = ngx_mail_session_getquitmsg(s);
++ ngx_connection_t *c = s->connection;
++
++ if (bye.len > 0) {
++ c->send(c, bye.data, bye.len);
++ }
++
++ /* clean up */
++ ngx_mail_cleanup_t * cln = s->cleanup;
++ while (cln != NULL) {
++ cln->handler(cln->data);
++ cln = cln->next;
++ }
++
++ ngx_mail_close_connection (c);
++}
++
++/* return protocol-specific bye message */
++ngx_str_t ngx_mail_session_getquitmsg(ngx_mail_session_t *s)
++{
++ ngx_mail_core_srv_conf_t *cscf;
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++ return cscf->protocol->quit_msg;
++}
++
++/* return protocol-specific internal error message */
++ngx_str_t ngx_mail_session_geterrmsg(ngx_mail_session_t *s)
++{
++ ngx_mail_core_srv_conf_t *cscf;
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++ return cscf->protocol->internal_server_error;
+ }
+
+
+@@ -969,6 +2090,13 @@
+ }
+
+
++/* note -- we want to log the local and remote host/port information for the
++ mail proxy sessions. however, nginx allows a mail servers to be specified as
++ listening on a unix domain socket. the code below assumes that the sockaddr
++ structure is pointing to an IPv4 address, and prints the address information
++ accordingly. we will need to modify the code in case we want to support
++ printing of unix domain socket information
++ */
+ u_char *
+ ngx_mail_log_error(ngx_log_t *log, u_char *buf, size_t len)
+ {
+@@ -984,7 +2112,11 @@
+
+ ctx = log->data;
+
+- p = ngx_snprintf(buf, len, ", client: %V", ctx->client);
++ if (ctx->client_port && ctx->client_port < 65536) {
++ p = ngx_snprintf(buf, len, ", client: %V:%ui", ctx->client, ctx->client_port);
++ } else {
++ p = ngx_snprintf(buf, len, ", client: %V", ctx->client, ctx->client_port);
++ }
+ len -= p - buf;
+ buf = p;
+
+@@ -1012,7 +2144,127 @@
+ return p;
+ }
+
++ /* with proxy, output the proxy relationship */
++
++ u_char dw_host[NGX_SOCKADDRLEN],
++ dw_peer[NGX_SOCKADDRLEN],
++ up_host[NGX_SOCKADDRLEN],
++ up_peer[NGX_SOCKADDRLEN];
++
++ socklen_t dw_host_len, dw_peer_len,
++ up_host_len, up_peer_len,
++ n;
++
++ ngx_memzero (dw_peer, NGX_SOCKADDRLEN);
++ ngx_memzero (dw_host, NGX_SOCKADDRLEN);
++ ngx_memzero (up_host, NGX_SOCKADDRLEN);
++ ngx_memzero (up_peer, NGX_SOCKADDRLEN);
++
++ dw_host_len = dw_peer_len = up_host_len = up_peer_len = NGX_SOCKADDRLEN;
++
++ if (s->connection) {
++ getsockname
++ (s->connection->fd, (struct sockaddr *)dw_host, &dw_host_len);
++
++ getpeername
++ (s->connection->fd, (struct sockaddr *)dw_peer, &dw_peer_len);
++ }
++
++ if (s->proxy->upstream.connection) {
++ getsockname (s->proxy->upstream.connection->fd,
++ (struct sockaddr *)up_host, &up_host_len);
++ getpeername (s->proxy->upstream.connection->fd,
++ (struct sockaddr *)up_peer, &up_peer_len);
++ }
++
+ p = ngx_snprintf(buf, len, ", upstream: %V", s->proxy->upstream.name);
+
++ len -= p - buf;
++ buf = p;
++
++ /* generate "(dw_peer->dw_host) <=> (up_host->up_peer)" */
++ p = ngx_snprintf(buf, len, " (");
++ len -= p - buf;
++ buf = p;
++
++ n = ngx_sock_ntop((struct sockaddr *)dw_peer, dw_peer_len, buf, len, 1);
++ len -= n;
++ buf += n;
++
++ *buf++ = '-';
++ len--;
++ *buf++ = '>';
++ len--;
++
++ n = ngx_sock_ntop((struct sockaddr *)dw_host, dw_host_len, buf, len, 1);
++ len -= n;
++ buf += n;
++
++ p = ngx_snprintf(buf, len, ") <=> (");
++ len -= p - buf;
++ buf = p;
++
++ n = ngx_sock_ntop((struct sockaddr *)up_host, up_host_len, buf, len, 1);
++ len -= n;
++ buf += n;
++
++ *buf++ = '-';
++ len--;
++ *buf++ = '>';
++ len--;
++
++ n = ngx_sock_ntop((struct sockaddr *)up_peer, up_peer_len, buf, len, 1);
++ len -= n;
++ buf += n;
++
++ *buf++ = ')';
++ len--;
++
++ p = buf;
++
+ return p;
+ }
++
++
++/*
++ * Giving a socket, return its local addr string representation IP. The
++ * string will be allocated on "pool".
++ */
++ngx_str_t ngx_mail_get_socket_local_addr_str (ngx_pool_t *pool, ngx_socket_t s)
++{
++ int family;
++ static ngx_str_t res;
++ struct sockaddr_in *sin;
++#if (NGX_HAVE_INET6)
++ struct sockaddr_in6 *sin6;
++#endif
++ u_char *p;
++ socklen_t len, strlen;
++ u_char sockaddr[NGX_SOCKADDRLEN];
++
++ len = NGX_SOCKADDRLEN;
++ ngx_memzero(sockaddr, len);
++ getsockname(s, (struct sockaddr*)sockaddr, &len);
++
++ family = ((struct sockaddr *)sockaddr)->sa_family;
++ if (family == AF_INET) {
++ sin = (struct sockaddr_in *)sockaddr;
++ p = ngx_palloc(pool, NGX_INET_ADDRSTRLEN);
++ strlen = ngx_inet_ntop (family, &(sin->sin_addr.s_addr), p,
++ NGX_INET_ADDRSTRLEN);
++
++#if (NGX_HAVE_INET6)
++ } else {
++ sin6 = (struct sockaddr_in6 *)sockaddr;
++ p = ngx_palloc(pool, NGX_INET6_ADDRSTRLEN);
++ strlen = ngx_inet_ntop (family, &(sin6->sin6_addr.s6_addr),
++ p, NGX_INET6_ADDRSTRLEN);
++#endif
++
++ }
++
++ res.data = p;
++ res.len = strlen;
++
++ return res;
++}
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_handler.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_handler.patch
new file mode 100644
index 000000000..31b3cc899
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_handler.patch
@@ -0,0 +1,462 @@
+--- nginx/src/mail/ngx_mail_imap_handler.c 2023-03-07 16:26:44.718094500 +0530
++++ nginx/src/mail/ngx_mail_imap_handler.c 2023-09-14 18:47:12.625941200 +0530
+@@ -20,27 +20,34 @@
+ ngx_connection_t *c);
+ static ngx_int_t ngx_mail_imap_starttls(ngx_mail_session_t *s,
+ ngx_connection_t *c);
++static ngx_int_t ngx_mail_imap_id(ngx_mail_session_t *s,
++ ngx_connection_t *c);
+
+-
+-static u_char imap_greeting[] = "* OK IMAP4 ready" CRLF;
+-static u_char imap_star[] = "* ";
++static u_char imap_star[] = "*";
+ static u_char imap_ok[] = "OK completed" CRLF;
+-static u_char imap_next[] = "+ OK" CRLF;
++static u_char imap_next[] = "+ " CRLF;
+ static u_char imap_plain_next[] = "+ " CRLF;
++static u_char imap_gssapi_next[] = "+ " CRLF;
+ static u_char imap_username[] = "+ VXNlcm5hbWU6" CRLF;
+ static u_char imap_password[] = "+ UGFzc3dvcmQ6" CRLF;
+-static u_char imap_bye[] = "* BYE" CRLF;
+ static u_char imap_invalid_command[] = "BAD invalid command" CRLF;
++static u_char imap_unsupported_mech[] = "NO mechanism not supported" CRLF;
++static u_char imap_nocleartext[] = "NO cleartext logins disabled" CRLF;
++static u_char imap_authaborted[] = "BAD AUTHENTICATE aborted" CRLF;
++static u_char imap_login_failed[] = "NO LOGIN failed" CRLF;
++static u_char imap_authenticate_failed[] = "NO AUTHENTICATE failed" CRLF;
+
+
+ void
+ ngx_mail_imap_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
+ {
+ ngx_mail_core_srv_conf_t *cscf;
++ ngx_mail_imap_srv_conf_t *iscf;
+
+ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++ iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
+
+- ngx_str_set(&s->out, imap_greeting);
++ s->out = iscf->greeting;
+
+ c->read->handler = ngx_mail_imap_init_protocol;
+
+@@ -91,6 +98,7 @@
+ }
+ }
+
++ ngx_mail_set_imap_parse_state_start(s);
+ s->mail_state = ngx_imap_start;
+ c->read->handler = ngx_mail_imap_auth_state;
+
+@@ -115,7 +123,7 @@
+ if (rev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
+ c->timedout = 1;
+- ngx_mail_close_connection(c);
++ ngx_mail_end_session(s); /* send IMAP BYE on timeout */
+ return;
+ }
+
+@@ -149,8 +157,8 @@
+ }
+
+ tag = 1;
+- s->text.len = 0;
+ ngx_str_set(&s->out, imap_ok);
++ s->text.len = 0;
+
+ if (rc == NGX_OK) {
+
+@@ -169,7 +177,6 @@
+
+ case NGX_IMAP_AUTHENTICATE:
+ rc = ngx_mail_imap_authenticate(s, c);
+- tag = (rc != NGX_OK);
+ break;
+
+ case NGX_IMAP_CAPABILITY:
+@@ -178,7 +185,6 @@
+
+ case NGX_IMAP_LOGOUT:
+ s->quit = 1;
+- ngx_str_set(&s->text, imap_bye);
+ break;
+
+ case NGX_IMAP_NOOP:
+@@ -188,6 +194,10 @@
+ rc = ngx_mail_imap_starttls(s, c);
+ break;
+
++ case NGX_IMAP_ID:
++ rc = ngx_mail_imap_id(s, c);
++ break;
++
+ default:
+ rc = NGX_MAIL_PARSE_INVALID_COMMAND;
+ break;
+@@ -198,10 +208,10 @@
+ case ngx_imap_auth_login_username:
+ rc = ngx_mail_auth_login_username(s, c, 0);
+
+- tag = 0;
+- ngx_str_set(&s->out, imap_password);
+- s->mail_state = ngx_imap_auth_login_password;
+-
++ if (rc == NGX_MAIL_AUTH_ARGUMENT) {
++ ngx_str_set(&s->out, imap_password);
++ s->mail_state = ngx_imap_auth_login_password;
++ }
+ break;
+
+ case ngx_imap_auth_login_password:
+@@ -212,6 +222,18 @@
+ rc = ngx_mail_auth_plain(s, c, 0);
+ break;
+
++ case ngx_imap_auth_gssapi:
++ {
++ ngx_str_t output;
++ ngx_str_set(&output, "");
++ rc = ngx_mail_auth_gssapi(s, c, &output);
++ if (rc == NGX_MAIL_AUTH_ARGUMENT) {
++ s->mail_state = ngx_imap_auth_gssapi;
++ s->out = output;
++ }
++ break;
++ }
++
+ case ngx_imap_auth_cram_md5:
+ rc = ngx_mail_auth_cram_md5(s, c);
+ break;
+@@ -233,17 +255,75 @@
+ switch (rc) {
+
+ case NGX_DONE:
+- ngx_mail_auth(s, c);
++ ngx_mail_do_auth(s, c);
+ return;
+
++ case NGX_OK:
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
++ case NGX_MAIL_AUTH_ABORT:
++ ngx_str_set(&s->out, imap_authaborted);
++ s->mail_state = ngx_imap_start;
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
+ case NGX_ERROR:
+ ngx_mail_session_internal_server_error(s);
+ return;
+
++ case NGX_MAIL_AUTH_FAILED:
++ ngx_str_set(&s->out, imap_authenticate_failed);
++ s->mail_state = ngx_imap_start;
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
++ case NGX_MAIL_LOGIN_FAILED:
++ ngx_str_set(&s->out, imap_login_failed);
++ s->mail_state = ngx_imap_start;
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
++ case NGX_MAIL_PARSE_INVALID_AUTH_MECH:
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "unsupported IMAP auth mechanism");
++ ngx_str_set(&s->out, imap_unsupported_mech);
++ s->mail_state = ngx_imap_start;
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
+ case NGX_MAIL_PARSE_INVALID_COMMAND:
+- s->state = 0;
+ ngx_str_set(&s->out, imap_invalid_command);
+ s->mail_state = ngx_imap_start;
++ ngx_mail_set_imap_parse_state_start(s);
++ s->arg_start = NULL;
++ ngx_mail_reset_parse_buffer(s);
++ break;
++
++ case NGX_MAIL_AUTH_ARGUMENT:
++ ngx_mail_set_imap_parse_state_argument(s);
++ /* preserve tag, since tag's memory is allocated in buffer, need to set the
++ * buffer pos after tag */
++ s->arg_start = s->buffer->start + s->tag.len;
++ s->buffer->pos = s->arg_start;
++ s->buffer->last = s->arg_start;
++ tag = 0; // just output s->out
++ break;
++
++ case NGX_IMAP_NEXT:
++ /* do nothing, preserve all the state, including s->state, s->mail_state,
++ * , s->buffer, s->arg_start
++ */
+ break;
+ }
+
+@@ -252,8 +332,8 @@
+ ngx_str_set(&s->tag, imap_star);
+ }
+
+- if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len) {
+- s->tagged_line.len = s->tag.len + s->text.len + s->out.len;
++ if (s->tagged_line.len < s->tag.len + s->text.len + s->out.len + 1) {
++ s->tagged_line.len = s->tag.len + s->text.len + s->out.len + 1;
+ s->tagged_line.data = ngx_pnalloc(c->pool, s->tagged_line.len);
+ if (s->tagged_line.data == NULL) {
+ ngx_mail_close_connection(c);
+@@ -268,9 +348,10 @@
+ }
+
+ p = ngx_cpymem(p, s->tag.data, s->tag.len);
++ *p++ = ' '; /* the space between tag and out */
+ ngx_memcpy(p, s->out.data, s->out.len);
+
+- s->out.len = s->text.len + s->tag.len + s->out.len;
++ s->out.len = s->text.len + s->tag.len + 1 /*for space*/ + s->out.len;
+ s->out.data = s->tagged_line.data;
+ }
+
+@@ -283,8 +364,8 @@
+
+ } else {
+ if (s->buffer->pos == s->buffer->last) {
+- s->buffer->pos = s->buffer->start;
+- s->buffer->last = s->buffer->start;
++ s->buffer->pos = s->buffer->start;
++ s->buffer->last = s->buffer->start;
+ }
+
+ s->tag.len = 0;
+@@ -307,6 +388,7 @@
+
+ #if (NGX_MAIL_SSL)
+ if (ngx_mail_starttls_only(s, c)) {
++ ngx_str_set(&s->text, imap_nocleartext);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ #endif
+@@ -317,6 +399,10 @@
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
++ if (arg[0].len > NGX_MAIL_MAX_LOGIN_LEN) {
++ return NGX_MAIL_LOGIN_FAILED;
++ }
++
+ s->login.len = arg[0].len;
+ s->login.data = ngx_pnalloc(c->pool, s->login.len);
+ if (s->login.data == NULL) {
+@@ -325,6 +411,10 @@
+
+ ngx_memcpy(s->login.data, arg[0].data, s->login.len);
+
++ if (arg[1].len > NGX_MAIL_MAX_PASSWORD_LEN) {
++ return NGX_MAIL_LOGIN_FAILED;
++ }
++
+ s->passwd.len = arg[1].len;
+ s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len);
+ if (s->passwd.data == NULL) {
+@@ -342,6 +432,8 @@
+ "imap login:\"%V\"", &s->login);
+ #endif
+
++ s->auth_method = NGX_MAIL_AUTH_PASSWD;
++ s->usedauth = 0;
+ return NGX_DONE;
+ }
+
+@@ -349,7 +441,7 @@
+ static ngx_int_t
+ ngx_mail_imap_authenticate(ngx_mail_session_t *s, ngx_connection_t *c)
+ {
+- ngx_int_t rc;
++ ngx_int_t rc, res;
+ ngx_mail_core_srv_conf_t *cscf;
+ ngx_mail_imap_srv_conf_t *iscf;
+
+@@ -359,37 +451,85 @@
+ }
+ #endif
+
+- iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
+-
+ rc = ngx_mail_auth_parse(s, c);
+
++ iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
++
+ switch (rc) {
+
+ case NGX_MAIL_AUTH_LOGIN:
+
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
+ ngx_str_set(&s->out, imap_username);
+ s->mail_state = ngx_imap_auth_login_username;
+
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
+
+ case NGX_MAIL_AUTH_LOGIN_USERNAME:
+
+- ngx_str_set(&s->out, imap_password);
+- s->mail_state = ngx_imap_auth_login_password;
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++
++ res = ngx_mail_auth_login_username(s, c, 1);
++ if (res == NGX_MAIL_AUTH_ARGUMENT) {
++ ngx_str_set(&s->out, imap_password);
++ s->mail_state = ngx_imap_auth_login_password;
++ return NGX_MAIL_AUTH_ARGUMENT;
++ } else {
++ return res;
++ }
+
+- return ngx_mail_auth_login_username(s, c, 1);
+
+ case NGX_MAIL_AUTH_PLAIN:
+
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
+ ngx_str_set(&s->out, imap_plain_next);
+ s->mail_state = ngx_imap_auth_plain;
+
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
++
++ case NGX_MAIL_AUTH_PLAIN_IR:
++
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ return ngx_mail_auth_plain(s, c, 1);
++
++ case NGX_MAIL_AUTH_GSSAPI:
++
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ ngx_str_set(&s->out, imap_gssapi_next);
++ s->mail_state = ngx_imap_auth_gssapi;
++
++ return NGX_MAIL_AUTH_ARGUMENT;
++
++ case NGX_MAIL_AUTH_GSSAPI_IR:
++
++ if (!(iscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ s->mail_state = ngx_imap_auth_gssapi;
++ ngx_str_t output;
++ ngx_str_set(&output, "");
++ res = ngx_mail_auth_gssapi(s, c, &output);
++ if(res == NGX_MAIL_AUTH_ARGUMENT) {
++ s->out = output;
++ return NGX_MAIL_AUTH_ARGUMENT;
++ } else {
++ return res;
++ }
+
+ case NGX_MAIL_AUTH_CRAM_MD5:
+
+ if (!(iscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
+- return NGX_MAIL_PARSE_INVALID_COMMAND;
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+ }
+
+ if (s->salt.data == NULL) {
+@@ -402,7 +542,7 @@
+
+ if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
+ s->mail_state = ngx_imap_auth_cram_md5;
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
+ }
+
+ return NGX_ERROR;
+@@ -475,3 +615,67 @@
+
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
++
++
++static ngx_int_t
++ngx_mail_imap_id(ngx_mail_session_t *s, ngx_connection_t * c)
++{
++ size_t i;
++ ngx_mail_imap_srv_conf_t *iscf;
++ ngx_str_t *key, * value;
++
++ iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL,s->connection->log,0,
++ "imap id received %d parameters from client", s->args.nelts);
++ if (s->args.nelts) {
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "client ID params [%d pair(s)]",
++ s->args.nelts/2);
++ for (i = 0; i < s->args.nelts / 2; ++i) {
++ ngx_log_debug3 (NGX_LOG_DEBUG_MAIL,
++ s->connection->log, 0,
++ "[pair %d] field:'%V' value:'%V'",
++ i+1,
++ (ngx_str_t*)s->args.elts + 2 * i,
++ (ngx_str_t*)s->args.elts + 2 * i + 1
++ );
++ key = (ngx_str_t*)s->args.elts + 2 * i;
++ /* bug 64978, add support to "name" and "version" field */
++ if (key->len == sizeof ("name") - 1 &&
++ (key->data[0] == 'N' || key->data[0] == 'n') &&
++ (key->data[1] == 'A' || key->data[1] == 'a') &&
++ (key->data[2] == 'M' || key->data[2] == 'm') &&
++ (key->data[3] == 'E' || key->data[3] == 'e')) {
++ value = (ngx_str_t*)s->args.elts + 2 * i + 1;
++
++ s->id_name.data = ngx_pnalloc(c->pool, value->len);
++ if (s->id_name.data == NULL) {
++ return NGX_ERROR;
++ }
++
++ ngx_memcpy(s->id_name.data, value->data, value->len);
++ s->id_name.len = value->len;
++ } else if (key->len == sizeof ("version") - 1 &&
++ (key->data[0] == 'V' || key->data[0] == 'v') &&
++ (key->data[1] == 'E' || key->data[1] == 'e') &&
++ (key->data[2] == 'R' || key->data[2] == 'r') &&
++ (key->data[3] == 'S' || key->data[3] == 's') &&
++ (key->data[4] == 'I' || key->data[4] == 'i') &&
++ (key->data[5] == 'O' || key->data[5] == 'o') &&
++ (key->data[6] == 'N' || key->data[6] == 'n')) {
++ value = (ngx_str_t*)s->args.elts + 2 * i + 1;
++
++ s->id_version.data = ngx_pnalloc(c->pool, value->len);
++ if (s->id_version.data == NULL) {
++ return NGX_ERROR;
++ }
++
++ ngx_memcpy(s->id_version.data, value->data, value->len);
++ s->id_version.len = value->len;
++ }
++ }
++ }
++ s->text = iscf->id;
++
++ return NGX_OK;
++}
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_c.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_c.patch
new file mode 100644
index 000000000..8f83bbbee
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_c.patch
@@ -0,0 +1,420 @@
+--- nginx/src/mail/ngx_mail_imap_module.c 2023-03-07 16:26:44.721101600 +0530
++++ nginx/src/mail/ngx_mail_imap_module.c 2023-09-14 18:47:12.632886600 +0530
+@@ -15,7 +15,9 @@
+ static void *ngx_mail_imap_create_srv_conf(ngx_conf_t *cf);
+ static char *ngx_mail_imap_merge_srv_conf(ngx_conf_t *cf, void *parent,
+ void *child);
++static char *ngx_mail_imap_id (ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
++static ngx_str_t default_imap_greeting = ngx_string("* OK IMAP4rev1 proxy server ready");
+
+ static ngx_str_t ngx_mail_imap_default_capabilities[] = {
+ ngx_string("IMAP4"),
+@@ -30,18 +32,20 @@
+ { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
+ { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
+ { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
++ { ngx_string("gssapi"), NGX_MAIL_AUTH_GSSAPI_ENABLED },
+ { ngx_null_string, 0 }
+ };
+
+
++/* zimbra's merge_conf method doesn't use this
+ static ngx_str_t ngx_mail_imap_auth_methods_names[] = {
+ ngx_string("AUTH=PLAIN"),
+ ngx_string("AUTH=LOGIN"),
+- ngx_null_string, /* APOP */
++ ngx_null_string, // APOP
+ ngx_string("AUTH=CRAM-MD5"),
+ ngx_string("AUTH=EXTERNAL"),
+- ngx_null_string /* NONE */
+-};
++ ngx_null_string // NONE
++};*/
+
+
+ static ngx_mail_protocol_t ngx_mail_imap_protocol = {
+@@ -57,7 +61,8 @@
+
+ ngx_string("* BAD internal server error" CRLF),
+ ngx_string("* BYE SSL certificate error" CRLF),
+- ngx_string("* BYE No required SSL certificate" CRLF)
++ ngx_string("* BYE No required SSL certificate" CRLF),
++ ngx_string("* BYE IMAP server terminating connection" CRLF)
+ };
+
+
+@@ -77,6 +82,13 @@
+ offsetof(ngx_mail_imap_srv_conf_t, capabilities),
+ NULL },
+
++ { ngx_string("imap_id"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
++ ngx_mail_imap_id,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_imap_srv_conf_t, id_params),
++ NULL },
++
+ { ngx_string("imap_auth"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+ ngx_conf_set_bitmask_slot,
+@@ -84,6 +96,20 @@
+ offsetof(ngx_mail_imap_srv_conf_t, auth_methods),
+ &ngx_mail_imap_auth_methods },
+
++ { ngx_string("imap_literalauth"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_imap_srv_conf_t, literalauth),
++ NULL },
++
++ { ngx_string("imap_greeting"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_imap_srv_conf_t, greeting),
++ NULL },
++
+ ngx_null_command
+ };
+
+@@ -133,6 +159,17 @@
+ return NULL;
+ }
+
++ if (ngx_array_init(&iscf->id_params, cf->pool, 4, sizeof(ngx_str_t))
++ != NGX_OK)
++ {
++ return NULL;
++ }
++
++ iscf->literalauth = NGX_CONF_UNSET;
++
++ ngx_str_null(&iscf->ua_name);
++ ngx_str_null(&iscf->ua_version);
++
+ return iscf;
+ }
+
+@@ -143,20 +180,23 @@
+ ngx_mail_imap_srv_conf_t *prev = parent;
+ ngx_mail_imap_srv_conf_t *conf = child;
+
+- u_char *p, *auth;
+- size_t size;
++ u_char *p, *p1, *p2, *p3;
++ size_t size, s1, s2, s3;
+ ngx_str_t *c, *d;
+- ngx_uint_t i, m;
++ ngx_uint_t i;
+
+ ngx_conf_merge_size_value(conf->client_buffer_size,
+ prev->client_buffer_size,
+- (size_t) ngx_pagesize);
++ (size_t) 4 * ngx_pagesize);
+
+ ngx_conf_merge_bitmask_value(conf->auth_methods,
+ prev->auth_methods,
+ (NGX_CONF_BITMASK_SET
+ |NGX_MAIL_AUTH_PLAIN_ENABLED));
+
++ if (conf->id_params.nelts == 0) {
++ conf->id_params = prev->id_params;
++ }
+
+ if (conf->capabilities.nelts == 0) {
+ conf->capabilities = prev->capabilities;
+@@ -174,85 +214,245 @@
+ }
+ }
+
+- size = sizeof("* CAPABILITY" CRLF) - 1;
++ s1 = sizeof("* CAPABILITY" CRLF) - 1;
++ s2 = s1;
++ s3 = s1;
+
+ c = conf->capabilities.elts;
+ for (i = 0; i < conf->capabilities.nelts; i++) {
+- size += 1 + c[i].len;
++ s1 += 1 + c[i].len;
++ s2 += 1 + c[i].len;
++ s3 += 1 + c[i].len;
+ }
+
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
+- {
+- if (m & conf->auth_methods) {
+- size += 1 + ngx_mail_imap_auth_methods_names[i].len;
+- }
++ if (conf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED) {
++ s1 += sizeof (" AUTH=LOGIN") - 1;
++ s2 += sizeof (" AUTH=LOGIN") - 1;
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
++ s1 += sizeof (" AUTH=PLAIN") - 1;
++ s2 += sizeof (" AUTH=PLAIN") - 1;
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
++ s1 += sizeof (" AUTH=CRAM-MD5") - 1;
++ s2 += sizeof (" AUTH=CRAM-MD5") - 1;
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED) {
++ s1 += sizeof (" AUTH=GSSAPI") - 1;
++ s2 += sizeof (" AUTH=GSSAPI") - 1;
++ s3 += sizeof (" AUTH=GSSAPI") - 1;
+ }
+
+- p = ngx_pnalloc(cf->pool, size);
+- if (p == NULL) {
++ s2 += sizeof (" STARTTLS") - 1;
++ s3 += sizeof (" STARTTLS") - 1;
++ s3 += sizeof (" LOGINDISABLED") - 1;
++
++ p1 = ngx_palloc(cf->pool, s1);
++ if (p1 == NULL) {
++ return NGX_CONF_ERROR;
++ }
++ p2 = ngx_palloc(cf->pool, s2);
++ if (p2 == NULL) {
++ return NGX_CONF_ERROR;
++ }
++ p3 = ngx_palloc(cf->pool, s3);
++ if (p3 == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+- conf->capability.len = size;
+- conf->capability.data = p;
++ conf->capability.len = s1;
++ conf->capability.data = p1;
+
+- p = ngx_cpymem(p, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
++ conf->starttls_capability.len = s2;
++ conf->starttls_capability.data = p2;
+
+- for (i = 0; i < conf->capabilities.nelts; i++) {
+- *p++ = ' ';
+- p = ngx_cpymem(p, c[i].data, c[i].len);
+- }
++ conf->starttls_only_capability.len = s3;
++ conf->starttls_only_capability.data = p3;
+
+- auth = p;
++ p1 = ngx_cpymem(p1, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
++ p2 = ngx_cpymem(p2, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
++ p3 = ngx_cpymem(p3, "* CAPABILITY", sizeof("* CAPABILITY") - 1);
+
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
+- {
+- if (m & conf->auth_methods) {
+- *p++ = ' ';
+- p = ngx_cpymem(p, ngx_mail_imap_auth_methods_names[i].data,
+- ngx_mail_imap_auth_methods_names[i].len);
+- }
++ c = conf->capabilities.elts;
++ for (i = 0; i < conf->capabilities.nelts; i++) {
++ *p1++ = ' ';
++ p1 = ngx_cpymem(p1,c[i].data,c[i].len);
++ *p2++ = ' ';
++ p2 = ngx_cpymem(p2,c[i].data,c[i].len);
++ *p3++ = ' ';
++ p3 = ngx_cpymem(p3,c[i].data,c[i].len);
++ }
++
++ if (conf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED) {
++ p1 = ngx_cpymem(p1," AUTH=LOGIN", sizeof(" AUTH=LOGIN") - 1);
++ p2 = ngx_cpymem(p2," AUTH=LOGIN", sizeof(" AUTH=LOGIN") - 1);
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
++ p1 = ngx_cpymem(p1," AUTH=PLAIN", sizeof(" AUTH=PLAIN") - 1);
++ p2 = ngx_cpymem(p2," AUTH=PLAIN", sizeof(" AUTH=PLAIN") - 1);
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
++ p1 = ngx_cpymem(p1," AUTH=CRAM-MD5", sizeof(" AUTH=CRAM-MD5") - 1);
++ p2 = ngx_cpymem(p2," AUTH=CRAM-MD5", sizeof(" AUTH=CRAM-MD5") - 1);
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED) {
++ p1 = ngx_cpymem(p1," AUTH=GSSAPI", sizeof(" AUTH=GSSAPI") - 1);
++ p2 = ngx_cpymem(p2," AUTH=GSSAPI", sizeof(" AUTH=GSSAPI") - 1);
++ p3 = ngx_cpymem(p3," AUTH=GSSAPI", sizeof(" AUTH=GSSAPI") - 1);
++ }
++
++ p2 = ngx_cpymem(p2," STARTTLS",sizeof(" STARTTLS")-1);
++ p3 = ngx_cpymem(p3," STARTTLS",sizeof(" STARTTLS")-1);
++ p3 = ngx_cpymem(p3," LOGINDISABLED",sizeof(" LOGINDISABLED")-1);
++
++ *p1++ = CR; *p1++ = LF;
++ *p2++ = CR; *p2++ = LF;
++ *p3++ = CR; *p3++ = LF;
++
++ ngx_conf_merge_str_value(conf->greeting, prev->greeting, "");
++ if (conf->greeting.len == 0) {
++ conf->greeting = default_imap_greeting;
++ }
++
++ p = ngx_pnalloc(cf->pool, conf->greeting.len + 2);
++ if (p == NULL) {
++ return NGX_CONF_ERROR;
+ }
+
+- *p++ = CR; *p = LF;
++ ngx_memcpy(p, conf->greeting.data, conf->greeting.len);
++ ngx_memcpy(p + conf->greeting.len, CRLF, sizeof(CRLF)-1);
++ conf->greeting.data = p;
++ conf->greeting.len += 2;
++
++ size = sizeof ("* ID ()" CRLF) - 1;
++
++ c = conf->id_params.elts;
++ for (i = 0; i < conf->id_params.nelts; ++i) {
++ if (!((c[i].len == 3) &&
++ (c[i].data[0] == 'n' || c[i].data[0] == 'N') &&
++ (c[i].data[1] == 'i' || c[i].data[1] == 'I') &&
++ (c[i].data[2] == 'l' || c[i].data[2] == 'L'))
++ )
++ {
++ size += 2; // for enclosing quotes
++ }
+
++ size += c[i].len;
++ size += 1; // for following SP
++ }
+
+- size += sizeof(" STARTTLS") - 1;
++ if (conf->id_params.nelts > 0) {
++ --size; // no SP follows the last parameter
++ } else {
++ size = size - 2 + 3; // take away the () and put nil
++ }
+
+ p = ngx_pnalloc(cf->pool, size);
+ if (p == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+- conf->starttls_capability.len = size;
+- conf->starttls_capability.data = p;
++ conf->id.len = size;
++ conf->id.data = p;
++
++ p = ngx_cpymem (p, "* ID ", sizeof ("* ID ") -1);
++
++ if (conf->id_params.nelts > 0)
++ {
++ *p++ = '(';
++
++ for (i = 0; i < conf->id_params.nelts; ++i)
++ {
++ if (!((c[i].len == 3) &&
++ (c[i].data[0] == 'n' || c[i].data[0] == 'N') &&
++ (c[i].data[1] == 'i' || c[i].data[1] == 'I') &&
++ (c[i].data[2] == 'l' || c[i].data[2] == 'L'))
++ )
++ {
++ *p++ = '"';
++ p = ngx_cpymem(p, c[i].data, c[i].len);
++ *p++ = '"';
++ }
++ else
++ {
++ p = ngx_cpymem(p, c[i].data, c[i].len);
++ }
++
++ if (i < conf->id_params.nelts - 1)
++ *p++ = ' ';
++ }
++
++ *p++ = ')';
++ }
++ else
++ {
++ p = ngx_cpymem (p, "nil", sizeof("nil") - 1);
++ }
+
+- p = ngx_cpymem(p, conf->capability.data,
+- conf->capability.len - (sizeof(CRLF) - 1));
+- p = ngx_cpymem(p, " STARTTLS", sizeof(" STARTTLS") - 1);
+ *p++ = CR; *p = LF;
++ ngx_conf_merge_value (conf->literalauth, prev->literalauth,1);
++ ngx_conf_merge_str_value (conf->ua_name, prev->ua_name, "ZCS");
++ ngx_conf_merge_str_value (conf->ua_version, prev->ua_version, "Unknown Version");
++
++ return NGX_CONF_OK;
++}
+
++static char *
++ngx_mail_imap_id (ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
++{
++ char *p = conf;
++ ngx_mail_imap_srv_conf_t *iscf;
++ ngx_str_t *c, *value, *elt;
++ ngx_uint_t i;
++ ngx_array_t *a;
+
+- size = (auth - conf->capability.data) + sizeof(CRLF) - 1
+- + sizeof(" STARTTLS LOGINDISABLED") - 1;
++ iscf = (ngx_mail_imap_srv_conf_t *)conf;
++
++ value = cf->args->elts;
++
++ if (cf->args->nelts % 2 == 0)
++ {
++ // ID response must contain id param field-value pairs
++ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
++ "unmatched pair in IMAP ID string: %V",
++ value + cf->args->nelts - 1);
+
+- p = ngx_pnalloc(cf->pool, size);
+- if (p == NULL) {
+ return NGX_CONF_ERROR;
+ }
++ else
++ {
++ a = (ngx_array_t *) (p + cmd->offset);
++ for (i = 1; i < cf->args->nelts; ++i)
++ {
++ c = ngx_array_push (a);
++ if (c == NULL) {
++ return NGX_CONF_ERROR;
++ }
+
+- conf->starttls_only_capability.len = size;
+- conf->starttls_only_capability.data = p;
++ *c = value[i];
++ }
+
+- p = ngx_cpymem(p, conf->capability.data,
+- auth - conf->capability.data);
+- p = ngx_cpymem(p, " STARTTLS LOGINDISABLED",
+- sizeof(" STARTTLS LOGINDISABLED") - 1);
+- *p++ = CR; *p = LF;
++ for (i = 0; i < a->nelts; i += 2 ) {
++ elt = ((ngx_str_t *) a->elts + i);
++ if (elt->len == sizeof ("NAME") - 1 &&
++ (elt->data[0] == 'N' || elt->data[0] == 'n') &&
++ (elt->data[1] == 'A' || elt->data[1] == 'a') &&
++ (elt->data[2] == 'M' || elt->data[2] == 'm') &&
++ (elt->data[3] == 'E' || elt->data[0] == 'e')) {
++ iscf->ua_name = *(elt + 1);
++ }else if (elt->len == sizeof ("VERSION") - 1 &&
++ (elt->data[0] == 'V' || elt->data[0] == 'v') &&
++ (elt->data[1] == 'E' || elt->data[1] == 'e') &&
++ (elt->data[2] == 'R' || elt->data[2] == 'r') &&
++ (elt->data[3] == 'S' || elt->data[3] == 's') &&
++ (elt->data[4] == 'I' || elt->data[4] == 'i') &&
++ (elt->data[5] == 'O' || elt->data[5] == 'o') &&
++ (elt->data[6] == 'N' || elt->data[6] == 'n')) {
++ iscf->ua_version = *(elt + 1);
++ }
++ }
+
+- return NGX_CONF_OK;
++ return NGX_CONF_OK;
++ }
+ }
++
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_h.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_h.patch
new file mode 100644
index 000000000..49e037c26
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_imap_module_h.patch
@@ -0,0 +1,18 @@
+--- nginx/src/mail/ngx_mail_imap_module.h 2023-03-07 16:26:44.722000700 +0530
++++ nginx/src/mail/ngx_mail_imap_module.h 2023-03-04 13:25:59.938112400 +0530
+@@ -24,6 +24,15 @@
+ ngx_uint_t auth_methods;
+
+ ngx_array_t capabilities;
++
++ ngx_array_t id_params;
++ ngx_str_t id;
++
++ ngx_str_t ua_name; /* user agent name coming from ID field "NAME" */
++ ngx_str_t ua_version; /* user agent version coming from ID field "VERSION" */
++
++ ngx_flag_t literalauth;
++ ngx_str_t greeting;
+ } ngx_mail_imap_srv_conf_t;
+
+
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
new file mode 100644
index 000000000..ee70dacb9
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
@@ -0,0 +1,1336 @@
+--- nginx/src/mail/ngx_mail_parse.c 2023-03-07 16:26:44.722976000 +0530
++++ nginx/src/mail/ngx_mail_parse.c 2023-09-18 19:18:53.672156800 +0530
+@@ -14,21 +14,104 @@
+ #include
+
+
++static ngx_int_t ngx_mail_imap_parse_id_params(ngx_mail_session_t *s, u_char *p);
++
++typedef enum {
++ swi_start = 0,
++ swi_tag,
++ swi_invalid,
++ swi_spaces_before_command,
++ swi_command,
++ swi_spaces_before_argument,
++ swi_argument,
++ swi_backslash,
++ swi_literal,
++ swi_no_sync_literal_argument,
++ swi_start_literal_argument,
++ swi_literal_argument,
++ swi_end_literal_argument,
++ swi_almost_done,
++ swi_begin_idparams = 15,
++ swi_end_idparams,
++ swi_done_idparams,
++ swi_almost_done_idparams,
++ swi_begin_idfield,
++ swi_id_n,
++ swi_id_ni,
++ swi_id_nil,
++ swi_idfield,
++ swi_idfield_len,
++ swi_idfield_len_plus,
++ swi_begin_idfield_l,
++ swi_idfield_l,
++ swi_SP_before_idvalue,
++ swi_X_before_idfield,
++ swi_begin_idvalue,
++ swi_idvalue,
++ swi_idvalue_n,
++ swi_idvalue_ni,
++ swi_idvalue_nil,
++ swi_idvalue_len,
++ swi_idvalue_len_plus,
++ swi_begin_idvalue_l,
++ swi_idvalue_l,
++} ngx_imap_parse_state_e;
++
++typedef enum {
++ swp_start = 0,
++ swp_command,
++ swp_invalid,
++ swp_spaces_before_argument,
++ swp_argument,
++ swp_almost_done
++} ngx_pop3_parse_state_e;
++
++typedef enum {
++ sws_start = 0,
++ sws_command,
++ sws_spaces_before_argument,
++ sws_argument,
++ sws_almost_done,
++ sws_invalid
++} ngx_smtp_parse_state_e;
++
++inline void ngx_mail_set_imap_parse_state_start(ngx_mail_session_t * s) {
++ s->state = swi_start;
++}
++
++inline void ngx_mail_set_pop3_parse_state_start(ngx_mail_session_t * s) {
++ s->state = swp_start;
++}
++
++inline void ngx_mail_set_smtp_parse_state_start(ngx_mail_session_t * s) {
++ s->state = sws_start;
++}
++
++inline void ngx_mail_set_imap_parse_state_argument(ngx_mail_session_t * s) {
++ s->state = swi_argument;
++}
++
++inline void ngx_mail_set_pop3_parse_state_argument(ngx_mail_session_t * s) {
++ s->state = swp_argument;
++}
++
++inline void ngx_mail_set_smtp_parse_state_argument(ngx_mail_session_t * s) {
++ s->state = sws_argument;
++}
++
++inline void ngx_mail_reset_parse_buffer(ngx_mail_session_t * s) {
++ s->buffer->pos = s->buffer->start;
++ s->buffer->last = s->buffer->start;
++}
++
++
+ ngx_int_t
+ ngx_mail_pop3_parse_command(ngx_mail_session_t *s)
+ {
+ u_char ch, *p, *c, c0, c1, c2, c3;
+ ngx_str_t *arg;
+- enum {
+- sw_start = 0,
+- sw_command,
+- sw_invalid,
+- sw_spaces_before_argument,
+- sw_argument,
+- sw_almost_done
+- } state;
+
+- state = s->state;
++ ngx_pop3_parse_state_e state = s->state;
+
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ ch = *p;
+@@ -36,13 +119,13 @@
+ switch (state) {
+
+ /* POP3 command */
+- case sw_start:
++ case swp_start:
+ s->cmd_start = p;
+- state = sw_command;
++ state = swp_command;
+
+ /* fall through */
+
+- case sw_command:
++ case swp_command:
+ if (ch == ' ' || ch == CR || ch == LF) {
+ c = s->cmd_start;
+
+@@ -98,10 +181,10 @@
+
+ switch (ch) {
+ case ' ':
+- state = sw_spaces_before_argument;
++ state = swp_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = swp_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -115,21 +198,21 @@
+
+ break;
+
+- case sw_invalid:
++ case swp_invalid:
+ goto invalid;
+
+- case sw_spaces_before_argument:
++ case swp_spaces_before_argument:
+ switch (ch) {
+ case ' ':
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = swp_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+ if (s->args.nelts <= 2) {
+- state = sw_argument;
++ state = swp_argument;
+ s->arg_start = p;
+ break;
+ }
+@@ -137,7 +220,7 @@
+ }
+ break;
+
+- case sw_argument:
++ case swp_argument:
+ switch (ch) {
+
+ case ' ':
+@@ -167,10 +250,10 @@
+
+ switch (ch) {
+ case ' ':
+- state = sw_spaces_before_argument;
++ state = swp_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = swp_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -182,7 +265,7 @@
+ }
+ break;
+
+- case sw_almost_done:
++ case swp_almost_done:
+ switch (ch) {
+ case LF:
+ goto done;
+@@ -200,22 +283,20 @@
+ done:
+
+ s->buffer->pos = p + 1;
+- s->state = (s->command != NGX_POP3_AUTH) ? sw_start : sw_argument;
+-
+ return NGX_OK;
+
+ invalid:
+
+- s->state = sw_invalid;
++ s->state = swp_invalid;
+
+ /* skip invalid command till LF */
+
+ for ( /* void */ ; p < s->buffer->last; p++) {
+ if (*p == LF) {
+- s->state = sw_start;
++ s->state = swp_start;
+ s->buffer->pos = p + 1;
+- return NGX_MAIL_PARSE_INVALID_COMMAND;
+- }
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++}
+ }
+
+ s->buffer->pos = p;
+@@ -228,25 +309,22 @@
+ ngx_mail_imap_parse_command(ngx_mail_session_t *s)
+ {
+ u_char ch, *p, *c, *dst, *src, *end;
++ ngx_int_t rc;
+ ngx_str_t *arg;
+- enum {
+- sw_start = 0,
+- sw_tag,
+- sw_invalid,
+- sw_spaces_before_command,
+- sw_command,
+- sw_spaces_before_argument,
+- sw_argument,
+- sw_backslash,
+- sw_literal,
+- sw_no_sync_literal_argument,
+- sw_start_literal_argument,
+- sw_literal_argument,
+- sw_end_literal_argument,
+- sw_almost_done
+- } state;
++ p = NULL; /* for avoid warning */
++ ngx_imap_parse_state_e state = s->state;
+
+- state = s->state;
++ if(state >= swi_begin_idparams) { /* beyond the states handled in ID parse function */
++ rc = ngx_mail_imap_parse_id_params(s, s->buffer->pos);
++ switch (rc) {
++ case NGX_OK:
++ goto done;
++ case NGX_MAIL_PARSE_INVALID_COMMAND:
++ goto invalid;
++ default: /* NGX_ERROR, NGX_AGAIN or NGX_IMAP_NEXT */
++ return rc;
++ }
++ }
+
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ ch = *p;
+@@ -254,18 +332,18 @@
+ switch (state) {
+
+ /* IMAP tag */
+- case sw_start:
++ case swi_start:
+ s->tag_start = p;
+- state = sw_tag;
++ state = swi_tag;
+
+ /* fall through */
+
+- case sw_tag:
++ case swi_tag:
+ switch (ch) {
+ case ' ':
+- s->tag.len = p - s->tag_start + 1;
++ s->tag.len = p - s->tag_start;
+ s->tag.data = s->tag_start;
+- state = sw_spaces_before_command;
++ state = swi_spaces_before_command;
+ break;
+ case CR:
+ case LF:
+@@ -279,15 +357,15 @@
+ }
+ if (p - s->tag_start > 31) {
+ goto invalid;
+- }
+- break;
++ }
++ break;
+ }
+ break;
+
+- case sw_invalid:
++ case swi_invalid:
+ goto invalid;
+
+- case sw_spaces_before_command:
++ case swi_spaces_before_command:
+ switch (ch) {
+ case ' ':
+ break;
+@@ -296,18 +374,41 @@
+ goto invalid;
+ default:
+ s->cmd_start = p;
+- state = sw_command;
++ state = swi_command;
+ break;
+ }
+ break;
+
+- case sw_command:
++ case swi_command:
+ if (ch == ' ' || ch == CR || ch == LF) {
+
+ c = s->cmd_start;
+
+ switch (p - c) {
+
++ case 2:
++ if ((c[0] == 'I' || c[0] == 'i')
++ && (c[1] == 'D' || c[1] == 'd'))
++ {
++ s->command = NGX_IMAP_ID;
++ /* RFC 2971 */
++ ngx_int_t rc;
++ s->state = swi_begin_idparams;
++ p++; //move to the next character
++ rc = ngx_mail_imap_parse_id_params(s, p);
++ switch (rc) {
++ case NGX_OK:
++ goto done;
++ case NGX_MAIL_PARSE_INVALID_COMMAND:
++ goto invalid;
++ default: /* NGX_ERROR or NGX_IMAP_NEXT */
++ return rc;
++ }
++ } else {
++ goto invalid;
++ }
++ break;
++
+ case 4:
+ if ((c[0] == 'N' || c[0] == 'n')
+ && (c[1] == 'O'|| c[1] == 'o')
+@@ -315,7 +416,7 @@
+ && (c[3] == 'P'|| c[3] == 'p'))
+ {
+ s->command = NGX_IMAP_NOOP;
+-
++ s->eargs = 0;
+ } else {
+ goto invalid;
+ }
+@@ -329,7 +430,7 @@
+ && (c[4] == 'N'|| c[4] == 'n'))
+ {
+ s->command = NGX_IMAP_LOGIN;
+-
++ s->eargs = 2;
+ } else {
+ goto invalid;
+ }
+@@ -344,7 +445,7 @@
+ && (c[5] == 'T'|| c[5] == 't'))
+ {
+ s->command = NGX_IMAP_LOGOUT;
+-
++ s->eargs = 0;
+ } else {
+ goto invalid;
+ }
+@@ -362,7 +463,7 @@
+ && (c[7] == 'S'|| c[7] == 's'))
+ {
+ s->command = NGX_IMAP_STARTTLS;
+-
++ s->eargs = 0;
+ } else {
+ goto invalid;
+ }
+@@ -382,7 +483,7 @@
+ && (c[9] == 'Y'|| c[9] == 'y'))
+ {
+ s->command = NGX_IMAP_CAPABILITY;
+-
++ s->eargs = 0;
+ } else {
+ goto invalid;
+ }
+@@ -402,7 +503,12 @@
+ && (c[10] == 'T'|| c[10] == 't')
+ && (c[11] == 'E'|| c[11] == 'e'))
+ {
+- s->command = NGX_IMAP_AUTHENTICATE;
++ if (ch != ' ') {
++ goto invalid;
++ } else {
++ s->command = NGX_IMAP_AUTHENTICATE;
++ s->eargs = 1;
++ }
+
+ } else {
+ goto invalid;
+@@ -418,10 +524,13 @@
+
+ switch (ch) {
+ case ' ':
+- state = sw_spaces_before_argument;
++ if (s->command == NGX_IMAP_CAPABILITY) {
++ goto invalid;
++ }
++ state = swi_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = swi_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -435,40 +544,46 @@
+
+ break;
+
+- case sw_spaces_before_argument:
++ case swi_spaces_before_argument:
+ switch (ch) {
+ case ' ':
+ break;
+ case CR:
+- state = sw_almost_done;
++ if (s->args.nelts == 0) {
++ goto invalid; //no argument
++ }
++ state = swi_almost_done;
+ break;
+ case LF:
++ if ( s->args.nelts == 0) {
++ goto invalid; // no argument
++ }
+ goto done;
+ case '"':
+- if (s->args.nelts <= 2) {
++ if (s->args.nelts <= s->eargs) {
+ s->quoted = 1;
+ s->arg_start = p + 1;
+- state = sw_argument;
++ state = swi_argument;
+ break;
+ }
+ goto invalid;
+ case '{':
+- if (s->args.nelts <= 2) {
+- state = sw_literal;
++ if (s->args.nelts <= s->eargs) {
++ state = swi_literal;
+ break;
+ }
+ goto invalid;
+ default:
+- if (s->args.nelts <= 2) {
++ if (s->args.nelts <= s->eargs) {
+ s->arg_start = p;
+- state = sw_argument;
++ state = swi_argument;
+ break;
+ }
+ goto invalid;
+ }
+ break;
+
+- case sw_argument:
++ case swi_argument:
+ if (ch == ' ' && s->quoted) {
+ break;
+ }
+@@ -510,10 +625,10 @@
+ switch (ch) {
+ case '"':
+ case ' ':
+- state = sw_spaces_before_argument;
++ state = swi_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = swi_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -522,46 +637,52 @@
+ case '\\':
+ if (s->quoted) {
+ s->backslash = 1;
+- state = sw_backslash;
++ state = swi_backslash;
+ }
+ break;
+ }
+ break;
+
+- case sw_backslash:
++ case swi_backslash:
+ switch (ch) {
+ case CR:
+ case LF:
+ goto invalid;
++ // (RFC3501)
++ // a backslash may only escape another backslash, or a double quote
++ case '\\':
++ case '"':
++ state = swi_argument;
++ break;
+ default:
+- state = sw_argument;
++ goto invalid;
+ }
+ break;
+
+- case sw_literal:
++ case swi_literal:
+ if (ch >= '0' && ch <= '9') {
+ s->literal_len = s->literal_len * 10 + (ch - '0');
+ break;
+ }
+ if (ch == '}') {
+- state = sw_start_literal_argument;
++ state = swi_start_literal_argument;
+ break;
+ }
+ if (ch == '+') {
+- state = sw_no_sync_literal_argument;
++ state = swi_no_sync_literal_argument;
+ break;
+ }
+ goto invalid;
+
+- case sw_no_sync_literal_argument:
++ case swi_no_sync_literal_argument:
+ if (ch == '}') {
+ s->no_sync_literal = 1;
+- state = sw_start_literal_argument;
++ state = swi_start_literal_argument;
+ break;
+ }
+ goto invalid;
+
+- case sw_start_literal_argument:
++ case swi_start_literal_argument:
+ switch (ch) {
+ case CR:
+ break;
+@@ -569,10 +690,10 @@
+ s->buffer->pos = p + 1;
+ s->arg_start = p + 1;
+ if (s->no_sync_literal == 0) {
+- s->state = sw_literal_argument;
++ s->state = swi_literal_argument;
+ return NGX_IMAP_NEXT;
+ }
+- state = sw_literal_argument;
++ state = swi_literal_argument;
+ s->no_sync_literal = 0;
+ break;
+ default:
+@@ -580,7 +701,7 @@
+ }
+ break;
+
+- case sw_literal_argument:
++ case swi_literal_argument:
+ if (s->literal_len && --s->literal_len) {
+ break;
+ }
+@@ -592,36 +713,38 @@
+ arg->len = p + 1 - s->arg_start;
+ arg->data = s->arg_start;
+ s->arg_start = NULL;
+- state = sw_end_literal_argument;
++ state = swi_end_literal_argument;
+
+ break;
+
+- case sw_end_literal_argument:
++ case swi_end_literal_argument:
+ switch (ch) {
+ case '{':
+- if (s->args.nelts <= 2) {
+- state = sw_literal;
++ if (s->args.nelts <= s->eargs) {
++ state = swi_literal;
+ break;
+ }
+ goto invalid;
+ case CR:
+- state = sw_almost_done;
++ state = swi_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+- state = sw_spaces_before_argument;
++ state = swi_spaces_before_argument;
+ break;
+ }
+ break;
+
+- case sw_almost_done:
++ case swi_almost_done:
+ switch (ch) {
+ case LF:
+ goto done;
+ default:
+ goto invalid;
+ }
++ default:
++ break; /* for avoid warning only */
+ }
+ }
+
+@@ -633,13 +756,11 @@
+ done:
+
+ s->buffer->pos = p + 1;
+- s->state = (s->command != NGX_IMAP_AUTHENTICATE) ? sw_start : sw_argument;
+-
+ return NGX_OK;
+
+ invalid:
+
+- s->state = sw_invalid;
++ s->state = swi_invalid;
+ s->quoted = 0;
+ s->backslash = 0;
+ s->no_sync_literal = 0;
+@@ -649,7 +770,7 @@
+
+ for ( /* void */ ; p < s->buffer->last; p++) {
+ if (*p == LF) {
+- s->state = sw_start;
++ s->state = swi_start;
+ s->buffer->pos = p + 1;
+
+ /* detect non-synchronizing literals */
+@@ -676,21 +797,500 @@
+ }
+
+
++static ngx_int_t
++ngx_mail_imap_parse_id_params(ngx_mail_session_t *s, u_char *p)
++{
++ u_char ch;
++ ngx_imap_parse_state_e state;
++ ngx_str_t *arg;
++ state = s->state;
++
++ for (; p < s->buffer->last; p++) {
++ ch = *p;
++ switch(state) {
++ case swi_begin_idparams:
++ switch (ch) {
++ case '(':
++ state = swi_begin_idfield;
++ break;
++ case 'n':
++ case 'N':
++ state = swi_id_n;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_begin_idparams: expected (/n/N, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_end_idparams:
++ switch (ch)
++ {
++ case ')':
++ state = swi_done_idparams;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_end_idparams: expected ), got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++
++ break;
++
++ case swi_done_idparams:
++ switch (ch)
++ {
++ case CR:
++ state = swi_almost_done;
++ break;
++ case LF:
++ return NGX_OK;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_done_idparams: expected CR/LF, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_id_n:
++ switch (ch) {
++ case 'i':
++ case 'I':
++ state = swi_id_ni;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_id_n: expected i/I, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_id_ni:
++ switch (ch) {
++ case 'l':
++ case 'L':
++ state = swi_id_nil;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_id_ni: expected l/L, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_id_nil:
++ switch (ch) {
++ case CR:
++ state = swi_almost_done;
++ break;
++ case LF:
++ return NGX_OK;
++ default:
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_begin_idfield:
++ switch (ch) {
++ case '{':
++ s->literal_len = 0;
++ state = swi_idfield_len;
++ break;
++ case '"':
++ s->quoted = 1;
++ s->backslash = 0;
++ s->arg_start = p+1;
++ state = swi_idfield;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_begin_idfield: expected \"/{, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idfield_len:
++ if (ch >= '0' && ch <= '9') {
++ s->literal_len = s->literal_len * 10 + (ch - '0');
++ break;
++ }
++ if (ch == '+') {
++ state = swi_idfield_len_plus; /* literalplus stuff */
++ break;
++ }
++ if (ch == '}') {
++ s->no_sync_literal = 0;
++ state = swi_begin_idfield_l;
++ break;
++ }
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idfield_len: expected 0-9/+/}, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++
++ case swi_idfield_len_plus:
++ if (ch == '}') {
++ s->no_sync_literal = 1;
++ state = swi_begin_idfield_l;
++ break;
++ }
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idfield_len_plus: expected }, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++
++ case swi_begin_idfield_l:
++ switch (ch)
++ {
++ case CR:
++ break;
++ case LF:
++ if (s->literal_len) {
++ s->buffer->pos = p + 1;
++ s->arg_start = p + 1;
++ state = swi_idfield_l;
++ } else {
++ s->buffer->pos = p + 1;
++ s->arg_start = NULL;
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) { return NGX_ERROR; }
++ arg->data = (u_char *)"";
++ arg->len = 0;
++ state = swi_SP_before_idvalue;
++ }
++ if (s->no_sync_literal == 1) {
++ s->no_sync_literal = 0;
++ break;
++ } else {
++ s->state = state;
++ return NGX_IMAP_NEXT;
++ }
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_begin_idfield_l: expected CR/LF, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idfield_l:
++ if (s->literal_len && --s->literal_len) {
++ break;
++ }
++
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++
++ arg->len = p + 1 - s->arg_start;
++ arg->data = s->arg_start;
++ s->arg_start = NULL;
++ state = swi_SP_before_idvalue;
++ break;
++
++ case swi_idfield:
++ switch (ch) {
++ case '\\':
++ if (!s->backslash) {
++ s->backslash = 1;
++ } else {
++ if (ch == '\\' && ch == '"')
++ s->backslash = 0;
++ else {
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL,
++ s->connection->log, 0,
++ "swi_idfield: \\ escapes non-quoted special '%c'",
++ ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ }
++ break;
++
++ case '"':
++ if (s->backslash) {
++ s->backslash = 0;
++ break;
++ }
++ s->quoted = 0;
++ arg = ngx_array_push(&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++
++ arg->len = p - s->arg_start;
++ arg->data = s->arg_start;
++ s->arg_start = NULL;
++ state = swi_SP_before_idvalue;
++ break;
++
++ case CR:
++ case LF:
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idfield: CR/LF breaks id field");
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ default:
++ break;
++ }
++ break;
++
++ case swi_begin_idvalue:
++ switch (ch)
++ {
++ case '"':
++ s->quoted = 1;
++ s->backslash = 0;
++ s->arg_start = p+1;
++ state = swi_idvalue;
++ break;
++ case 'n':
++ case 'N':
++ state = swi_idvalue_n;
++ break;
++ case '{':
++ s->literal_len = 0;
++ state = swi_idvalue_len;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_begin_idvalue: expected \"/n/N/{, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idvalue_len:
++ if (ch >= '0' && ch <= '9') {
++ s->literal_len = s->literal_len + (ch - '0');
++ break;
++ }
++ if (ch == '+') {
++ state = swi_idvalue_len_plus;
++ break;
++ }
++ if (ch == '}') {
++ s->no_sync_literal = 0;
++ state = swi_begin_idvalue_l;
++ break;
++ }
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue_len: expected 0-9/}, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++
++ case swi_idvalue_len_plus:
++ if (ch == '}') {
++ s->no_sync_literal = 1;
++ state = swi_begin_idvalue_l;
++ break;
++ }
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue_len_plus: expected }, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++
++ case swi_begin_idvalue_l:
++ switch (ch)
++ {
++ case CR:
++ break;
++ case LF:
++ if (s->literal_len) {
++ s->buffer->pos = p + 1;
++ s->arg_start = p + 1;
++ state = swi_idvalue_l;
++ } else {
++ s->buffer->pos = p + 1;
++ s->arg_start = NULL;
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) { return NGX_ERROR; }
++ arg->data = (u_char *)"";
++ arg->len = 0;
++ state = swi_X_before_idfield;
++ }
++ if (s->no_sync_literal == 1) {
++ s->no_sync_literal = 0;
++ break;
++ } else {
++ s->state = state;
++ return NGX_IMAP_NEXT;
++ }
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_begin_idvalue_l: expected CR/LF, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idvalue_l:
++ if (s->literal_len && --s->literal_len) {
++ break;
++ }
++
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++
++ arg->len = p + 1 - s->arg_start;
++ arg->data = s->arg_start;
++ s->arg_start = NULL;
++ state = swi_X_before_idfield;
++ break;
++
++ case swi_idvalue_n:
++ switch (ch)
++ {
++ case 'i':
++ case 'I':
++ state = swi_idvalue_ni;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue_n: expected i/I, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idvalue_ni:
++ switch (ch)
++ {
++ case 'l':
++ case 'L':
++ state = swi_idvalue_nil;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue_ni: expected l/L, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idvalue_nil:
++ switch (ch)
++ {
++ case ' ':
++ state = swi_begin_idfield;
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++ arg->data = (u_char *)"";
++ arg->len = 0;
++ break;
++ case ')':
++ state = swi_done_idparams;
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++ arg->data = (u_char *)"";
++ arg->len = 0;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue_nil: expected SP/), got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_SP_before_idvalue:
++ switch (ch)
++ {
++ case ' ':
++ state = swi_begin_idvalue;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_SP_before_idvalue: expected SP, got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_X_before_idfield:
++ switch (ch)
++ {
++ case ' ':
++ state = swi_begin_idfield;
++ break;
++ case ')':
++ state = swi_done_idparams;
++ break;
++ default:
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_X_before_idfield: expected SP/), got '%c'", ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ break;
++
++ case swi_idvalue:
++ switch (ch)
++ {
++ case '\\':
++ if (!s->backslash) {
++ s->backslash = 1;
++ } else {
++ if (ch == '\\' || ch == '"')
++ s->backslash = 0;
++ else {
++ ngx_log_debug1 (NGX_LOG_DEBUG_MAIL,
++ s->connection->log, 0,
++ "swi_idvalue: \\ escapes non-quoted special '%c'",
++ ch);
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++ }
++ break;
++
++ case '"':
++ if (s->backslash)
++ {
++ s->backslash = 0;
++ break;
++ }
++ s->quoted = 0;
++ arg = ngx_array_push (&s->args);
++ if (arg == NULL) {
++ return NGX_ERROR;
++ }
++
++ arg->len = p - s->arg_start;
++ arg->data = s->arg_start;
++ s->arg_start = NULL;
++ state = swi_X_before_idfield;
++ break;
++
++ case CR:
++ case LF:
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "swi_idvalue: CR/LF breaks id value");
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ default:
++ break;
++ }
++ break;
++ case swi_almost_done:
++ switch (ch) {
++ case LF:
++ return NGX_OK;
++ default:
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++
++ default:
++ break; /* for avoid warning only */
++ } /* switch (state) */
++ } /* for */
++
++ s->buffer->pos = p;
++ s->state = state;
++
++ return NGX_AGAIN;
++}
++
++
+ ngx_int_t
+ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
+ {
+ u_char ch, *p, *c, c0, c1, c2, c3;
+ ngx_str_t *arg;
+- enum {
+- sw_start = 0,
+- sw_command,
+- sw_invalid,
+- sw_spaces_before_argument,
+- sw_argument,
+- sw_almost_done
+- } state;
+
+- state = s->state;
++ ngx_smtp_parse_state_e state = s->state;
+
+ for (p = s->buffer->pos; p < s->buffer->last; p++) {
+ ch = *p;
+@@ -698,13 +1298,13 @@
+ switch (state) {
+
+ /* SMTP command */
+- case sw_start:
++ case sws_start:
+ s->cmd_start = p;
+- state = sw_command;
++ state = sws_command;
+
+ /* fall through */
+
+- case sw_command:
++ case sws_command:
+ if (ch == ' ' || ch == CR || ch == LF) {
+ c = s->cmd_start;
+
+@@ -789,10 +1389,10 @@
+
+ switch (ch) {
+ case ' ':
+- state = sw_spaces_before_argument;
++ state = sws_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = sws_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -806,21 +1406,21 @@
+
+ break;
+
+- case sw_invalid:
++ case sws_invalid:
+ goto invalid;
+
+- case sw_spaces_before_argument:
++ case sws_spaces_before_argument:
+ switch (ch) {
+ case ' ':
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = sws_almost_done;
+ break;
+ case LF:
+ goto done;
+ default:
+ if (s->args.nelts <= 10) {
+- state = sw_argument;
++ state = sws_argument;
+ s->arg_start = p;
+ break;
+ }
+@@ -828,7 +1428,7 @@
+ }
+ break;
+
+- case sw_argument:
++ case sws_argument:
+ switch (ch) {
+ case ' ':
+ case CR:
+@@ -843,10 +1443,10 @@
+
+ switch (ch) {
+ case ' ':
+- state = sw_spaces_before_argument;
++ state = sws_spaces_before_argument;
+ break;
+ case CR:
+- state = sw_almost_done;
++ state = sws_almost_done;
+ break;
+ case LF:
+ goto done;
+@@ -858,7 +1458,7 @@
+ }
+ break;
+
+- case sw_almost_done:
++ case sws_almost_done:
+ switch (ch) {
+ case LF:
+ goto done;
+@@ -876,19 +1476,19 @@
+ done:
+
+ s->buffer->pos = p + 1;
+- s->state = (s->command != NGX_SMTP_AUTH) ? sw_start : sw_argument;
++
+
+ return NGX_OK;
+
+ invalid:
+
+- s->state = sw_invalid;
++ s->state = sws_invalid;
+
+ /* skip invalid command till LF */
+
+ for ( /* void */ ; p < s->buffer->last; p++) {
+ if (*p == LF) {
+- s->state = sw_start;
++ s->state = sws_start;
+ s->buffer->pos = p + 1;
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+@@ -905,12 +1505,6 @@
+ {
+ ngx_str_t *arg;
+
+-#if (NGX_MAIL_SSL)
+- if (ngx_mail_starttls_only(s, c)) {
+- return NGX_MAIL_PARSE_INVALID_COMMAND;
+- }
+-#endif
+-
+ if (s->args.nelts == 0) {
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+@@ -925,7 +1519,7 @@
+ return NGX_MAIL_AUTH_LOGIN;
+ }
+
+- if (s->args.nelts == 2) {
++ if (s->args.nelts == 2) { //initial response
+ return NGX_MAIL_AUTH_LOGIN_USERNAME;
+ }
+
+@@ -938,14 +1532,28 @@
+ return NGX_MAIL_AUTH_PLAIN;
+ }
+
+- if (s->args.nelts == 2) {
+- return ngx_mail_auth_plain(s, c, 1);
++ if (s->args.nelts == 2) { //initial response
++ return NGX_MAIL_AUTH_PLAIN_IR;
+ }
+ }
+
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
++ if (arg[0].len == 6) {
++ if (ngx_strncasecmp(arg[0].data, (u_char *) "GSSAPI", 6) == 0 ) {
++ if (s->args.nelts == 1) {
++ return NGX_MAIL_AUTH_GSSAPI;
++ }
++
++ if (s->args.nelts == 2) { //initial response
++ return NGX_MAIL_AUTH_GSSAPI_IR;
++ }
++ }
++
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
++ }
++
+ if (arg[0].len == 8) {
+
+ if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
+@@ -971,5 +1579,5 @@
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+- return NGX_MAIL_PARSE_INVALID_COMMAND;
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+ }
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_handler.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_handler.patch
new file mode 100644
index 000000000..e703a4ed3
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_handler.patch
@@ -0,0 +1,386 @@
+--- nginx/src/mail/ngx_mail_pop3_handler.c 2023-03-07 16:26:44.725901500 +0530
++++ nginx/src/mail/ngx_mail_pop3_handler.c 2023-09-14 18:47:12.646461800 +0530
+@@ -21,12 +21,18 @@
+ static ngx_int_t ngx_mail_pop3_auth(ngx_mail_session_t *s, ngx_connection_t *c);
+
+
+-static u_char pop3_greeting[] = "+OK POP3 ready" CRLF;
++/*static u_char pop3_greeting[] = "+OK POP3 ready" CRLF; zimbra uses the greeting specified by the directive */
+ static u_char pop3_ok[] = "+OK" CRLF;
+ static u_char pop3_next[] = "+ " CRLF;
++static u_char pop3_gssapi_next[] = "+ " CRLF;
+ static u_char pop3_username[] = "+ VXNlcm5hbWU6" CRLF;
+ static u_char pop3_password[] = "+ UGFzc3dvcmQ6" CRLF;
+ static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF;
++static u_char pop3_unsupported_mech[] = "-ERR mechanism not supported" CRLF;
++static u_char pop3_nocleartext[] = "-ERR cleartext logins disabled" CRLF;
++static u_char pop3_authaborted[] = "-ERR authentication aborted" CRLF;
++static u_char pop3_login_failed[] = "-ERR invalid username/password" CRLF;
++static u_char pop3_auth_failed[] = "-ERR line is too long" CRLF;
+
+
+ void
+@@ -47,20 +53,20 @@
+ return;
+ }
+
+- s->out.data = ngx_pnalloc(c->pool, sizeof(pop3_greeting) + s->salt.len);
++ s->out.data = ngx_pnalloc(c->pool, pscf->greeting.len + s->salt.len - 1);
+ if (s->out.data == NULL) {
+ ngx_mail_session_internal_server_error(s);
+ return;
+ }
+
+- p = ngx_cpymem(s->out.data, pop3_greeting, sizeof(pop3_greeting) - 3);
++ p = ngx_cpymem(s->out.data, pscf->greeting.data, pscf->greeting.len - 2);
+ *p++ = ' ';
+ p = ngx_cpymem(p, s->salt.data, s->salt.len);
+
+ s->out.len = p - s->out.data;
+
+ } else {
+- ngx_str_set(&s->out, pop3_greeting);
++ s->out = pscf->greeting;
+ }
+
+ c->read->handler = ngx_mail_pop3_init_protocol;
+@@ -80,6 +86,7 @@
+ {
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
++ ngx_mail_pop3_srv_conf_t *pscf;
+
+ c = rev->data;
+
+@@ -102,13 +109,16 @@
+ return;
+ }
+
+- s->buffer = ngx_create_temp_buf(c->pool, 128);
++ pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
++
++ s->buffer = ngx_create_temp_buf(c->pool, pscf->client_buffer_size);
+ if (s->buffer == NULL) {
+ ngx_mail_session_internal_server_error(s);
+ return;
+ }
+ }
+
++ ngx_mail_set_pop3_parse_state_start(s);
+ s->mail_state = ngx_pop3_start;
+ c->read->handler = ngx_mail_pop3_auth_state;
+
+@@ -143,7 +153,7 @@
+ ngx_mail_close_connection(c);
+ return;
+ }
+-
++
+ return;
+ }
+
+@@ -175,6 +185,7 @@
+
+ case NGX_POP3_USER:
+ rc = ngx_mail_pop3_user(s, c);
++ s->mail_state = ngx_pop3_user;
+ break;
+
+ case NGX_POP3_CAPA:
+@@ -213,6 +224,7 @@
+
+ case NGX_POP3_PASS:
+ rc = ngx_mail_pop3_pass(s, c);
++ s->mail_state = ngx_pop3_user;
+ break;
+
+ case NGX_POP3_CAPA:
+@@ -240,8 +252,10 @@
+ case ngx_pop3_auth_login_username:
+ rc = ngx_mail_auth_login_username(s, c, 0);
+
+- ngx_str_set(&s->out, pop3_password);
+- s->mail_state = ngx_pop3_auth_login_password;
++ if(rc == NGX_MAIL_AUTH_ARGUMENT) {
++ ngx_str_set(&s->out, pop3_password);
++ s->mail_state = ngx_pop3_auth_login_password;
++ }
+ break;
+
+ case ngx_pop3_auth_login_password:
+@@ -256,6 +270,18 @@
+ rc = ngx_mail_auth_cram_md5(s, c);
+ break;
+
++ case ngx_pop3_auth_gssapi:
++ {
++ ngx_str_t output;
++ ngx_str_set(&output, "");
++ rc = ngx_mail_auth_gssapi(s, c, &output);
++ if (rc == NGX_MAIL_AUTH_ARGUMENT) {
++ s->mail_state = ngx_pop3_auth_gssapi;
++ s->out = output;
++ }
++ break;
++ }
++
+ case ngx_pop3_auth_external:
+ rc = ngx_mail_auth_external(s, c, 0);
+ break;
+@@ -269,43 +295,73 @@
+ switch (rc) {
+
+ case NGX_DONE:
+- ngx_mail_auth(s, c);
++ ngx_mail_do_auth(s, c);
+ return;
+
++ case NGX_OK:
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
++
++ case NGX_MAIL_AUTH_ABORT:
++ ngx_str_set(&s->out, pop3_authaborted);
++ s->mail_state = ngx_pop3_start;
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
++
+ case NGX_ERROR:
+ ngx_mail_session_internal_server_error(s);
+ return;
+
+- case NGX_MAIL_PARSE_INVALID_COMMAND:
++ case NGX_MAIL_LOGIN_FAILED:
++ ngx_str_set(&s->out, pop3_login_failed);
+ s->mail_state = ngx_pop3_start;
+- s->state = 0;
+-
+- ngx_str_set(&s->out, pop3_invalid_command);
+-
+- /* fall through */
+-
+- case NGX_OK:
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
+
+- s->args.nelts = 0;
+-
+- if (s->buffer->pos == s->buffer->last) {
+- s->buffer->pos = s->buffer->start;
+- s->buffer->last = s->buffer->start;
+- }
++ case NGX_MAIL_AUTH_FAILED:
++ ngx_str_set(&s->out, pop3_auth_failed);
++ s->mail_state = ngx_pop3_start;
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
++
++ case NGX_MAIL_PARSE_INVALID_AUTH_MECH:
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, c->log, 0,
++ "unsupported POP auth mechanism");
++ ngx_str_set(&s->out, pop3_unsupported_mech);
++ s->mail_state = ngx_pop3_start;
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
+
+- if (s->state) {
+- s->arg_start = s->buffer->pos;
+- }
++ case NGX_MAIL_PARSE_INVALID_COMMAND:
++ ngx_str_set(&s->out, pop3_invalid_command);
++ s->mail_state = ngx_pop3_start;
++ s->arg_start = NULL;
++ ngx_mail_set_pop3_parse_state_start(s);
++ break;
++
++ case NGX_MAIL_AUTH_ARGUMENT:
++ s->arg_start = s->buffer->start;
++ ngx_mail_set_pop3_parse_state_argument(s);
++ break;
++ }
+
+- if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+- ngx_mail_session_internal_server_error(s);
+- return;
+- }
++ s->args.nelts = 0;
++ ngx_mail_reset_parse_buffer(s);
+
+- ngx_mail_send(c->write);
++ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
++ ngx_mail_session_internal_server_error(s);
++ return;
+ }
++
++ ngx_mail_send(c->write);
+ }
+
++
+ static ngx_int_t
+ ngx_mail_pop3_user(ngx_mail_session_t *s, ngx_connection_t *c)
+ {
+@@ -313,6 +369,7 @@
+
+ #if (NGX_MAIL_SSL)
+ if (ngx_mail_starttls_only(s, c)) {
++ ngx_str_set(&s->out, pop3_nocleartext);
+ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+ #endif
+@@ -322,6 +379,10 @@
+ }
+
+ arg = s->args.elts;
++ if(arg[0].len > NGX_MAIL_MAX_LOGIN_LEN) {
++ ngx_str_null(&s->login);
++ return NGX_OK;
++ }
+ s->login.len = arg[0].len;
+ s->login.data = ngx_pnalloc(c->pool, s->login.len);
+ if (s->login.data == NULL) {
+@@ -333,8 +394,6 @@
+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+ "pop3 login: \"%V\"", &s->login);
+
+- s->mail_state = ngx_pop3_user;
+-
+ return NGX_OK;
+ }
+
+@@ -349,6 +408,11 @@
+ }
+
+ arg = s->args.elts;
++
++ if (s->login.len == 0 || arg[0].len > NGX_MAIL_MAX_PASSWORD_LEN) {
++ return NGX_MAIL_LOGIN_FAILED;
++ }
++
+ s->passwd.len = arg[0].len;
+ s->passwd.data = ngx_pnalloc(c->pool, s->passwd.len);
+ if (s->passwd.data == NULL) {
+@@ -362,6 +426,9 @@
+ "pop3 passwd: \"%V\"", &s->passwd);
+ #endif
+
++ s->auth_method = NGX_MAIL_AUTH_PASSWD;
++ s->usedauth = 0;
++
+ return NGX_DONE;
+ }
+
+@@ -464,6 +531,7 @@
+ "pop3 apop: \"%V\" \"%V\"", &s->login, &s->passwd);
+
+ s->auth_method = NGX_MAIL_AUTH_APOP;
++ s->usedauth = 0;
+
+ return NGX_DONE;
+ }
+@@ -484,10 +552,7 @@
+ pscf = ngx_mail_get_module_srv_conf(s, ngx_mail_pop3_module);
+
+ if (s->args.nelts == 0) {
+- s->out = pscf->auth_capability;
+- s->state = 0;
+-
+- return NGX_OK;
++ return NGX_MAIL_PARSE_INVALID_COMMAND;
+ }
+
+ rc = ngx_mail_auth_parse(s, c);
+@@ -496,34 +561,74 @@
+
+ case NGX_MAIL_AUTH_LOGIN:
+
++ if (!(pscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
+ ngx_str_set(&s->out, pop3_username);
+ s->mail_state = ngx_pop3_auth_login_username;
+
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
+
+ case NGX_MAIL_AUTH_LOGIN_USERNAME:
+
++ if (!(pscf->auth_methods & NGX_MAIL_AUTH_LOGIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
+ ngx_str_set(&s->out, pop3_password);
+ s->mail_state = ngx_pop3_auth_login_password;
+
+- return ngx_mail_auth_login_username(s, c, 1);
++ return ngx_mail_auth_login_username(s, c, 0);
+
+ case NGX_MAIL_AUTH_PLAIN:
+
++ if (!(pscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
+ ngx_str_set(&s->out, pop3_next);
+ s->mail_state = ngx_pop3_auth_plain;
+
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
++
++ case NGX_MAIL_AUTH_PLAIN_IR:
++
++ if (!(pscf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ return ngx_mail_auth_plain(s, c, 1);
++
++ case NGX_MAIL_AUTH_GSSAPI:
++ if( !(pscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ ngx_str_set(&s->out, pop3_gssapi_next);
++ s->mail_state = ngx_pop3_auth_gssapi;
++ return NGX_MAIL_AUTH_ARGUMENT;
++
++ case NGX_MAIL_AUTH_GSSAPI_IR:
++
++ if (!(pscf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
++ }
++ s->mail_state = ngx_pop3_auth_gssapi;
++ ngx_str_t output;
++ ngx_str_set(&output, "");
++ int res = ngx_mail_auth_gssapi(s, c, &output);
++ if(res == NGX_MAIL_AUTH_ARGUMENT) {
++ s->out = output;
++ return NGX_MAIL_AUTH_ARGUMENT;
++ } else {
++ return res;
++ }
+
+ case NGX_MAIL_AUTH_CRAM_MD5:
+
+ if (!(pscf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)) {
+- return NGX_MAIL_PARSE_INVALID_COMMAND;
++ return NGX_MAIL_PARSE_INVALID_AUTH_MECH;
+ }
+
+ if (ngx_mail_auth_cram_md5_salt(s, c, "+ ", 2) == NGX_OK) {
+ s->mail_state = ngx_pop3_auth_cram_md5;
+- return NGX_OK;
++ return NGX_MAIL_AUTH_ARGUMENT;
+ }
+
+ return NGX_ERROR;
+@@ -538,6 +643,9 @@
+ s->mail_state = ngx_pop3_auth_external;
+
+ return NGX_OK;
++
++ default:
++ break;
+ }
+
+ return rc;
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_c.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_c.patch
new file mode 100644
index 000000000..bc831928f
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_c.patch
@@ -0,0 +1,370 @@
+--- nginx/src/mail/ngx_mail_pop3_module.c 2023-03-07 16:26:44.727853600 +0530
++++ nginx/src/mail/ngx_mail_pop3_module.c 2023-09-14 18:47:12.652834400 +0530
+@@ -16,6 +16,7 @@
+ static char *ngx_mail_pop3_merge_srv_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+
++static ngx_str_t default_pop3_greeting = ngx_string("+OK POP3 ready");
+
+ static ngx_str_t ngx_mail_pop3_default_capabilities[] = {
+ ngx_string("TOP"),
+@@ -28,7 +29,9 @@
+ static ngx_conf_bitmask_t ngx_mail_pop3_auth_methods[] = {
+ { ngx_string("plain"), NGX_MAIL_AUTH_PLAIN_ENABLED },
+ { ngx_string("apop"), NGX_MAIL_AUTH_APOP_ENABLED },
++ { ngx_string("login"), NGX_MAIL_AUTH_LOGIN_ENABLED },
+ { ngx_string("cram-md5"), NGX_MAIL_AUTH_CRAM_MD5_ENABLED },
++ { ngx_string("gssapi"), NGX_MAIL_AUTH_GSSAPI_ENABLED },
+ { ngx_string("external"), NGX_MAIL_AUTH_EXTERNAL_ENABLED },
+ { ngx_null_string, 0 }
+ };
+@@ -44,6 +47,21 @@
+ };
+
+
++static ngx_str_t ngx_mail_pop3_auth_plain_capability =
++ ngx_string("+OK methods supported:" CRLF
++ "LOGIN" CRLF
++ "PLAIN" CRLF
++ "." CRLF);
++
++
++static ngx_str_t ngx_mail_pop3_auth_cram_md5_capability =
++ ngx_string("+OK methods supported:" CRLF
++ "LOGIN" CRLF
++ "PLAIN" CRLF
++ "CRAM-MD5" CRLF
++ "." CRLF);
++
++
+ static ngx_mail_protocol_t ngx_mail_pop3_protocol = {
+ ngx_string("pop3"),
+ ngx_string("\x04pop3"),
+@@ -57,12 +75,20 @@
+
+ ngx_string("-ERR internal server error" CRLF),
+ ngx_string("-ERR SSL certificate error" CRLF),
+- ngx_string("-ERR No required SSL certificate" CRLF)
++ ngx_string("-ERR No required SSL certificate" CRLF),
++ ngx_string("")
+ };
+
+
+ static ngx_command_t ngx_mail_pop3_commands[] = {
+
++ { ngx_string("pop3_client_buffer"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_size_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_pop3_srv_conf_t, client_buffer_size),
++ NULL },
++
+ { ngx_string("pop3_capabilities"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_1MORE,
+ ngx_mail_capabilities,
+@@ -77,6 +103,13 @@
+ offsetof(ngx_mail_pop3_srv_conf_t, auth_methods),
+ &ngx_mail_pop3_auth_methods },
+
++ { ngx_string("pop3_greeting"),
++ NGX_MAIL_MAIN_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_str_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_pop3_srv_conf_t, greeting),
++ NULL },
++
+ ngx_null_command
+ };
+
+@@ -118,6 +151,8 @@
+ return NULL;
+ }
+
++ pscf->client_buffer_size = NGX_CONF_UNSET_SIZE;
++
+ if (ngx_array_init(&pscf->capabilities, cf->pool, 4, sizeof(ngx_str_t))
+ != NGX_OK)
+ {
+@@ -134,19 +169,30 @@
+ ngx_mail_pop3_srv_conf_t *prev = parent;
+ ngx_mail_pop3_srv_conf_t *conf = child;
+
+- u_char *p;
+- size_t size, stls_only_size;
++ u_char *p, *p1, *p2, *p3;
++ size_t s1, s2, s3;
+ ngx_str_t *c, *d;
+- ngx_uint_t i, m;
++ ngx_uint_t i;
++
++ ngx_conf_merge_size_value(conf->client_buffer_size,
++ prev->client_buffer_size,
++ (size_t) 4*ngx_pagesize);
+
+ ngx_conf_merge_bitmask_value(conf->auth_methods,
+ prev->auth_methods,
+- (NGX_CONF_BITMASK_SET
+- |NGX_MAIL_AUTH_PLAIN_ENABLED));
++ NGX_CONF_BITMASK_SET);
+
++ /*
+ if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
+ conf->auth_methods |= NGX_MAIL_AUTH_LOGIN_ENABLED;
+ }
++ */
++
++ ngx_conf_merge_str_value(conf->greeting, prev->greeting,"");
++
++ if (conf->greeting.len == 0) {
++ conf->greeting = default_pop3_greeting;
++ }
+
+ if (conf->capabilities.nelts == 0) {
+ conf->capabilities = prev->capabilities;
+@@ -164,160 +210,124 @@
+ }
+ }
+
+- size = sizeof("+OK Capability list follows" CRLF) - 1
+- + sizeof("." CRLF) - 1;
+-
+- stls_only_size = size + sizeof("STLS" CRLF) - 1;
++ s1 = sizeof("+OK Capability list follows" CRLF) - 1
++ + sizeof("." CRLF)-1;
++ if (conf->auth_methods &
++ (NGX_MAIL_AUTH_PLAIN_ENABLED | NGX_MAIL_AUTH_GSSAPI_ENABLED))
++ s1 += sizeof("SASL" CRLF)-1;
++ s2 = s1;
++ s3 = s1;
+
+ c = conf->capabilities.elts;
+- for (i = 0; i < conf->capabilities.nelts; i++) {
+- size += c[i].len + sizeof(CRLF) - 1;
+-
+- if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
+- continue;
++ for (i=0; icapabilities.nelts; ++i)
++ {
++ s1 += c[i].len + sizeof (CRLF)-1;
++ s2 += c[i].len + sizeof (CRLF)-1;
++ if (ngx_strcasecmp(c[i].data, (u_char *) "USER") != 0) {
++ s3 += c[i].len + sizeof (CRLF)-1;
+ }
+-
+- stls_only_size += c[i].len + sizeof(CRLF) - 1;
+ }
+
+- size += sizeof("SASL") - 1 + sizeof(CRLF) - 1;
++ if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
++ s1 += sizeof(" PLAIN") - 1;
++ s2 += sizeof(" PLAIN") - 1;
++ s3 += sizeof(" PLAIN") - 1;
++ }
++ if (conf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED) {
++ s1 += sizeof(" GSSAPI") - 1;
++ s2 += sizeof(" GSSAPI") - 1;
++ s3 += sizeof(" GSSAPI") - 1;
++ }
+
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
+- {
+- if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
+- continue;
+- }
++ s2 += sizeof("STLS" CRLF) - 1;
++ s3 += sizeof("STLS" CRLF) - 1;
+
+- if (m & conf->auth_methods) {
+- size += 1 + ngx_mail_pop3_auth_methods_names[i].len;
+- }
++ p1 = ngx_pnalloc(cf->pool,s1);
++ if (p1 == NULL) {
++ return NGX_CONF_ERROR;
+ }
+-
+- p = ngx_pnalloc(cf->pool, size);
+- if (p == NULL) {
++ p2 = ngx_palloc(cf->pool,s2);
++ if (p2 == NULL) {
+ return NGX_CONF_ERROR;
+ }
+-
+- conf->capability.len = size;
+- conf->capability.data = p;
+-
+- p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
+- sizeof("+OK Capability list follows" CRLF) - 1);
+-
+- for (i = 0; i < conf->capabilities.nelts; i++) {
+- p = ngx_cpymem(p, c[i].data, c[i].len);
+- *p++ = CR; *p++ = LF;
++ p3 = ngx_pnalloc(cf->pool,s3);
++ if (p3 == NULL) {
++ return NGX_CONF_ERROR;
+ }
+
+- p = ngx_cpymem(p, "SASL", sizeof("SASL") - 1);
++ conf->capability.len = s1;
++ conf->capability.data = p1;
++ conf->starttls_capability.len = s2;
++ conf->starttls_capability.data = p2;
++ conf->starttls_only_capability.len = s3;
++ conf->starttls_only_capability.data = p3;
++
++ p1 = ngx_cpymem(p1, "+OK Capability list follows" CRLF,
++ sizeof("+OK Capability list follows" CRLF) - 1);
++ p2 = ngx_cpymem(p2, "+OK Capability list follows" CRLF,
++ sizeof("+OK Capability list follows" CRLF) - 1);
++ p3 = ngx_cpymem(p3, "+OK Capability list follows" CRLF,
++ sizeof("+OK Capability list follows" CRLF) - 1);
+
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
++ c = conf->capabilities.elts;
++ for (i = 0; i < conf->capabilities.nelts; ++i)
+ {
+- if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
+- continue;
+- }
+-
+- if (m & conf->auth_methods) {
+- *p++ = ' ';
+- p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
+- ngx_mail_pop3_auth_methods_names[i].len);
++ p1 = ngx_cpymem(p1,c[i].data,c[i].len);
++ p2 = ngx_cpymem(p2,c[i].data,c[i].len);
++ *p1++ = CR; *p1++ = LF;
++ *p2++ = CR; *p2++ = LF;
++ if (ngx_strcasecmp(c[i].data, (u_char *) "USER") != 0) {
++ p3 = ngx_cpymem(p3,c[i].data,c[i].len);
++ *p3++ = CR; *p3++ = LF;
+ }
+ }
+
+- *p++ = CR; *p++ = LF;
+-
+- *p++ = '.'; *p++ = CR; *p = LF;
+-
+-
+- size += sizeof("STLS" CRLF) - 1;
+-
+- p = ngx_pnalloc(cf->pool, size);
+- if (p == NULL) {
+- return NGX_CONF_ERROR;
+- }
+-
+- conf->starttls_capability.len = size;
+- conf->starttls_capability.data = p;
+-
+- p = ngx_cpymem(p, conf->capability.data,
+- conf->capability.len - (sizeof("." CRLF) - 1));
++ if (conf->auth_methods &
++ (NGX_MAIL_AUTH_PLAIN_ENABLED | NGX_MAIL_AUTH_GSSAPI_ENABLED)) {
++ p1 = ngx_cpymem(p1,"SASL",sizeof("SASL") - 1);
++ p2 = ngx_cpymem(p2,"SASL",sizeof("SASL") - 1);
++ p3 = ngx_cpymem(p3,"SASL",sizeof("SASL") - 1);
+
+- p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
+- *p++ = '.'; *p++ = CR; *p = LF;
+-
+-
+- size = sizeof("+OK methods supported:" CRLF) - 1
+- + sizeof("." CRLF) - 1;
+-
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
+- {
+- if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
+- continue;
++ if (conf->auth_methods & NGX_MAIL_AUTH_PLAIN_ENABLED) {
++ p1 = ngx_cpymem(p1," PLAIN",sizeof(" PLAIN") - 1);
++ p2 = ngx_cpymem(p2," PLAIN",sizeof(" PLAIN") - 1);
++ p3 = ngx_cpymem(p3," PLAIN",sizeof(" PLAIN") - 1);
+ }
+-
+- if (m & conf->auth_methods) {
+- size += ngx_mail_pop3_auth_methods_names[i].len
+- + sizeof(CRLF) - 1;
++ if (conf->auth_methods & NGX_MAIL_AUTH_GSSAPI_ENABLED) {
++ p1 = ngx_cpymem(p1," GSSAPI",sizeof(" GSSAPI") - 1);
++ p2 = ngx_cpymem(p2," GSSAPI",sizeof(" GSSAPI") - 1);
++ p3 = ngx_cpymem(p3," GSSAPI",sizeof(" GSSAPI") - 1);
+ }
+- }
+
+- p = ngx_pnalloc(cf->pool, size);
+- if (p == NULL) {
+- return NGX_CONF_ERROR;
++ *p1++ = CR; *p1++ = LF;
++ *p2++ = CR; *p2++ = LF;
++ *p3++ = CR; *p3++ = LF;
+ }
+
+- conf->auth_capability.data = p;
+- conf->auth_capability.len = size;
++ p2 = ngx_cpymem(p2,"STLS" CRLF, sizeof("STLS" CRLF)-1);
++ p3 = ngx_cpymem(p3,"STLS" CRLF, sizeof("STLS" CRLF)-1);
+
+- p = ngx_cpymem(p, "+OK methods supported:" CRLF,
+- sizeof("+OK methods supported:" CRLF) - 1);
++ *p1++ = '.'; *p1++ = CR; *p1++ = LF;
++ *p2++ = '.'; *p2++ = CR; *p2++ = LF;
++ *p3++ = '.'; *p3++ = CR; *p3++ = LF;
+
+- for (m = NGX_MAIL_AUTH_PLAIN_ENABLED, i = 0;
+- m <= NGX_MAIL_AUTH_EXTERNAL_ENABLED;
+- m <<= 1, i++)
+- {
+- if (ngx_mail_pop3_auth_methods_names[i].len == 0) {
+- continue;
+- }
++ /* not required */
++ if (conf->auth_methods & NGX_MAIL_AUTH_CRAM_MD5_ENABLED) {
++ conf->auth_capability = ngx_mail_pop3_auth_cram_md5_capability;
+
+- if (m & conf->auth_methods) {
+- p = ngx_cpymem(p, ngx_mail_pop3_auth_methods_names[i].data,
+- ngx_mail_pop3_auth_methods_names[i].len);
+- *p++ = CR; *p++ = LF;
+- }
++ } else {
++ conf->auth_capability = ngx_mail_pop3_auth_plain_capability;
+ }
+
+- *p++ = '.'; *p++ = CR; *p = LF;
+-
+-
+- p = ngx_pnalloc(cf->pool, stls_only_size);
++ p = ngx_pnalloc(cf->pool,conf->greeting.len + 2);
+ if (p == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+- conf->starttls_only_capability.len = stls_only_size;
+- conf->starttls_only_capability.data = p;
+-
+- p = ngx_cpymem(p, "+OK Capability list follows" CRLF,
+- sizeof("+OK Capability list follows" CRLF) - 1);
+-
+- for (i = 0; i < conf->capabilities.nelts; i++) {
+- if (ngx_strcasecmp(c[i].data, (u_char *) "USER") == 0) {
+- continue;
+- }
+-
+- p = ngx_cpymem(p, c[i].data, c[i].len);
+- *p++ = CR; *p++ = LF;
+- }
+-
+- p = ngx_cpymem(p, "STLS" CRLF, sizeof("STLS" CRLF) - 1);
+- *p++ = '.'; *p++ = CR; *p = LF;
++ ngx_memcpy(p, conf->greeting.data, conf->greeting.len);
++ ngx_memcpy(p + conf->greeting.len, CRLF, sizeof(CRLF) - 1);
++ conf->greeting.data = p;
++ conf->greeting.len += 2;
+
+ return NGX_CONF_OK;
+ }
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_h.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_h.patch
new file mode 100644
index 000000000..f28341938
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_pop3_module_h.patch
@@ -0,0 +1,24 @@
+--- nginx/src/mail/ngx_mail_pop3_module.h 2023-03-07 16:26:44.730781700 +0530
++++ nginx/src/mail/ngx_mail_pop3_module.h 2023-09-14 18:47:12.657858600 +0530
+@@ -15,6 +15,10 @@
+
+
+ typedef struct {
++ // Zimbra customizations start here (Jira Tickets: )
++ size_t client_buffer_size;
++ // Zimbra customizations end here
++
+ ngx_str_t capability;
+ ngx_str_t starttls_capability;
+ ngx_str_t starttls_only_capability;
+@@ -23,6 +27,10 @@
+ ngx_uint_t auth_methods;
+
+ ngx_array_t capabilities;
++
++ // Zimbra customizations start here (Jira Tickets: )
++ ngx_str_t greeting;
++ // Zimbra end start here
+ } ngx_mail_pop3_srv_conf_t;
+
+
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_proxy_module.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_proxy_module.patch
new file mode 100644
index 000000000..ac99d9827
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_proxy_module.patch
@@ -0,0 +1,1663 @@
+--- nginx/src/mail/ngx_mail_proxy_module.c 2023-07-23 13:21:27.110618600 +0530
++++ nginx/src/mail/ngx_mail_proxy_module.c 2023-09-14 18:47:12.661845700 +0530
+@@ -5,20 +5,32 @@
+ */
+
+
++#include
+ #include
+ #include
+ #include
+ #include
+ #include
++#include
++#include
++#include
++#include
++#include
+
++extern ngx_module_t ngx_mail_auth_http_module;
+
+ typedef struct {
+ ngx_flag_t enable;
+ ngx_flag_t pass_error_message;
++ ngx_flag_t issue_pop3_xoip;
++ ngx_flag_t issue_imap_id;
+ ngx_flag_t xclient;
++ ngx_flag_t proxy_ssl;
++ ngx_ssl_t *ssl;
+ ngx_flag_t smtp_auth;
+ ngx_flag_t proxy_protocol;
+ size_t buffer_size;
++ ngx_msec_t ctimeout;
+ ngx_msec_t timeout;
+ } ngx_mail_proxy_conf_t;
+
+@@ -39,6 +51,31 @@
+ static char *ngx_mail_proxy_merge_conf(ngx_conf_t *cf, void *parent,
+ void *child);
+
++#if (NGX_MAIL_SSL)
++static char *ngx_mail_proxy_ssl(ngx_conf_t *cf, ngx_command_t *cmd,
++ void *conf);
++static void ngx_mail_proxy_ssl_init_connection(ngx_mail_session_t *s,
++ ngx_connection_t *c);
++static void ngx_mail_proxy_ssl_handshake(ngx_connection_t *c);
++/** TODO suport ssl session reuse
++static void ngx_mail_proxy_set_session(ngx_peer_connection_t *pc);
++static void ngx_mail_proxy_save_session(ngx_peer_connection_t *pc);
++*/
++#endif
++
++/* throttle */
++static void ngx_mail_proxy_throttle_imap(ngx_event_t *rev);
++static void ngx_mail_proxy_allow_imap(throttle_callback_t *callback);
++static void ngx_mail_proxy_choke_imap(throttle_callback_t *callback);
++static void ngx_mail_proxy_throttle_pop3(ngx_event_t *rev);
++static void ngx_mail_proxy_allow_pop3(throttle_callback_t *callback);
++static void ngx_mail_proxy_choke_pop3(throttle_callback_t *callback);
++static void ngx_mail_proxy_choke_session(ngx_mail_session_t *s);
++
++/* utility */
++static ngx_str_t ngx_imap_quote_string(ngx_pool_t *pool, ngx_str_t *u);
++static void ngx_mail_proxy_auth_sleep_handler (ngx_event_t *rev);
++
+
+ static ngx_command_t ngx_mail_proxy_commands[] = {
+
+@@ -56,6 +93,13 @@
+ offsetof(ngx_mail_proxy_conf_t, buffer_size),
+ NULL },
+
++ { ngx_string("proxy_ctimeout"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_msec_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_proxy_conf_t, ctimeout),
++ NULL },
++
+ { ngx_string("proxy_timeout"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_msec_slot,
+@@ -70,6 +114,20 @@
+ offsetof(ngx_mail_proxy_conf_t, pass_error_message),
+ NULL },
+
++ { ngx_string("proxy_issue_pop3_xoip"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_proxy_conf_t, issue_pop3_xoip),
++ NULL },
++
++ { ngx_string("proxy_issue_imap_id"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1,
++ ngx_conf_set_flag_slot,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_proxy_conf_t, issue_imap_id),
++ NULL },
++
+ { ngx_string("xclient"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+@@ -77,6 +135,17 @@
+ offsetof(ngx_mail_proxy_conf_t, xclient),
+ NULL },
+
++#if (NGX_MAIL_SSL)
++
++ { ngx_string("proxy_ssl"),
++ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
++ ngx_mail_proxy_ssl,
++ NGX_MAIL_SRV_CONF_OFFSET,
++ offsetof(ngx_mail_proxy_conf_t, proxy_ssl),
++ NULL },
++
++#endif
++
+ { ngx_string("proxy_smtp_auth"),
+ NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG,
+ ngx_conf_set_flag_slot,
+@@ -121,8 +190,12 @@
+ NGX_MODULE_V1_PADDING
+ };
+
+-
++static u_char pop3_authplain[] = "AUTH PLAIN" CRLF;
++static u_char pop3_authxzimbra[] = "AUTH X-ZIMBRA" CRLF;
+ static u_char smtp_auth_ok[] = "235 2.0.0 OK" CRLF;
++static u_char imap_login_no[] = "NO LOGIN failed" CRLF;
++static u_char imap_auth_no[] = "NO AUTHENTICATE failed" CRLF;
++static u_char imap_no[] = "NO" CRLF;
+
+
+ void
+@@ -159,7 +232,9 @@
+ return;
+ }
+
+- ngx_add_timer(p->upstream.connection->read, cscf->timeout);
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++
++ ngx_add_timer(p->upstream.connection->read, pcf->ctimeout);
+
+ p->upstream.connection->data = s;
+ p->upstream.connection->pool = s->connection->pool;
+@@ -167,8 +242,6 @@
+ s->connection->read->handler = ngx_mail_proxy_block_read;
+ p->upstream.connection->write->handler = ngx_mail_proxy_write_handler;
+
+- pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+-
+ s->proxy->buffer = ngx_create_temp_buf(s->connection->pool,
+ pcf->buffer_size);
+ if (s->proxy->buffer == NULL) {
+@@ -180,6 +253,16 @@
+
+ s->out.len = 0;
+
++/* bug 32683, ssl support on mail proxy connection */
++#if (NGX_MAIL_SSL)
++
++ if (pcf->proxy_ssl && p->upstream.connection->ssl == NULL) {
++ ngx_mail_proxy_ssl_init_connection(s, p->upstream.connection);
++ return;
++ }
++
++#endif
++
+ switch (s->protocol) {
+
+ case NGX_MAIL_POP3_PROTOCOL:
+@@ -228,10 +311,20 @@
+ {
+ u_char *p;
+ ngx_int_t rc;
++ int family;
+ ngx_str_t line;
++ size_t len;
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+ ngx_mail_proxy_conf_t *pcf;
++ struct sockaddr_in *sin;
++
++#if (NGX_HAVE_INET6)
++ struct sockaddr_in6 *sin6;
++#endif
++
++ ngx_mail_core_srv_conf_t *cscf;
++ ngx_str_t ap, ap64, tmp;
+
+ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+ "mail proxy pop3 auth handler");
+@@ -239,6 +332,9 @@
+ c = rev->data;
+ s = c->data;
+
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++
+ if (rev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+ "upstream timed out");
+@@ -258,7 +354,7 @@
+ return;
+ }
+
+- rc = ngx_mail_proxy_read_response(s, 0);
++ rc = ngx_mail_proxy_read_response(s, s->mail_state);
+
+ if (rc == NGX_AGAIN) {
+ if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
+@@ -270,29 +366,158 @@
+ }
+
+ if (rc == NGX_ERROR) {
+- ngx_mail_proxy_upstream_error(s);
+- return;
++ if (s->mail_state == ngx_pop3_passwd ||
++ s->mail_state == ngx_pop3_auth_plain_response
++ )
++ {
++ if(s->proxy->upstream.connection->read->timer_set) {
++ ngx_del_timer(s->proxy->upstream.connection->read);
++ }
++
++ ngx_add_timer(s->connection->read,cscf->auth_wait_intvl);
++ s->connection->read->handler = ngx_mail_proxy_auth_sleep_handler;
++ return;
++ }
++ else
++ {
++ ngx_mail_proxy_upstream_error(s);
++ return;
++ }
++ }
++
++ if (s->mail_state == ngx_pop3_start)
++ {
++ // bug 23349 -- conditionally (not always) issue pop3 xoip command
++ if (pcf->issue_pop3_xoip == 0) {
++ s->mail_state = ngx_pop3_xoip;
++ }
+ }
+
+ switch (s->mail_state) {
+
+ case ngx_pop3_start:
+- ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0, "mail proxy send user");
++ s->connection->log->action =
++ "sending POP3 XOIP command to upstream";
+
+- s->connection->log->action = "sending user name to upstream";
++ /* Bug 13325 - The upstream server needs to record the IP address of
++ the downstream client that connected. For this, the Zimbra server
++ has been modified to support the XOIP command that will allow
++ the proxy to pass the IP address of the downstream client. Both
++ ipv4 and ipv6 (bug 56383) has been supported
++ */
++ family = s->connection->sockaddr->sa_family;
++ if (family == AF_INET) {
++ len = NGX_INET_ADDRSTRLEN;
++ sin = (struct sockaddr_in *) s->connection->sockaddr;
++
++#if (NGX_HAVE_INET6)
++ } else { /* AF_INET6 */
++ len = NGX_INET6_ADDRSTRLEN;
++ sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
++#endif
++
++ }
++
++ line.len = sizeof ("XOIP ") -1 +
++ len +
++ sizeof (CRLF) - 1;
++
++ line.data = ngx_palloc(c->pool, line.len);
+
+- line.len = sizeof("USER ") - 1 + s->login.len + 2;
+- line.data = ngx_pnalloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
+- p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
+- p = ngx_cpymem(p, s->login.data, s->login.len);
+- *p++ = CR; *p = LF;
++ p = ngx_sprintf (line.data, "XOIP ");
++ tmp.data = p;
++
++ if (family == AF_INET) {
++ len = ngx_inet_ntop (family, &(sin->sin_addr.s_addr), p,
++ line.data + line.len - p);
++
++#if (NGX_HAVE_INET6)
++ } else { /* AF_INET6 */
++ len = ngx_inet_ntop (family, &(sin6->sin6_addr.s6_addr),
++ p, line.data + line.len - p);
++#endif
++
++ }
++
++ p += len;
++
++ tmp.len = p - tmp.data;
++
++ *p++ = CR;
++ *p++ = LF;
++
++ line.len = p - line.data;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "sending POP3 XOIP command (XOIP %V)",
++ &tmp);
++
++ s->mail_state = ngx_pop3_xoip;
++
++ break;
++
++ case ngx_pop3_xoip:
++ if (!s->usedauth && (s->auth_method == NGX_MAIL_AUTH_PLAIN
++ || s->auth_method == NGX_MAIL_AUTH_PLAIN_IR))
++ {
++ /* If auth plain was used, but no authz, then we must blank out
++ login+zlogin, and use dusr+zusr in authc to upstream
++ */
++ s->dusr = s->qlogin;
++ s->zusr = s->zlogin;
++ s->qlogin.data = (u_char*)"";
++ s->qlogin.len = 0;
++ s->zlogin.data = (u_char*)"";
++ s->zlogin.len = 0;
++ s->usedauth = 1;
++ }
++
++ if (!s->usedauth)
++ {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "mail proxy send user");
++
++ s->connection->log->action = "sending user name to upstream";
++
++ line.len = sizeof("USER ") - 1 + s->qlogin.len + 2;
++ line.data = ngx_palloc(c->pool, line.len);
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ p = ngx_cpymem(line.data, "USER ", sizeof("USER ") - 1);
++ p = ngx_cpymem(p, s->qlogin.data, s->qlogin.len);
++ *p++ = CR; *p = LF;
++
++ s->mail_state = ngx_pop3_user;
++ }
++ else
++ {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "mail proxy send auth plain");
++
++ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI)
++ {
++ s->connection->log->action = "sending AUTH X-ZIMBRA to upstream";
++ line.len = sizeof(pop3_authxzimbra) -1;
++ line.data = pop3_authxzimbra;
++ }
++ else
++ {
++ s->connection->log->action = "sending AUTH PLAIN to upstream";
++ line.len = sizeof(pop3_authplain) - 1;
++ line.data = pop3_authplain;
++ }
++
++ s->mail_state = ngx_pop3_auth_plain;
++ }
+
+- s->mail_state = ngx_pop3_user;
+ break;
+
+ case ngx_pop3_user:
+@@ -315,27 +540,67 @@
+ break;
+
+ case ngx_pop3_passwd:
+- s->connection->read->handler = ngx_mail_proxy_handler;
+- s->connection->write->handler = ngx_mail_proxy_handler;
+- rev->handler = ngx_mail_proxy_handler;
+- c->write->handler = ngx_mail_proxy_handler;
++ case ngx_pop3_auth_plain_response:
++ ngx_mail_proxy_throttle_pop3(rev);
++ return;
+
+- pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+- ngx_add_timer(s->connection->read, pcf->timeout);
+- ngx_del_timer(c->read);
++ case ngx_pop3_auth_plain:
++ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI) {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "mail proxy send AUTH X-ZIMBRA response");
++ s->connection->log->action = "sending AUTH X-ZIMBRA response to upstream";
++ }
++ else {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "mail proxy send AUTH PLAIN response");
++ s->connection->log->action = "sending AUTH PLAIN response to upstream";
++ }
+
+- c->log->action = NULL;
+- ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
+
+- if (s->buffer->pos < s->buffer->last
+- || s->connection->read->ready)
+- {
+- ngx_post_event(c->write, &ngx_posted_events);
++ ap.len = s->qlogin.len + 1 +
++ s->dusr.len + 1 +
++ s->dpasswd.len;
++ ap.data = ngx_palloc (c->pool, ap.len);
++
++ if (ap.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
+ }
+
+- ngx_mail_proxy_handler(s->connection->write);
++ ngx_memcpy (ap.data, s->qlogin.data, s->qlogin.len);
++ ngx_memcpy (ap.data + s->qlogin.len, "\x0", 1);
++ ngx_memcpy (ap.data + s->qlogin.len + 1,
++ s->dusr.data,
++ s->dusr.len);
++ ngx_memcpy (ap.data + s->qlogin.len + 1 + s->dusr.len,
++ "\x0",1);
++ ngx_memcpy (ap.data + s->qlogin.len+1 + s->dusr.len + 1,
++ s->dpasswd.data,
++ s->dpasswd.len);
+
+- return;
++ ap64.len = ngx_base64_encoded_length(ap.len);
++ ap64.data = ngx_palloc(c->pool, ap64.len);
++
++ if (ap64.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ ngx_encode_base64 (&ap64, &ap);
++
++ line.len = ap64.len + sizeof(CRLF) -1;
++ line.data = ngx_palloc (c->pool, line.len);
++
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ ngx_memcpy (line.data, ap64.data, ap64.len);
++ ngx_memcpy (line.data + ap64.len, CRLF, sizeof (CRLF) -1);
++
++ s->mail_state = ngx_pop3_auth_plain_response;
++ break;
+
+ default:
+ #if (NGX_SUPPRESS_WARN)
+@@ -368,16 +633,33 @@
+ {
+ u_char *p;
+ ngx_int_t rc;
+- ngx_str_t line;
++ ngx_uint_t family;
++ size_t len;
++ ngx_str_t line, proxy_ip;
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+ ngx_mail_proxy_conf_t *pcf;
++ struct sockaddr_in *sin;
++
++#if (NGX_HAVE_INET6)
++ struct sockaddr_in6 *sin6;
++#endif
++
++ ngx_mail_core_srv_conf_t *cscf;
++ ngx_mail_imap_srv_conf_t *iscf;
++ ngx_str_t challenge;
++ ngx_str_t ql, qp, login, tmp;
++ socklen_t socklen;
++ u_char sockaddr[NGX_SOCKADDRLEN];
+
+ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+ "mail proxy imap auth handler");
+
+ c = rev->data;
+ s = c->data;
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++ cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
++ iscf = ngx_mail_get_module_srv_conf(s, ngx_mail_imap_module);
+
+ if (rev->timedout) {
+ ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT,
+@@ -409,32 +691,268 @@
+ return;
+ }
+
++ if (rc == NGX_ABORT) {
++ /* NGX_ABORT is borrowed to indicate nginx should send
++ * something coming from upstream directly. But don't return
++ * just yet as we need to replay all other responses from
++ * the upstream as well
++ */
++ if (s->connection->send(s->connection, s->out.data, s->out.len) <
++ (ssize_t) s->out.len) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++ s->proxy->buffer->pos = s->proxy->buffer->start;
++ s->proxy->buffer->last = s->proxy->buffer->start;
++ }
++
+ if (rc == NGX_ERROR) {
+- ngx_mail_proxy_upstream_error(s);
+- return;
++ if (s->mail_state == ngx_imap_passwd ||
++ s->mail_state == ngx_imap_auth_plain_ir
++ )
++ {
++ if(s->proxy->upstream.connection->read->timer_set) {
++ ngx_del_timer(s->proxy->upstream.connection->read);
++ }
++
++ ngx_add_timer(s->connection->read,cscf->auth_wait_intvl);
++ s->connection->read->handler = ngx_mail_proxy_auth_sleep_handler;
++ return;
++ }
++ else
++ {
++ ngx_mail_proxy_upstream_error(s);
++ return;
++ }
++ }
++
++ if (s->mail_state == ngx_imap_start)
++ {
++ // bug 23349 -- conditionally (not always) issue imap id command
++ if (pcf->issue_imap_id == 0) {
++ s->mail_state = ngx_imap_id;
++ }
+ }
+
+ switch (s->mail_state) {
+
+ case ngx_imap_start:
+ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
+- "mail proxy send login");
++ "mail proxy send id");
++
++ s->connection->log->action =
++ "sending IMAP ID extension command to upstream";
++
++ /* Bug 13325 - The upstream server needs to record the IP of the
++ original downstream client that connected, not just the proxy's IP
++ To pass on the information about the downstream client, we use the
++ IMAP ID extension command (rfc 2971)
+
+- s->connection->log->action = "sending LOGIN command to upstream";
++ Currently both ipv4 and ipv6 (bug 56383) are supported
++ */
++ family = s->connection->sockaddr->sa_family;
++ if (family == AF_INET) {
++ len = NGX_INET_ADDRSTRLEN;
++ sin = (struct sockaddr_in *) s->connection->sockaddr;
++
++#if (NGX_HAVE_INET6)
++ } else { /* AF_INET6 */
++ len = NGX_INET6_ADDRSTRLEN;
++ sin6 = (struct sockaddr_in6 *) s->connection->sockaddr;
++#endif
++
++ }
++
++ line.len = s->tag.len + 1 /* for space */ +
++ sizeof ("ID (\"X-ORIGINATING-IP\" \"") - 1 +
++ len +
++ sizeof ("\" \"name\" \"") - 1 +
++ iscf->ua_name.len +
++ sizeof("\" \"version\" \"") - 1 +
++ iscf->ua_version.len +
++ sizeof ("\" \"X-VIA\" \"(" NGINX_VER ")\")"CRLF) - 1;
++ ngx_memzero(sockaddr, NGX_SOCKADDRLEN);
++ socklen = NGX_SOCKADDRLEN;
++ if(getsockname(s->connection->fd, (struct sockaddr*)sockaddr, &socklen) < 0) {
++ ngx_log_error(NGX_LOG_WARN, s->connection->log, errno, "can't get proxy's IP address");
++ }
++
++ if(((struct sockaddr *)sockaddr)->sa_family == AF_INET) {
++ proxy_ip.len = NGX_INET_ADDRSTRLEN;
++ } else {
++ proxy_ip.len = NGX_INET6_ADDRSTRLEN;
++ }
++ proxy_ip.data = ngx_palloc(c->pool, proxy_ip.len);
++ proxy_ip.len = ngx_sock_ntop((struct sockaddr*)sockaddr, socklen, proxy_ip.data, proxy_ip.len, 0);
++ line.len += proxy_ip.len;
++
++ if (s->id_name.len > 0) {
++ line.len += (s->id_name.len + sizeof(",") - 1);
++ if (s->id_version.len > 0) {
++ line.len += (s->id_version.len + sizeof("/") - 1);
++ }
++ }
++
++ line.data = ngx_palloc(c->pool, line.len);
+
+- line.len = s->tag.len + sizeof("LOGIN ") - 1
+- + 1 + NGX_SIZE_T_LEN + 1 + 2;
+- line.data = ngx_pnalloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
+- line.len = ngx_sprintf(line.data, "%VLOGIN {%uz}" CRLF,
+- &s->tag, s->login.len)
+- - line.data;
++ p = ngx_sprintf (line.data, "%V ID (\"X-ORIGINATING-IP\" \"", &s->tag);
++ tmp.data = p;
++
++ if (family == AF_INET) {
++ len = ngx_inet_ntop (family, &(sin->sin_addr.s_addr), p,
++ line.data + line.len - p);
++#if (NGX_HAVE_INET6)
++ } else { /* AF_INET6 */
++ len = ngx_inet_ntop (family, &(sin6->sin6_addr.s6_addr),
++ p, line.data + line.len - p);
++#endif
++ }
++
++ p += len;
++ tmp.len = p - tmp.data;
++
++ p = ngx_sprintf(p, "\" \"name\" \"%V\" \"version\" \"%V\" \"X-VIA\" \"",
++ &iscf->ua_name, &iscf->ua_version);
++ if (s->id_name.len > 0) {
++ p = ngx_cpymem(p, s->id_name.data, s->id_name.len);
++ if (s->id_version.len > 0) {
++ *p++ = '/';
++ p = ngx_cpymem(p, s->id_version.data, s->id_version.len);
++ }
++ *p++ = ',';
++ }
++ p = ngx_sprintf(p, "%V(" NGINX_VER ")\")"CRLF, &proxy_ip);
++
++ line.len = p - line.data;
++
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "sending IMAP ID command %V",
++ &line);
++
++ s->mail_state = ngx_imap_id;
+
+- s->mail_state = ngx_imap_login;
++ break;
++
++ case ngx_imap_id:
++ /* If the downstream client has logged in with a sasl mechanism
++ that does not use clear-text passwords, we do not have the
++ end user credentials to log in to the upstream server, therefore
++ in this case, we need to log in with the master username and
++ master password, using auth plain to the upstream server
++ */
++
++ if (!s->usedauth && (s->auth_method == NGX_MAIL_AUTH_PLAIN
++ || s->auth_method == NGX_MAIL_AUTH_PLAIN_IR)) {
++ /* If auth plain was used, but no authz, then we must blank out
++ login+zlogin, and use dusr+zusr in authc to upstream
++ */
++ s->dusr = s->qlogin;
++ s->zusr = s->zlogin;
++ s->qlogin.data = (u_char*)"";
++ s->qlogin.len = 0;
++ s->zlogin.data = (u_char*)"";
++ s->zlogin.len = 0;
++ s->usedauth = 1;
++ }
++
++ if (!s->usedauth)
++ {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "no delegated auth, login to upstream using LOGIN");
++
++ s->connection->log->action = "sending LOGIN command to upstream";
++
++ /* LOGIN with literal or quoted strings (imap_literalauth) */
++ if (iscf->literalauth)
++ {
++ line.len = s->tag.len + 1 + sizeof("LOGIN ") - 1
++ + 1 + NGX_SIZE_T_LEN + 1 + 2;
++ line.data = ngx_palloc(c->pool, line.len);
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ line.len = ngx_sprintf(line.data, "%V LOGIN {%uz}" CRLF,
++ &s->tag, s->qlogin.len + s->zlogin.len)
++ - line.data;
++
++ s->mail_state = ngx_imap_login;
++ }
++ else
++ {
++ /* merge back zimbra extensions (/tb|/wm|/ni), if any */
++
++ login.data = ngx_palloc(c->pool, s->qlogin.len + s->zlogin.len);
++ if (login.data == NULL) {
++ login = s->qlogin;
++ } else {
++ login.len = s->qlogin.len + s->zlogin.len;
++ ngx_memcpy(login.data, s->qlogin.data, s->qlogin.len);
++ ngx_memcpy(login.data + s->qlogin.len, s->zlogin.data,
++ s->zlogin.len);
++ }
++ ql = ngx_imap_quote_string(c->pool, &login);
++ qp = ngx_imap_quote_string(c->pool, &s->passwd);
++
++ line.len = s->tag.len + 1 /* for space */ + sizeof("LOGIN ") - 1 +
++ ql.len +
++ sizeof(" ") - 1 +
++ qp.len +
++ sizeof(CRLF) - 1;
++
++ line.data = ngx_palloc(c->pool,line.len);
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ ngx_sprintf(line.data,"%V LOGIN %V %V" CRLF, &s->tag, &ql, &qp);
++
++ s->mail_state = ngx_imap_passwd;
++ }
++ }
++ else
++ {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "Using delegated auth to log in to upstream");
++
++ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI)
++ {
++ s->connection->log->action = "sending AUTHENTICATE X-ZIMBRA to upstream";
++
++ line.len = s->tag.len + 1 /* for space */ + sizeof ("AUTHENTICATE X-ZIMBRA") - 1 + 2;
++ line.data = ngx_palloc (c->pool, line.len);
++
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ ngx_snprintf (line.data, line.len, "%V AUTHENTICATE X-ZIMBRA" CRLF, &s->tag);
++ }
++ else
++ {
++ s->connection->log->action = "sending AUTHENTICATE PLAIN to upstream";
++
++ line.len = s->tag.len + 1 /* for space */ + sizeof ("AUTHENTICATE PLAIN") - 1 + 2;
++ line.data = ngx_palloc (c->pool, line.len);
++
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ ngx_snprintf (line.data, line.len, "%V AUTHENTICATE PLAIN" CRLF, &s->tag);
++ }
++
++ s->mail_state = ngx_imap_auth_plain;
++ }
+ break;
+
+ case ngx_imap_login:
+@@ -442,15 +960,15 @@
+
+ s->connection->log->action = "sending user name to upstream";
+
+- line.len = s->login.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2;
++ line.len = s->qlogin.len + 1 + 1 + NGX_SIZE_T_LEN + 1 + 2;
+ line.data = ngx_pnalloc(c->pool, line.len);
+ if (line.data == NULL) {
+ ngx_mail_proxy_internal_server_error(s);
+ return;
+ }
+
+- line.len = ngx_sprintf(line.data, "%V {%uz}" CRLF,
+- &s->login, s->passwd.len)
++ line.len = ngx_sprintf(line.data, "%V%V {%uz}" CRLF,
++ &s->qlogin, &s->zlogin, s->passwd.len)
+ - line.data;
+
+ s->mail_state = ngx_imap_user;
+@@ -476,31 +994,67 @@
+ break;
+
+ case ngx_imap_passwd:
+- s->connection->read->handler = ngx_mail_proxy_handler;
+- s->connection->write->handler = ngx_mail_proxy_handler;
+- rev->handler = ngx_mail_proxy_handler;
+- c->write->handler = ngx_mail_proxy_handler;
++ case ngx_imap_auth_plain_ir:
++ ngx_mail_proxy_throttle_imap(rev);
++ return;
+
+- pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+- ngx_add_timer(s->connection->read, pcf->timeout);
+- ngx_del_timer(c->read);
++ case ngx_imap_auth_plain:
++ /* RFC 4616
++ message = [authzid] UTF8NUL authcid UTF8NUL passwd
++ */
+
+- c->log->action = NULL;
+- ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
++ challenge.len = s->qlogin.len + s->zlogin.len + 1 +
++ s->dusr.len + s->zusr.len + 1 +
++ s->dpasswd.len;
++ line.len = ngx_base64_encoded_length (challenge.len);
+
+- if (s->buffer->pos < s->buffer->last
+- || s->connection->read->ready)
+- {
+- ngx_post_event(c->write, &ngx_posted_events);
++ challenge.data = ngx_palloc (c->pool, challenge.len);
++ if (challenge.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
+ }
+
+- ngx_mail_proxy_handler(s->connection->write);
++ line.data = ngx_palloc (c->pool, line.len + 2); /* +2 for CRLF */
++ if (line.data == NULL) {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
+
+- return;
++ /* construct the base64 challenge for auth-plain login to upstream */
++
++ p = challenge.data;
++ p = ngx_cpymem(p, s->qlogin.data, s->qlogin.len); /* authz */
++ p = ngx_cpymem(p, s->zlogin.data, s->zlogin.len); /* [/wm|/ni|/tb] */
++ *p++ = '\x0';
++ p = ngx_cpymem(p, s->dusr.data, s->dusr.len); /* authc */
++ p = ngx_cpymem(p, s->zusr.data, s->zusr.len); /* [/wm|/ni|/tb] for authc */
++ *p++ = '\x0';
++ p = ngx_cpymem(p, s->dpasswd.data, s->dpasswd.len); /* password */
++
++ ngx_encode_base64 (&line, &challenge);
++
++ if (s->auth_method == NGX_MAIL_AUTH_GSSAPI) {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "sending AUTH X-ZIMBRA challenge to upstream"
++ );
++ }
++ else {
++ ngx_log_debug0 (NGX_LOG_DEBUG_MAIL, rev->log, 0,
++ "sending AUTH PLAIN challenge to upstream"
++ );
++ }
++
++ ngx_memcpy (line.data + line.len, CRLF, 2);
++ line.len += 2;
++
++ s->mail_state = ngx_imap_auth_plain_ir;
++
++ break;
+
+ default:
+ #if (NGX_SUPPRESS_WARN)
+- ngx_str_null(&line);
++ line.len = 0;
++ line.data = NULL;
+ #endif
+ break;
+ }
+@@ -958,6 +1512,33 @@
+ ssize_t n;
+ ngx_buf_t *b;
+ ngx_mail_proxy_conf_t *pcf;
++ int expect_chunk;
++
++ /* (bug 21323)
++
++ during the authentication phase, the upstream imap server can include an
++ optional untagged response to the LOGIN or to the ID command
++ if the `nio_imap_enabled' parameter is set to true, then the upstream
++ server's response is split into two tcp packets, the first chunk
++ contains the untagged response, and the next chunk contains the tagged
++ result
++
++ in this function, nginx previously expected all the response to arrive
++ in a single chunk, which is not true in this case, and therefore, we
++ must maintain a state variable (expect_chunk), which has boolean
++ significance -- if the variable starts off as false, and it is marked
++ true when we encounter an untagged response
++
++ when the tagged response eventually arrives (the tag identifier is at
++ the start of a new line of response), then this variable is signaled
++ to false again, which means that we don't expect another chunk of
++ data
++
++ if we finish processing the data returned by the call to recv(), and
++ if expect_chunk is set to true, then we return NGX_AGAIN, which will
++ cause this handler to get invoked again, when the next chunk of data
++ becomes available
++ */
+
+ s->connection->log->action = "reading response from upstream";
+
+@@ -976,7 +1557,12 @@
+
+ b->last += n;
+
+- if (b->last - b->pos < 4) {
++ /* if (b->last - b->pos < 5) {
++ return NGX_AGAIN;
++ } */ /* -- This won't work with zimbra */
++
++ if ((b->last - b->pos < 5) && (b->pos) && (*b->pos != '+'))
++ {
+ return NGX_AGAIN;
+ }
+
+@@ -992,13 +1578,20 @@
+ return NGX_AGAIN;
+ }
+
++ expect_chunk = 0;
+ p = b->pos;
+
+ switch (s->protocol) {
+
+ case NGX_MAIL_POP3_PROTOCOL:
+- if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
+- return NGX_OK;
++ if (state == ngx_pop3_auth_plain) {
++ if (p[0] == '+' && p[1] == ' ') {
++ return NGX_OK;
++ }
++ } else {
++ if (p[0] == '+' && p[1] == 'O' && p[2] == 'K') {
++ return NGX_OK;
++ }
+ }
+ break;
+
+@@ -1006,23 +1599,86 @@
+ switch (state) {
+
+ case ngx_imap_start:
+- if (p[0] == '*' && p[1] == ' ' && p[2] == 'O' && p[3] == 'K') {
++ if (ngx_strncmp(p, "* OK", sizeof("* OK") - 1) == 0) {
++ char *k = strchr((char *)p, '\n');
++ if (k != NULL) {
++ /* bug 79531 identify the [ALERT] msg from upstream */
++ if (ngx_strncmp(k+1, "* OK [ALERT]", sizeof("* OK [ALERT]") - 1) == 0) {
++ ngx_log_debug0(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "ALERT message recvd from upstream");
++ s->out.len = b->last - b->pos;
++ s->out.data = b->pos;
++ return NGX_ABORT;
++ }
++ }
+ return NGX_OK;
+ }
+ break;
+
+ case ngx_imap_login:
+ case ngx_imap_user:
++ case ngx_imap_auth_plain:
+ if (p[0] == '+') {
+ return NGX_OK;
+ }
+ break;
+
++ case ngx_imap_id:
++ /* bug 68678 ignore the untagged error for the ID command */
++ if (ngx_strncmp(p, "* BAD", sizeof("* BAD") - 1) == 0) {
++ return NGX_OK;
++ }
++
++ /* fall through */
+ case ngx_imap_passwd:
+- if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0) {
+- p += s->tag.len;
+- if (p[0] == 'O' && p[1] == 'K') {
+- return NGX_OK;
++ case ngx_imap_auth_plain_ir:
++ /* Consume (optional, untagged response, plus) tagged response to
++ IMAP command previously issued
++ As the switch case indicates, we are prepared to handle this
++ after sending the ID command, or after sending the password to
++ the upstream imap server
++ In the former case, the IMAP server MAY optionally include an
++ untagged ID repsonse (RFC 2971, section 3.1)
++ In the latter case, the IMAP server MAY include a CAPABILITY
++ response code in the tagged OK response to a successful LOGIN
++ command (RFC 3501, section 6.2.3)
++ */
++
++ while ((p != NULL) && (p < b->last))
++ {
++ if (ngx_strncmp(p, s->tag.data, s->tag.len) == 0)
++ {
++ /* This line is the tagged response */
++ expect_chunk = 0;
++
++ p += s->tag.len + 1 /*for space*/;
++ if (p[0] == 'O' && p[1] == 'K')
++ {
++ return NGX_OK;
++ }
++ else
++ {
++ break;
++ }
++ }
++ else
++ {
++ /* this line is any optional untagged response
++ */
++ p = (u_char *)strstr ((char *)p, (char *)"\n");
++ if (!p)
++ {
++ /* if we don't find the newline, it indicates an
++ invalid response
++ */
++ break;
++ }
++ else
++ {
++ /* the first (possible) chunk has been read */
++ expect_chunk = 1;
++ ++p;
++ }
+ }
+ }
+ break;
+@@ -1090,6 +1746,11 @@
+ break;
+ }
+
++ if (expect_chunk == 1) {
++ return NGX_AGAIN;
++ }
++
++ s->sendquitmsg = 1;
+ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
+
+ if (pcf->pass_error_message == 0) {
+@@ -1143,6 +1804,7 @@
+ "upstream timed out");
+ }
+
++ s->sendquitmsg = 1;
+ ngx_mail_proxy_close_session(s);
+ return;
+ }
+@@ -1220,7 +1882,14 @@
+
+ n = src->recv(src, b->last, size);
+
+- if (n == NGX_AGAIN || n == 0) {
++ if (n == NGX_AGAIN) {
++ break;
++ }
++
++ if (n == 0) {
++ if (c == s->connection && !ev->write) {
++ s->sendquitmsg = 1;
++ }
+ break;
+ }
+
+@@ -1283,6 +1952,10 @@
+ }
+
+
++/* error out of an established proxy session
++ - close the upstream connection
++ - close the downstream connection after sending any pending data
++ */
+ static void
+ ngx_mail_proxy_upstream_error(ngx_mail_session_t *s)
+ {
+@@ -1291,6 +1964,14 @@
+ "close mail proxy connection: %d",
+ s->proxy->upstream.connection->fd);
+
++#if (NGX_MAIL_SSL)
++
++ if (s->proxy->upstream.connection->ssl) {
++ s->proxy->upstream.connection->ssl->no_wait_shutdown = 1;
++ ngx_ssl_shutdown(s->proxy->upstream.connection);
++ }
++#endif
++
+ ngx_close_connection(s->proxy->upstream.connection);
+ }
+
+@@ -1312,6 +1993,14 @@
+ "close mail proxy connection: %d",
+ s->proxy->upstream.connection->fd);
+
++#if (NGX_MAIL_SSL)
++
++ if (s->proxy->upstream.connection->ssl) {
++ s->proxy->upstream.connection->ssl->no_wait_shutdown = 1;
++ ngx_ssl_shutdown(s->proxy->upstream.connection);
++ }
++#endif
++
+ ngx_close_connection(s->proxy->upstream.connection);
+ }
+
+@@ -1327,10 +2016,22 @@
+ "close mail proxy connection: %d",
+ s->proxy->upstream.connection->fd);
+
++#if (NGX_MAIL_SSL)
++
++ if (s->proxy->upstream.connection->ssl) {
++ s->proxy->upstream.connection->ssl->no_wait_shutdown = 1;
++ ngx_ssl_shutdown(s->proxy->upstream.connection);
++ }
++#endif
++
+ ngx_close_connection(s->proxy->upstream.connection);
+ }
+
+- ngx_mail_close_connection(s->connection);
++ if (s->sendquitmsg) {
++ ngx_mail_end_session(s);
++ } else {
++ ngx_mail_close_connection(s->connection);
++ }
+ }
+
+
+@@ -1346,11 +2047,16 @@
+
+ pcf->enable = NGX_CONF_UNSET;
+ pcf->pass_error_message = NGX_CONF_UNSET;
++ pcf->issue_pop3_xoip = NGX_CONF_UNSET;
++ pcf->issue_imap_id = NGX_CONF_UNSET;
+ pcf->xclient = NGX_CONF_UNSET;
+ pcf->smtp_auth = NGX_CONF_UNSET;
+ pcf->proxy_protocol = NGX_CONF_UNSET;
+ pcf->buffer_size = NGX_CONF_UNSET_SIZE;
++ pcf->ctimeout = NGX_CONF_UNSET_MSEC;
+ pcf->timeout = NGX_CONF_UNSET_MSEC;
++ pcf->proxy_ssl = NGX_CONF_UNSET;
++ pcf->ssl = NGX_CONF_UNSET_PTR;
+
+ return pcf;
+ }
+@@ -1364,12 +2070,500 @@
+
+ ngx_conf_merge_value(conf->enable, prev->enable, 0);
+ ngx_conf_merge_value(conf->pass_error_message, prev->pass_error_message, 0);
++ ngx_conf_merge_value(conf->issue_pop3_xoip, prev->issue_pop3_xoip, 1);
++ ngx_conf_merge_value(conf->issue_imap_id, prev->issue_imap_id, 1);
+ ngx_conf_merge_value(conf->xclient, prev->xclient, 1);
++ ngx_conf_merge_value(conf->proxy_ssl, prev->proxy_ssl, 0);
++ ngx_conf_merge_ptr_value(conf->ssl, prev->ssl, NULL);
+ ngx_conf_merge_value(conf->smtp_auth, prev->smtp_auth, 0);
+ ngx_conf_merge_value(conf->proxy_protocol, prev->proxy_protocol, 0);
+ ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
+ (size_t) ngx_pagesize);
++ ngx_conf_merge_msec_value(conf->ctimeout, prev->ctimeout, 2 * 60000);
+ ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000);
+
+ return NGX_CONF_OK;
+ }
++
++#if (NGX_MAIL_SSL)
++
++static char *
++ngx_mail_proxy_ssl(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) {
++
++ ngx_pool_cleanup_t *cln;
++ char *rc;
++ ngx_mail_proxy_conf_t *pcf;
++
++ rc = ngx_conf_set_flag_slot(cf, cmd, conf);
++ if (rc != NGX_CONF_OK) {
++ return rc;
++ }
++
++ pcf = (ngx_mail_proxy_conf_t *)conf;
++
++ if (!pcf->proxy_ssl) {
++ return NGX_CONF_OK;
++ }
++
++ pcf->ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t));
++
++ if (pcf->ssl == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ pcf->ssl->log = cf->log;
++
++ // don't support SSLv2 anymore
++ if (ngx_ssl_create(pcf->ssl, ~(NGX_SSL_SSLv2|NGX_SSL_SSLv3), NULL)
++ != NGX_OK) {
++ return NGX_CONF_ERROR;
++ }
++
++ cln = ngx_pool_cleanup_add(cf->pool, 0);
++ if (cln == NULL) {
++ return NGX_CONF_ERROR;
++ }
++
++ cln->handler = ngx_ssl_cleanup_ctx;
++ cln->data = pcf->ssl;
++
++ return NGX_CONF_OK;
++}
++
++#endif
++/* throttle imap session if necessary (user has just finished logging in) */
++static void ngx_mail_proxy_throttle_imap(ngx_event_t *rev)
++{
++ throttle_callback_t *callback;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_mail_proxy_conf_t *pcf;
++ ngx_mail_session_t *s;
++ ngx_connection_t *c;
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++ ngx_str_t user;
++
++ c = rev->data;
++ s = c->data;
++ pool = c->pool;
++ log = ngx_cycle->log;
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++
++ callback = ngx_pcalloc(pool, sizeof(throttle_callback_t));
++ if (callback == NULL) {
++ ngx_mail_proxy_upstream_error(s);
++ return;
++ }
++
++ callback->check_only = 0; /* increment the counter */
++ callback->session = s;
++ callback->connection = c;
++ callback->rev = rev;
++ callback->config = pcf;
++ callback->log = log;
++ callback->pool = pool;
++ callback->on_allow = ngx_mail_proxy_allow_imap;
++ callback->on_deny = ngx_mail_proxy_choke_imap;
++
++ if (tscf->mail_login_user_max == 0) {
++ callback->on_allow(callback);
++ } else {
++ user = s->qlogin;
++ if ((user.len == 0) && (s->auth_method == NGX_MAIL_AUTH_PLAIN
++ || s->auth_method == NGX_MAIL_AUTH_PLAIN_IR)) {
++ user = s->dusr;
++ }
++ ngx_mail_throttle_user(user, callback);
++ }
++}
++
++static void ngx_mail_proxy_allow_imap(throttle_callback_t *callback)
++{
++ ngx_mail_session_t *s = callback->session;
++ ngx_event_t *rev = callback->rev;
++ ngx_connection_t *c = callback->connection;
++ ngx_mail_proxy_conf_t *pcf = callback->config;
++
++ s->connection->read->handler = ngx_mail_proxy_handler;
++ s->connection->write->handler = ngx_mail_proxy_handler;
++ rev->handler = ngx_mail_proxy_handler;
++ c->write->handler = ngx_mail_proxy_handler;
++
++ ngx_add_timer(s->connection->read, pcf->timeout);
++ if (c->read->timer_set) {
++ ngx_del_timer(c->read);
++ }
++
++ c->log->action = NULL;
++ ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
++
++ ngx_mail_proxy_handler(s->connection->write);
++}
++
++static void ngx_mail_proxy_choke_imap(throttle_callback_t *callback)
++{
++ ngx_mail_session_t *s = callback->session;
++ ngx_mail_proxy_choke_session(s);
++}
++
++/* throttle pop3 session if necessary (user has just finished logging in) */
++static void ngx_mail_proxy_throttle_pop3(ngx_event_t *rev)
++{
++ throttle_callback_t *callback;
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_mail_proxy_conf_t *pcf;
++ ngx_mail_session_t *s;
++ ngx_connection_t *c;
++ ngx_pool_t *pool;
++ ngx_log_t *log;
++ ngx_str_t user;
++
++ c = rev->data;
++ s = c->data;
++ pool = c->pool;
++ log = ngx_cycle->log;
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++
++ callback = ngx_pcalloc(pool, sizeof(throttle_callback_t));
++ if (callback == NULL) {
++ ngx_mail_proxy_upstream_error(s);
++ return;
++ }
++
++ callback->check_only = 0; /* increment the counter */
++ callback->session = s;
++ callback->connection = c;
++ callback->rev = rev;
++ callback->config = pcf;
++ callback->log = log;
++ callback->pool = pool;
++ callback->on_allow = ngx_mail_proxy_allow_pop3;
++ callback->on_deny = ngx_mail_proxy_choke_pop3;
++
++ if (tscf->mail_login_user_max == 0) {
++ callback->on_allow(callback);
++ } else {
++ user = s->qlogin;
++ if ((user.len == 0) && (s->auth_method == NGX_MAIL_AUTH_PLAIN
++ || s->auth_method == NGX_MAIL_AUTH_PLAIN_IR)) {
++ user = s->dusr;
++ }
++ ngx_mail_throttle_user(user, callback);
++ }
++}
++
++static void ngx_mail_proxy_allow_pop3(throttle_callback_t *callback)
++{
++ ngx_mail_session_t *s = callback->session;
++ ngx_event_t *rev = callback->rev;
++ ngx_connection_t *c = callback->connection;
++ ngx_mail_proxy_conf_t *pcf = callback->config;
++
++ s->connection->read->handler = ngx_mail_proxy_handler;
++ s->connection->write->handler = ngx_mail_proxy_handler;
++ rev->handler = ngx_mail_proxy_handler;
++ c->write->handler = ngx_mail_proxy_handler;
++
++ ngx_add_timer(s->connection->read, pcf->timeout);
++ if (c->read->timer_set) {
++ ngx_del_timer(c->read);
++ }
++
++ c->log->action = NULL;
++ ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
++
++ ngx_mail_proxy_handler(s->connection->write);
++}
++
++static void ngx_mail_proxy_choke_pop3(throttle_callback_t *callback)
++{
++ ngx_mail_session_t *s = callback->session;
++ ngx_mail_proxy_choke_session(s);
++}
++
++static void ngx_mail_proxy_choke_session(ngx_mail_session_t *s)
++{
++ ngx_mail_throttle_srv_conf_t *tscf;
++ ngx_str_t bye, msg, umsg;
++ ngx_pool_t *pool;
++ u_char *p;
++
++ tscf = ngx_mail_get_module_srv_conf(s, ngx_mail_throttle_module);
++ pool = s->connection->pool;
++ msg = tscf->mail_login_user_rejectmsg;
++
++ if (s->proxy->upstream.connection)
++ {
++ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, s->connection->log, 0,
++ "close mail proxy connection: %d",
++ s->proxy->upstream.connection->fd);
++
++#if (NGX_MAIL_SSL)
++
++ if (s->proxy->upstream.connection->ssl) {
++ s->proxy->upstream.connection->ssl->no_wait_shutdown = 1;
++ ngx_ssl_shutdown(s->proxy->upstream.connection);
++ }
++#endif
++
++ ngx_close_connection(s->proxy->upstream.connection);
++ }
++
++ if (s->protocol == NGX_MAIL_IMAP_PROTOCOL)
++ {
++ bye.len = sizeof("* BYE ") - 1 +
++ msg.len +
++ sizeof(CRLF) - 1;
++
++ bye.data = ngx_palloc(pool, bye.len);
++
++ if (bye.data != NULL)
++ {
++ p = bye.data;
++ p = ngx_cpymem(p,"* BYE ",sizeof("* BYE ")-1);
++ p = ngx_cpymem(p, msg.data, msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p - bye.data;
++ }
++ else
++ {
++ bye.data = (u_char *) ("* BYE" CRLF);
++ bye.len = sizeof("* BYE" CRLF)-1;
++ }
++
++ s->out = bye;
++ s->quit = 0;
++ ngx_mail_send(s->connection->write);
++
++ if (s->command == NGX_IMAP_LOGIN) {
++ umsg.data = imap_login_no;
++ umsg.len = sizeof(imap_login_no) - 1;
++ } else if (s->command == NGX_IMAP_AUTHENTICATE) {
++ umsg.data = imap_auth_no;
++ umsg.len = sizeof(imap_auth_no) - 1;
++ } else {
++ umsg.data = imap_no;
++ umsg.len = sizeof(imap_no) - 1;
++ }
++
++ s->out.len = s->tag.len + 1 /*for space*/+ umsg.len;
++ s->out.data = ngx_palloc(pool, s->out.len);
++
++ if (s->out.data == NULL) {
++ s->out.data = (u_char*)"";
++ s->out.len = 0;
++ ngx_mail_close_connection(s->connection);
++ } else {
++ ngx_memcpy(s->out.data, s->tag.data, s->tag.len);
++ *(s->out.data + s->tag.len) = ' ';
++ ngx_memcpy(s->out.data + s->tag.len + 1, umsg.data, umsg.len);
++ s->quit = 1;
++ ngx_mail_send(s->connection->write);
++ }
++
++ return;
++ }
++ else if (s->protocol == NGX_MAIL_POP3_PROTOCOL)
++ {
++ bye.len = sizeof("-ERR ")-1 +
++ msg.len +
++ sizeof(CRLF)-1;
++
++ bye.data = ngx_palloc(pool,bye.len);
++
++ if (bye.data != NULL)
++ {
++ p = bye.data;
++ p = ngx_cpymem(p,"-ERR ",sizeof("-ERR ")-1);
++ p = ngx_cpymem(p,msg.data,msg.len);
++ *p++ = CR;
++ *p++ = LF;
++ bye.len = p-bye.data;
++ }
++ else
++ {
++ bye.data = (u_char *)("-ERR" CRLF);
++ bye.len = sizeof("-ERR" CRLF)-1;
++ }
++
++ s->out = bye;
++ s->quit = 1;
++ ngx_mail_send(s->connection->write);
++ return;
++ }
++ else
++ {
++ /* TODO ?? reject SMTP ?? */
++ bye.data = (u_char *)"";
++ bye.len = 0;
++ s->out = bye;
++ s->quit = 1;
++ ngx_mail_send(s->connection->write);
++ return;
++ }
++}
++
++/* Quote an IMAP string according to RFC 3501, section 9 (formal syntax) */
++static ngx_str_t ngx_imap_quote_string(ngx_pool_t *pool, ngx_str_t *u)
++{
++ size_t s;
++ ngx_str_t k;
++ u_char *p,*q,*r;
++
++ s = 2;
++ q = u->data;
++ r = q + u->len;
++
++ while (qdata;
++ r = q + u->len;
++ *p++ = '"';
++ while (qlog, 0,
++ "mail proxy auth sleep handler");
++
++ c = rev->data;
++ s = c->data;
++
++ ngx_zm_lookup_delete_cache(s->key_alias, s->key_route);
++
++ if (rev->timedout) {
++ ngx_mail_proxy_upstream_error(s);
++ return;
++ }
++
++ if (rev->active) {
++ if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
++ ngx_mail_proxy_upstream_error(s);
++ }
++ }
++}
++
++ngx_flag_t
++ngx_mail_get_proxy_ssl (ngx_mail_session_t * s)
++{
++ ngx_mail_proxy_conf_t * pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++ return pcf->proxy_ssl;
++}
++
++#if (NGX_HTTP_SSL)
++
++static void
++ngx_mail_proxy_ssl_init_connection(ngx_mail_session_t *s, ngx_connection_t *c)
++{
++ ngx_int_t rc;
++ ngx_mail_proxy_conf_t *pcf;
++
++ pcf = ngx_mail_get_module_srv_conf(s, ngx_mail_proxy_module);
++
++ if (ngx_ssl_create_connection(pcf->ssl, c,
++ NGX_SSL_BUFFER|NGX_SSL_CLIENT)
++ != NGX_OK)
++ {
++ ngx_mail_proxy_internal_server_error(s);
++ return;
++ }
++
++ s->connection->log->action = "SSL handshaking to upstream";
++
++ rc = ngx_ssl_handshake(c);
++
++ if (rc == NGX_AGAIN) {
++ c->ssl->handler = ngx_mail_proxy_ssl_handshake;
++ return;
++ }
++
++ ngx_mail_proxy_ssl_handshake(c);
++}
++
++
++static void
++ngx_mail_proxy_ssl_handshake(ngx_connection_t *c)
++{
++ ngx_mail_session_t *s;
++ s = c->data;
++
++ if (c->ssl->handshaked) {
++
++ c->write->handler = ngx_mail_proxy_write_handler;
++ switch (s->protocol) {
++
++ case NGX_MAIL_POP3_PROTOCOL:
++ c->read->handler = ngx_mail_proxy_pop3_handler;
++ s->mail_state = ngx_pop3_start;
++ break;
++
++ case NGX_MAIL_IMAP_PROTOCOL:
++ c->read->handler = ngx_mail_proxy_imap_handler;
++ s->mail_state = ngx_imap_start;
++ break;
++
++ default: /* NGX_MAIL_SMTP_PROTOCOL */
++ c->read->handler = ngx_mail_proxy_smtp_handler;
++ s->mail_state = ngx_smtp_start;
++ break;
++ }
++
++ /* server might have send the intial welcome msg */
++ c->read->handler(c->read);
++ } else {
++ /* when handshake fails, we should close the session */
++ ngx_mail_proxy_upstream_error(s);
++ }
++}
++
++/** TODO support ssl session reuse
++void
++ngx_mail_proxy_set_session (ngx_peer_connection_t *pc, ngx_mail_proxy_ctx_t *ctx)
++{
++ ngx_ssl_session_t *ssl_session;
++ ngx_int_t rc;
++
++ ssl_session = peer->ssl_session;
++
++ rc = ngx_ssl_set_session(pc->connection, ssl_session);
++
++ ngx_log_debug2(NGX_LOG_DEBUG_MAIL, pc->log, 0,
++ "set session: %p:%d",
++ ssl_session, ssl_session ? ssl_session->references : 0);
++ return;
++}
++
++void
++ngx_mail_proxy_save_session (ngx_peer_connection_t *pc)
++{
++
++}
++*/
++
++#endif
++
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_smtp_module.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_smtp_module.patch
new file mode 100644
index 000000000..1df46d629
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_smtp_module.patch
@@ -0,0 +1,14 @@
+--- nginx/src/mail/ngx_mail_smtp_module.c 2023-03-07 16:26:44.739565600 +0530
++++ nginx/src/mail/ngx_mail_smtp_module.c 2023-09-14 18:47:12.670786200 +0530
+@@ -50,7 +50,10 @@
+
+ ngx_string("451 4.3.2 Internal server error" CRLF),
+ ngx_string("421 4.7.1 SSL certificate error" CRLF),
+- ngx_string("421 4.7.1 No required SSL certificate" CRLF)
++ // Zimbra customizations start here (Jira Tickets: )
++ ngx_string("421 4.7.1 No required SSL certificate" CRLF),
++ ngx_string("") /* zimbra add a quite_msg field in mail protocol */
++ // Zimbra customizations end here
+ };
+
+
From 036f98f5a300cd00bd7bf06abd1b662c9c6f4a7a Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Mon, 2 Oct 2023 16:58:35 +0530
Subject: [PATCH 08/14] ZCS-13998 : NGINX - Customization code separation from
repo
- Changed in order to work the customization for the any nginx version got from public repository.
ZCS-13998 : NGINX - Customization code separation from repo
- Added patch files in order to apply zimbra specific customizations
ZCS-13998 : NGINX - Customization code separation from repo
- Changes to create build with patches
Update Makefile
ZCS-13998 : NGINX - Customization code separation from repo
- Update build file
ZCS-13998 : NGINX - Customization code separation from repo
- customization related changes
ZCS-13998 : NGINX - Customization code separation from repo
- build failure fix
ZCS-13998 : NGINX - Customization code separation from repo
ZCS-13998 : NGINX - Customization code separation from repo
- build failure fixes
ZCS-13998 : NGINX - Customization code separation from repo
- fix
ZCS-13998 : NGINX - Customization code separation from repo
- fix
ZCS-13998 : NGINX - Customization code separation from repo
- compilation fixes
ZCS-13998 : NGINX - Customization code separation from repo
- fixed compilation
---
thirdparty/nginx/Makefile | 16 +++++--
.../nginx/zimbra-nginx/debian/patches/series | 22 +++++++++
thirdparty/nginx/zimbra-nginx/debian/rules | 5 +-
.../nginx/zimbra-nginx/debian/source/format | 2 +-
.../nginx/zimbra-nginx/rpm/SPECS/nginx.spec | 46 ++++++++++++++++++-
5 files changed, 84 insertions(+), 7 deletions(-)
create mode 100644 thirdparty/nginx/zimbra-nginx/debian/patches/series
diff --git a/thirdparty/nginx/Makefile b/thirdparty/nginx/Makefile
index 4f582c8b8..e282aeb8e 100644
--- a/thirdparty/nginx/Makefile
+++ b/thirdparty/nginx/Makefile
@@ -6,8 +6,10 @@ psrctmp := $(PLATFORM_DIR)/srctmp
pvers := $(NGINX_VERSION)
pname := nginx
zname := zimbra-$(pname)
-pfile := $(zname)-$(pvers).tar.gz
+pfile := $(pname)-$(pvers).tar.gz
+purl := http://nginx.org/download/$(pname)-$(pvers).tar.gz
psrc_file := $(SRC_DIR)/$(pfile)
+psrc_final_file := $(SRC_DIR)/$(zname)-$(pvers).tar.gz
zspec := $(pname).spec
zmodules := zmmodules
@@ -19,7 +21,11 @@ getsrc:
mkdir -p $(SRC_DIR)
mkdir -p $(psrctmp)
mkdir -p $(psrctmp)/$(pname)-$(pvers)-zimbra/
- cp -pr $(pname)/* $(psrctmp)/$(pname)-$(pvers)-zimbra/
+ cd $(psrctmp) && \
+ $(WGET) $(purl) && \
+ $(TAR) -xvf $(pname)-$(pvers).tar.gz && \
+ cp -pr $(pname)-$(pvers)/* $(psrctmp)/$(pname)-$(pvers)-zimbra/
+ cd $(PLATFORM_DIR)
mkdir -p $(psrctmp)/$(pname)-$(pvers)-zimbra/modules
cd $(psrctmp)/$(pname)-$(pvers)-zimbra/modules && \
git clone https://github.com/nviennot/nginx-tcp-keepalive.git nviennot-nginx-tcp-keepalive >/dev/null 2>&1 && \
@@ -51,7 +57,8 @@ build_rpm:
$(replace-pkginfo) $(specfile) && \
$(replace-pathinfo) $(specfile) && \
$(MKDIR) BUILD BUILDROOT RPMS SOURCES SRPMS && \
- $(CP) $(psrc_file) SOURCES/ && \
+ $(CP) $(psrc_final_file) SOURCES/ && \
+ $(CP) $(PKG_ROOT)/patches/*.patch SOURCES/ && \
$(PKG_BUILD) $(specfile)
build_deb: z_tgz = $(zname)_$(pvers).orig.tar.gz
@@ -60,8 +67,9 @@ build_deb:
$(CD) $(PLATFORM_DIR)/$(zname) && \
$(replace-pkginfo) debian/changelog $(z_shlibs) && \
$(replace-pathinfo) debian/rules && \
- $(CP) $(psrc_file) ../$(z_tgz) && \
+ $(CP) $(psrc_final_file) ../$(z_tgz) && \
$(TAR) xfz ../$(z_tgz) --strip-components=1 && \
+ $(CP) $(PKG_ROOT)/patches/*.patch debian/patches/ && \
$(PKG_BUILD)
clean: pkgrm
diff --git a/thirdparty/nginx/zimbra-nginx/debian/patches/series b/thirdparty/nginx/zimbra-nginx/debian/patches/series
new file mode 100644
index 000000000..7e145a7f8
--- /dev/null
+++ b/thirdparty/nginx/zimbra-nginx/debian/patches/series
@@ -0,0 +1,22 @@
+nginx_auto_cc.patch
+nginx_auto_lib.patch
+nginx_auto_modules.patch
+nginx_auto_options.patch
+nginx_auto_sources.patch
+nginx_README.patch
+nginx_src_core.patch
+nginx_src_event.patch
+nginx_src_http.patch
+nginx_src_mail_ngx_mail.patch
+nginx_src_mail_ngx_mail_auth_http_module.patch
+nginx_src_mail_ngx_mail_core_module.patch
+nginx_src_mail_ngx_mail_handler.patch
+nginx_src_mail_ngx_mail_imap_handler.patch
+nginx_src_mail_ngx_mail_imap_module_c.patch
+nginx_src_mail_ngx_mail_imap_module_h.patch
+nginx_src_mail_ngx_mail_parse.patch
+nginx_src_mail_ngx_mail_pop3_handler.patch
+nginx_src_mail_ngx_mail_pop3_module_c.patch
+nginx_src_mail_ngx_mail_pop3_module_h.patch
+nginx_src_mail_ngx_mail_proxy_module.patch
+nginx_src_mail_ngx_mail_smtp_module.patch
\ No newline at end of file
diff --git a/thirdparty/nginx/zimbra-nginx/debian/rules b/thirdparty/nginx/zimbra-nginx/debian/rules
index 566d0cd03..eea5712f8 100755
--- a/thirdparty/nginx/zimbra-nginx/debian/rules
+++ b/thirdparty/nginx/zimbra-nginx/debian/rules
@@ -1,5 +1,6 @@
#!/usr/bin/make -f
export DEB_BUILD_OPTIONS=nocheck
+export DH_VERBOSE=1
# Ensure rpath is set correctly
export DEB_LDFLAGS_MAINT_APPEND=-Wl,-rpath,OZCL
@@ -9,8 +10,10 @@ export DEB_CFLAGS_MAINT_APPEND=-O0
%:
dh $@
+override_dh_auto_clean:
+
override_dh_auto_configure:
- ./auto/configure --prefix=OZC \
+ ./configure --prefix=OZC \
--with-cc-opt="-g -IOZCI" \
--with-ld-opt="-Wl,-rpath,OZCL -LOZCL" \
--with-debug \
diff --git a/thirdparty/nginx/zimbra-nginx/debian/source/format b/thirdparty/nginx/zimbra-nginx/debian/source/format
index 89ae9db8f..163aaf8d8 100644
--- a/thirdparty/nginx/zimbra-nginx/debian/source/format
+++ b/thirdparty/nginx/zimbra-nginx/debian/source/format
@@ -1 +1 @@
-3.0 (native)
+3.0 (quilt)
diff --git a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
index 706338689..98e994915 100644
--- a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
+++ b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
@@ -4,6 +4,28 @@ Version: VERSION
Release: 1zimbra8.8b4ZAPPEND
License: MIT
Source: %{name}-%{version}.tar.gz
+Patch0: nginx_auto_cc.patch
+Patch1: nginx_auto_lib.patch
+Patch2: nginx_auto_modules.patch
+Patch3: nginx_auto_options.patch
+Patch4: nginx_auto_sources.patch
+Patch5: nginx_README.patch
+Patch6: nginx_src_core.patch
+Patch7: nginx_src_event.patch
+Patch8: nginx_src_http.patch
+Patch9: nginx_src_mail_ngx_mail.patch
+Patch10: nginx_src_mail_ngx_mail_auth_http_module.patch
+Patch11: nginx_src_mail_ngx_mail_core_module.patch
+Patch12: nginx_src_mail_ngx_mail_handler.patch
+Patch13: nginx_src_mail_ngx_mail_imap_handler.patch
+Patch14: nginx_src_mail_ngx_mail_imap_module_c.patch
+Patch15: nginx_src_mail_ngx_mail_imap_module_h.patch
+Patch16: nginx_src_mail_ngx_mail_parse.patch
+Patch17: nginx_src_mail_ngx_mail_pop3_handler.patch
+Patch18: nginx_src_mail_ngx_mail_pop3_module_c.patch
+Patch19: nginx_src_mail_ngx_mail_pop3_module_h.patch
+Patch20: nginx_src_mail_ngx_mail_proxy_module.patch
+Patch21: nginx_src_mail_ngx_mail_smtp_module.patch
BuildRequires: pcre-devel, zlib-devel
BuildRequires: zimbra-openssl-devel >= 3.0.9-1zimbra8.8b1ZAPPEND
BuildRequires: zimbra-cyrus-sasl-devel >= 2.1.28-1zimbra8.7b4ZAPPEND
@@ -62,11 +84,33 @@ The Zimbra nginx build
%prep
%setup -n nginx-%{version}-zimbra
+%patch0 -p1
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+%patch8 -p1
+%patch9 -p1
+%patch10 -p1
+%patch11 -p1
+%patch12 -p1
+%patch13 -p1
+%patch14 -p1
+%patch15 -p1
+%patch16 -p1
+%patch17 -p1
+%patch18 -p1
+%patch19 -p1
+%patch20 -p1
+%patch21 -p1
%build
LDFLAGS="-Wl,-rpath,OZCL"; export LDFLAGS; \
CFLAGS="-g -O0"; export CFLAGS; \
-./auto/configure --prefix=OZC \
+./configure --prefix=OZC \
--with-cc-opt="-g -IOZCI" \
--with-ld-opt="-Wl,-rpath,OZCL -LOZCL" \
--with-debug \
From f7d9f87e2779534b49b22abf78b0ae17417fc170 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Mon, 9 Oct 2023 16:06:23 +0530
Subject: [PATCH 09/14] ZCS-13998 : NGINX - Customization code separation from
repo
- Some review comments
---
thirdparty/nginx/patches/nginx_README.patch | 2 +-
.../nginx_src_mail_ngx_mail_parse.patch | 68 ++++++++++---------
2 files changed, 37 insertions(+), 33 deletions(-)
diff --git a/thirdparty/nginx/patches/nginx_README.patch b/thirdparty/nginx/patches/nginx_README.patch
index 876c1167d..38b24b509 100644
--- a/thirdparty/nginx/patches/nginx_README.patch
+++ b/thirdparty/nginx/patches/nginx_README.patch
@@ -5,7 +5,7 @@
+
+This is the official repository for building out the third party dependency nginx for Zimbra Collaboration Suite 8.7 and later.
+
-+Issues should be reported via [Zimbra's bugzilla](https://bugzilla.zimbra.com)
++Issues should be reported via [Zimbra's jira](https://synacor.atlassian.net/jira/your-work)
+
+## Development branch
+zimbra/develop
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
index ee70dacb9..5756360ac 100644
--- a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
@@ -1,5 +1,5 @@
---- nginx/src/mail/ngx_mail_parse.c 2023-03-07 16:26:44.722976000 +0530
-+++ nginx/src/mail/ngx_mail_parse.c 2023-09-18 19:18:53.672156800 +0530
+--- nginx/src/mail/ngx_mail_parse.c 2023-10-03 16:49:31.548168900 +0530
++++ nginx/src/mail/ngx_mail_parse.c 2023-10-09 13:58:27.495188500 +0530
@@ -14,21 +14,104 @@
#include
@@ -268,7 +268,7 @@
for (p = s->buffer->pos; p < s->buffer->last; p++) {
ch = *p;
-@@ -254,18 +332,18 @@
+@@ -254,21 +332,22 @@
switch (state) {
/* IMAP tag */
@@ -292,7 +292,11 @@
break;
case CR:
case LF:
-@@ -279,15 +357,15 @@
++ case '\x0':
+ goto invalid;
+ default:
+ if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')
+@@ -279,15 +358,15 @@
}
if (p - s->tag_start > 31) {
goto invalid;
@@ -312,7 +316,7 @@
switch (ch) {
case ' ':
break;
-@@ -296,18 +374,41 @@
+@@ -296,18 +375,41 @@
goto invalid;
default:
s->cmd_start = p;
@@ -356,7 +360,7 @@
case 4:
if ((c[0] == 'N' || c[0] == 'n')
&& (c[1] == 'O'|| c[1] == 'o')
-@@ -315,7 +416,7 @@
+@@ -315,7 +417,7 @@
&& (c[3] == 'P'|| c[3] == 'p'))
{
s->command = NGX_IMAP_NOOP;
@@ -365,7 +369,7 @@
} else {
goto invalid;
}
-@@ -329,7 +430,7 @@
+@@ -329,7 +431,7 @@
&& (c[4] == 'N'|| c[4] == 'n'))
{
s->command = NGX_IMAP_LOGIN;
@@ -374,7 +378,7 @@
} else {
goto invalid;
}
-@@ -344,7 +445,7 @@
+@@ -344,7 +446,7 @@
&& (c[5] == 'T'|| c[5] == 't'))
{
s->command = NGX_IMAP_LOGOUT;
@@ -383,7 +387,7 @@
} else {
goto invalid;
}
-@@ -362,7 +463,7 @@
+@@ -362,7 +464,7 @@
&& (c[7] == 'S'|| c[7] == 's'))
{
s->command = NGX_IMAP_STARTTLS;
@@ -392,7 +396,7 @@
} else {
goto invalid;
}
-@@ -382,7 +483,7 @@
+@@ -382,7 +484,7 @@
&& (c[9] == 'Y'|| c[9] == 'y'))
{
s->command = NGX_IMAP_CAPABILITY;
@@ -401,7 +405,7 @@
} else {
goto invalid;
}
-@@ -402,7 +503,12 @@
+@@ -402,7 +504,12 @@
&& (c[10] == 'T'|| c[10] == 't')
&& (c[11] == 'E'|| c[11] == 'e'))
{
@@ -415,7 +419,7 @@
} else {
goto invalid;
-@@ -418,10 +524,13 @@
+@@ -418,10 +525,13 @@
switch (ch) {
case ' ':
@@ -431,7 +435,7 @@
break;
case LF:
goto done;
-@@ -435,40 +544,46 @@
+@@ -435,40 +545,46 @@
break;
@@ -487,7 +491,7 @@
if (ch == ' ' && s->quoted) {
break;
}
-@@ -510,10 +625,10 @@
+@@ -510,10 +626,10 @@
switch (ch) {
case '"':
case ' ':
@@ -500,7 +504,7 @@
break;
case LF:
goto done;
-@@ -522,46 +637,52 @@
+@@ -522,46 +638,52 @@
case '\\':
if (s->quoted) {
s->backslash = 1;
@@ -562,7 +566,7 @@
switch (ch) {
case CR:
break;
-@@ -569,10 +690,10 @@
+@@ -569,10 +691,10 @@
s->buffer->pos = p + 1;
s->arg_start = p + 1;
if (s->no_sync_literal == 0) {
@@ -575,7 +579,7 @@
s->no_sync_literal = 0;
break;
default:
-@@ -580,7 +701,7 @@
+@@ -580,7 +702,7 @@
}
break;
@@ -584,7 +588,7 @@
if (s->literal_len && --s->literal_len) {
break;
}
-@@ -592,36 +713,38 @@
+@@ -592,36 +714,38 @@
arg->len = p + 1 - s->arg_start;
arg->data = s->arg_start;
s->arg_start = NULL;
@@ -630,7 +634,7 @@
}
}
-@@ -633,13 +756,11 @@
+@@ -633,13 +757,11 @@
done:
s->buffer->pos = p + 1;
@@ -645,7 +649,7 @@
s->quoted = 0;
s->backslash = 0;
s->no_sync_literal = 0;
-@@ -649,7 +770,7 @@
+@@ -649,7 +771,7 @@
for ( /* void */ ; p < s->buffer->last; p++) {
if (*p == LF) {
@@ -654,7 +658,7 @@
s->buffer->pos = p + 1;
/* detect non-synchronizing literals */
-@@ -676,21 +797,500 @@
+@@ -676,21 +798,500 @@
}
@@ -1164,7 +1168,7 @@
for (p = s->buffer->pos; p < s->buffer->last; p++) {
ch = *p;
-@@ -698,13 +1298,13 @@
+@@ -698,13 +1299,13 @@
switch (state) {
/* SMTP command */
@@ -1181,7 +1185,7 @@
if (ch == ' ' || ch == CR || ch == LF) {
c = s->cmd_start;
-@@ -789,10 +1389,10 @@
+@@ -789,10 +1390,10 @@
switch (ch) {
case ' ':
@@ -1194,7 +1198,7 @@
break;
case LF:
goto done;
-@@ -806,21 +1406,21 @@
+@@ -806,21 +1407,21 @@
break;
@@ -1220,7 +1224,7 @@
s->arg_start = p;
break;
}
-@@ -828,7 +1428,7 @@
+@@ -828,7 +1429,7 @@
}
break;
@@ -1229,7 +1233,7 @@
switch (ch) {
case ' ':
case CR:
-@@ -843,10 +1443,10 @@
+@@ -843,10 +1444,10 @@
switch (ch) {
case ' ':
@@ -1242,7 +1246,7 @@
break;
case LF:
goto done;
-@@ -858,7 +1458,7 @@
+@@ -858,7 +1459,7 @@
}
break;
@@ -1251,7 +1255,7 @@
switch (ch) {
case LF:
goto done;
-@@ -876,19 +1476,19 @@
+@@ -876,19 +1477,19 @@
done:
s->buffer->pos = p + 1;
@@ -1274,7 +1278,7 @@
s->buffer->pos = p + 1;
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
-@@ -905,12 +1505,6 @@
+@@ -905,12 +1506,6 @@
{
ngx_str_t *arg;
@@ -1287,7 +1291,7 @@
if (s->args.nelts == 0) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
-@@ -925,7 +1519,7 @@
+@@ -925,7 +1520,7 @@
return NGX_MAIL_AUTH_LOGIN;
}
@@ -1296,7 +1300,7 @@
return NGX_MAIL_AUTH_LOGIN_USERNAME;
}
-@@ -938,14 +1532,28 @@
+@@ -938,14 +1533,28 @@
return NGX_MAIL_AUTH_PLAIN;
}
@@ -1327,7 +1331,7 @@
if (arg[0].len == 8) {
if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
-@@ -971,5 +1579,5 @@
+@@ -971,5 +1580,5 @@
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
From ed8ed0945f6af28cd9a1ae8d708d2c46a668379f Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Mon, 9 Oct 2023 19:12:10 +0530
Subject: [PATCH 10/14] ZCS-13998 : NGINX - Customization code separation from
repo
- Some review comments
---
.../nginx_src_mail_ngx_mail_parse.patch | 62 ++++++++++---------
1 file changed, 32 insertions(+), 30 deletions(-)
diff --git a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
index 5756360ac..b006cd76e 100644
--- a/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
+++ b/thirdparty/nginx/patches/nginx_src_mail_ngx_mail_parse.patch
@@ -1,5 +1,5 @@
--- nginx/src/mail/ngx_mail_parse.c 2023-10-03 16:49:31.548168900 +0530
-+++ nginx/src/mail/ngx_mail_parse.c 2023-10-09 13:58:27.495188500 +0530
++++ nginx/src/mail/ngx_mail_parse.c 2023-10-09 19:09:23.434448700 +0530
@@ -14,21 +14,104 @@
#include
@@ -296,7 +296,7 @@
goto invalid;
default:
if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')
-@@ -279,15 +358,15 @@
+@@ -279,35 +358,59 @@
}
if (p - s->tag_start > 31) {
goto invalid;
@@ -316,7 +316,9 @@
switch (ch) {
case ' ':
break;
-@@ -296,18 +375,41 @@
+ case CR:
+ case LF:
++ case '\x0':
goto invalid;
default:
s->cmd_start = p;
@@ -360,7 +362,7 @@
case 4:
if ((c[0] == 'N' || c[0] == 'n')
&& (c[1] == 'O'|| c[1] == 'o')
-@@ -315,7 +417,7 @@
+@@ -315,7 +418,7 @@
&& (c[3] == 'P'|| c[3] == 'p'))
{
s->command = NGX_IMAP_NOOP;
@@ -369,7 +371,7 @@
} else {
goto invalid;
}
-@@ -329,7 +431,7 @@
+@@ -329,7 +432,7 @@
&& (c[4] == 'N'|| c[4] == 'n'))
{
s->command = NGX_IMAP_LOGIN;
@@ -378,7 +380,7 @@
} else {
goto invalid;
}
-@@ -344,7 +446,7 @@
+@@ -344,7 +447,7 @@
&& (c[5] == 'T'|| c[5] == 't'))
{
s->command = NGX_IMAP_LOGOUT;
@@ -387,7 +389,7 @@
} else {
goto invalid;
}
-@@ -362,7 +464,7 @@
+@@ -362,7 +465,7 @@
&& (c[7] == 'S'|| c[7] == 's'))
{
s->command = NGX_IMAP_STARTTLS;
@@ -396,7 +398,7 @@
} else {
goto invalid;
}
-@@ -382,7 +484,7 @@
+@@ -382,7 +485,7 @@
&& (c[9] == 'Y'|| c[9] == 'y'))
{
s->command = NGX_IMAP_CAPABILITY;
@@ -405,7 +407,7 @@
} else {
goto invalid;
}
-@@ -402,7 +504,12 @@
+@@ -402,7 +505,12 @@
&& (c[10] == 'T'|| c[10] == 't')
&& (c[11] == 'E'|| c[11] == 'e'))
{
@@ -419,7 +421,7 @@
} else {
goto invalid;
-@@ -418,10 +525,13 @@
+@@ -418,10 +526,13 @@
switch (ch) {
case ' ':
@@ -435,7 +437,7 @@
break;
case LF:
goto done;
-@@ -435,40 +545,46 @@
+@@ -435,40 +546,46 @@
break;
@@ -491,7 +493,7 @@
if (ch == ' ' && s->quoted) {
break;
}
-@@ -510,10 +626,10 @@
+@@ -510,10 +627,10 @@
switch (ch) {
case '"':
case ' ':
@@ -504,7 +506,7 @@
break;
case LF:
goto done;
-@@ -522,46 +638,52 @@
+@@ -522,46 +639,52 @@
case '\\':
if (s->quoted) {
s->backslash = 1;
@@ -566,7 +568,7 @@
switch (ch) {
case CR:
break;
-@@ -569,10 +691,10 @@
+@@ -569,10 +692,10 @@
s->buffer->pos = p + 1;
s->arg_start = p + 1;
if (s->no_sync_literal == 0) {
@@ -579,7 +581,7 @@
s->no_sync_literal = 0;
break;
default:
-@@ -580,7 +702,7 @@
+@@ -580,7 +703,7 @@
}
break;
@@ -588,7 +590,7 @@
if (s->literal_len && --s->literal_len) {
break;
}
-@@ -592,36 +714,38 @@
+@@ -592,36 +715,38 @@
arg->len = p + 1 - s->arg_start;
arg->data = s->arg_start;
s->arg_start = NULL;
@@ -634,7 +636,7 @@
}
}
-@@ -633,13 +757,11 @@
+@@ -633,13 +758,11 @@
done:
s->buffer->pos = p + 1;
@@ -649,7 +651,7 @@
s->quoted = 0;
s->backslash = 0;
s->no_sync_literal = 0;
-@@ -649,7 +771,7 @@
+@@ -649,7 +772,7 @@
for ( /* void */ ; p < s->buffer->last; p++) {
if (*p == LF) {
@@ -658,7 +660,7 @@
s->buffer->pos = p + 1;
/* detect non-synchronizing literals */
-@@ -676,21 +798,500 @@
+@@ -676,21 +799,500 @@
}
@@ -1168,7 +1170,7 @@
for (p = s->buffer->pos; p < s->buffer->last; p++) {
ch = *p;
-@@ -698,13 +1299,13 @@
+@@ -698,13 +1300,13 @@
switch (state) {
/* SMTP command */
@@ -1185,7 +1187,7 @@
if (ch == ' ' || ch == CR || ch == LF) {
c = s->cmd_start;
-@@ -789,10 +1390,10 @@
+@@ -789,10 +1391,10 @@
switch (ch) {
case ' ':
@@ -1198,7 +1200,7 @@
break;
case LF:
goto done;
-@@ -806,21 +1407,21 @@
+@@ -806,21 +1408,21 @@
break;
@@ -1224,7 +1226,7 @@
s->arg_start = p;
break;
}
-@@ -828,7 +1429,7 @@
+@@ -828,7 +1430,7 @@
}
break;
@@ -1233,7 +1235,7 @@
switch (ch) {
case ' ':
case CR:
-@@ -843,10 +1444,10 @@
+@@ -843,10 +1445,10 @@
switch (ch) {
case ' ':
@@ -1246,7 +1248,7 @@
break;
case LF:
goto done;
-@@ -858,7 +1459,7 @@
+@@ -858,7 +1460,7 @@
}
break;
@@ -1255,7 +1257,7 @@
switch (ch) {
case LF:
goto done;
-@@ -876,19 +1477,19 @@
+@@ -876,19 +1478,19 @@
done:
s->buffer->pos = p + 1;
@@ -1278,7 +1280,7 @@
s->buffer->pos = p + 1;
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
-@@ -905,12 +1506,6 @@
+@@ -905,12 +1507,6 @@
{
ngx_str_t *arg;
@@ -1291,7 +1293,7 @@
if (s->args.nelts == 0) {
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
-@@ -925,7 +1520,7 @@
+@@ -925,7 +1521,7 @@
return NGX_MAIL_AUTH_LOGIN;
}
@@ -1300,7 +1302,7 @@
return NGX_MAIL_AUTH_LOGIN_USERNAME;
}
-@@ -938,14 +1533,28 @@
+@@ -938,14 +1534,28 @@
return NGX_MAIL_AUTH_PLAIN;
}
@@ -1331,7 +1333,7 @@
if (arg[0].len == 8) {
if (ngx_strncasecmp(arg[0].data, (u_char *) "CRAM-MD5", 8) == 0) {
-@@ -971,5 +1580,5 @@
+@@ -971,5 +1581,5 @@
return NGX_MAIL_PARSE_INVALID_COMMAND;
}
From 89f4a1bd3fec2b5537f7ce708bfef08dfbc44709 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Thu, 12 Oct 2023 01:06:59 +0530
Subject: [PATCH 11/14] ZCS-14068 : NGINX - Update review comments and
documentation
- Some review comments
---
thirdparty/nginx/patches/nginx_README.patch | 2 +-
thirdparty/nginx/patches/nginx_docs.patch | 30688 ++++++++++++++++
.../nginx/patches/nginx_src_event.patch | 13 +-
3 files changed, 30694 insertions(+), 9 deletions(-)
create mode 100644 thirdparty/nginx/patches/nginx_docs.patch
diff --git a/thirdparty/nginx/patches/nginx_README.patch b/thirdparty/nginx/patches/nginx_README.patch
index 38b24b509..7d4316861 100644
--- a/thirdparty/nginx/patches/nginx_README.patch
+++ b/thirdparty/nginx/patches/nginx_README.patch
@@ -5,7 +5,7 @@
+
+This is the official repository for building out the third party dependency nginx for Zimbra Collaboration Suite 8.7 and later.
+
-+Issues should be reported via [Zimbra's jira](https://synacor.atlassian.net/jira/your-work)
++Issues should be reported via [Zimbra Forum](https://forums.zimbra.org/)
+
+## Development branch
+zimbra/develop
diff --git a/thirdparty/nginx/patches/nginx_docs.patch b/thirdparty/nginx/patches/nginx_docs.patch
new file mode 100644
index 000000000..ee9362714
--- /dev/null
+++ b/thirdparty/nginx/patches/nginx_docs.patch
@@ -0,0 +1,30688 @@
+diff -urN nginx-1.24.0/docs/dtd/change_log_conf.dtd nginx/docs/dtd/change_log_conf.dtd
+--- nginx-1.24.0/docs/dtd/change_log_conf.dtd 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/dtd/change_log_conf.dtd 2023-03-04 13:25:23.458893200 +0530
+@@ -0,0 +1,22 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff -urN nginx-1.24.0/docs/dtd/changes.dtd nginx/docs/dtd/changes.dtd
+--- nginx-1.24.0/docs/dtd/changes.dtd 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/dtd/changes.dtd 2023-03-04 13:25:23.459891100 +0530
+@@ -0,0 +1,22 @@
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
+diff -urN nginx-1.24.0/docs/GNUmakefile nginx/docs/GNUmakefile
+--- nginx-1.24.0/docs/GNUmakefile 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/GNUmakefile 2023-03-04 13:25:23.457866400 +0530
+@@ -0,0 +1,41 @@
++
++VER= $(shell grep 'define NGINX_VERSION' src/core/nginx.h \
++ | sed -e 's/^.*"\(.*\)".*/\1/')
++NGINX= nginx-$(VER)
++TEMP= tmp
++XSLS?= xslscript.pl
++
++
++all: changes
++
++changes: $(TEMP)/$(NGINX)/CHANGES.ru \
++ $(TEMP)/$(NGINX)/CHANGES
++
++
++$(TEMP)/$(NGINX)/CHANGES.ru: docs/dtd/changes.dtd \
++ docs/xml/nginx/changes.xml \
++ docs/xml/change_log_conf.xml \
++ docs/xslt/changes.xslt
++
++ mkdir -p $(TEMP)/$(NGINX)
++
++ xmllint --noout --valid docs/xml/nginx/changes.xml
++ xsltproc --stringparam lang ru \
++ -o $@ docs/xslt/changes.xslt docs/xml/nginx/changes.xml
++
++
++$(TEMP)/$(NGINX)/CHANGES: docs/dtd/changes.dtd \
++ docs/xml/nginx/changes.xml \
++ docs/xml/change_log_conf.xml \
++ docs/xslt/changes.xslt
++
++ mkdir -p $(TEMP)/$(NGINX)
++
++ xmllint --noout --valid docs/xml/nginx/changes.xml
++ xsltproc --stringparam lang en \
++ -o $@ docs/xslt/changes.xslt docs/xml/nginx/changes.xml
++
++
++docs/xslt/changes.xslt: docs/xsls/changes.xsls
++
++ $(XSLS) -o $@ $<
+diff -urN nginx-1.24.0/docs/html/50x.html nginx/docs/html/50x.html
+--- nginx-1.24.0/docs/html/50x.html 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/html/50x.html 2023-09-14 18:47:11.586451000 +0530
+@@ -0,0 +1,19 @@
++
++
++
++Error
++
++
++
++An error occurred.
++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.
++Faithfully yours, nginx.
++
++
+diff -urN nginx-1.24.0/docs/html/index.html nginx/docs/html/index.html
+--- nginx-1.24.0/docs/html/index.html 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/html/index.html 2023-09-14 18:47:11.591663200 +0530
+@@ -0,0 +1,23 @@
++
++
++
++Welcome to nginx!
++
++
++
++Welcome to nginx!
++If you see this page, the nginx web server is successfully installed and
++working. Further configuration is required.
++
++For online documentation and support please refer to
++nginx.org.
++Commercial support is available at
++nginx.com.
++
++Thank you for using nginx.
++
++
+diff -urN nginx-1.24.0/docs/html/zmerror_upstream_502.html nginx/docs/html/zmerror_upstream_502.html
+--- nginx-1.24.0/docs/html/zmerror_upstream_502.html 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/html/zmerror_upstream_502.html 2023-03-04 13:25:59.800430200 +0530
+@@ -0,0 +1,29 @@
++
++
++
++Error 502 Connection to Upstream is Refused
++
++
++HTTP ERROR 502
++Problem accessing ZCS upstream server.
++ Cannot connect to the ZCS upstream server. Connection is refused.
++ Possible reasons:
++
++ - upstream server is unreachable
++ - upstream server is currently being upgraded
++ - upstream server is down
++
++ Please contact your ZCS administrator to fix the problem.
++
++Powered by Nginx-Zimbra://
++
++
++
++
++
++
++
++
++
++
++
+diff -urN nginx-1.24.0/docs/html/zmerror_upstream_504.html nginx/docs/html/zmerror_upstream_504.html
+--- nginx-1.24.0/docs/html/zmerror_upstream_504.html 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/html/zmerror_upstream_504.html 2023-03-04 13:25:59.801427300 +0530
+@@ -0,0 +1,30 @@
++
++
++
++Error 504 Connection to Upstream is Time Out
++
++
++HTTP ERROR 504
++Problem accessing ZCS upstream server. Reason:
++ Cannot connect to the ZCS upstream server. Connection timeout.
++ Possible reasons:
++
++ - upstream server is blocked by a firewall
++ - upstream server is failing to send back the response in time
++ - upstream server is down
++
++ Please contact your ZCS administrator to fix the problem.
++
++Powered by Nginx-Zimbra://
++
++
++
++
++
++
++
++
++
++
++
++
+diff -urN nginx-1.24.0/docs/man/nginx.8 nginx/docs/man/nginx.8
+--- nginx-1.24.0/docs/man/nginx.8 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/man/nginx.8 2023-03-04 13:25:23.463143700 +0530
+@@ -0,0 +1,214 @@
++.\"
++.\" Copyright (C) 2010, 2019 Sergey A. Osokin
++.\" Copyright (C) Nginx, Inc.
++.\" 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 AND CONTRIBUTORS ``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.
++.\"
++.\"
++.Dd November 5, 2020
++.Dt NGINX 8
++.Os
++.Sh NAME
++.Nm nginx
++.Nd "HTTP and reverse proxy server, mail proxy server"
++.Sh SYNOPSIS
++.Nm
++.Op Fl ?hqTtVv
++.Op Fl c Ar file
++.Op Fl e Ar file
++.Op Fl g Ar directives
++.Op Fl p Ar prefix
++.Op Fl s Ar signal
++.Sh DESCRIPTION
++.Nm
++(pronounced
++.Dq engine x )
++is an HTTP and reverse proxy server, a mail proxy server, and a generic
++TCP/UDP proxy server.
++It is known for its high performance, stability, rich feature set, simple
++configuration, and low resource consumption.
++.Pp
++The options are as follows:
++.Bl -tag -width ".Fl d Ar directives"
++.It Fl ?\& , h
++Print help.
++.It Fl c Ar file
++Use an alternative configuration
++.Ar file .
++.It Fl e Ar file
++Use an alternative error log
++.Ar file .
++Special value
++.Cm stderr
++indicates that the standard error output should be used.
++.It Fl g Ar directives
++Set global configuration directives.
++See
++.Sx EXAMPLES
++for details.
++.It Fl p Ar prefix
++Set the prefix path.
++The default value is
++.Pa %%PREFIX%% .
++.It Fl q
++Suppress non-error messages during configuration testing.
++.It Fl s Ar signal
++Send a signal to the master process.
++The argument
++.Ar signal
++can be one of:
++.Cm stop , quit , reopen , reload .
++The following table shows the corresponding system signals:
++.Pp
++.Bl -tag -width ".Cm reopen" -compact
++.It Cm stop
++.Dv SIGTERM
++.It Cm quit
++.Dv SIGQUIT
++.It Cm reopen
++.Dv SIGUSR1
++.It Cm reload
++.Dv SIGHUP
++.El
++.It Fl T
++Same as
++.Fl t ,
++but additionally dump configuration files to standard output.
++.It Fl t
++Do not run, just test the configuration file.
++.Nm
++checks the configuration file syntax and then tries to open files
++referenced in the configuration file.
++.It Fl V
++Print the
++.Nm
++version, compiler version, and
++.Pa configure
++script parameters.
++.It Fl v
++Print the
++.Nm
++version.
++.El
++.Sh SIGNALS
++The master process of
++.Nm
++can handle the following signals:
++.Pp
++.Bl -tag -width ".Dv SIGINT , SIGTERM" -compact
++.It Dv SIGINT , SIGTERM
++Shut down quickly.
++.It Dv SIGHUP
++Reload configuration, start the new worker process with a new
++configuration, and gracefully shut down old worker processes.
++.It Dv SIGQUIT
++Shut down gracefully.
++.It Dv SIGUSR1
++Reopen log files.
++.It Dv SIGUSR2
++Upgrade the
++.Nm
++executable on the fly.
++.It Dv SIGWINCH
++Shut down worker processes gracefully.
++.El
++.Pp
++While there is no need to explicitly control worker processes normally,
++they support some signals too:
++.Pp
++.Bl -tag -width ".Dv SIGINT , SIGTERM" -compact
++.It Dv SIGTERM
++Shut down quickly.
++.It Dv SIGQUIT
++Shut down gracefully.
++.It Dv SIGUSR1
++Reopen log files.
++.El
++.Sh DEBUGGING LOG
++To enable a debugging log, reconfigure
++.Nm
++to build with debugging:
++.Pp
++.Dl "./configure --with-debug ..."
++.Pp
++and then set the
++.Cm debug
++level of the
++.Va error_log :
++.Pp
++.Dl "error_log /path/to/log debug;"
++.Pp
++It is also possible to enable the debugging for a particular IP address:
++.Bd -literal -offset indent
++events {
++ debug_connection 127.0.0.1;
++}
++.Ed
++.Sh ENVIRONMENT
++The
++.Ev NGINX
++environment variable is used internally by
++.Nm
++and should not be set directly by the user.
++.Sh FILES
++.Bl -tag -width indent
++.It Pa %%PID_PATH%%
++Contains the process ID of
++.Nm .
++The contents of this file are not sensitive, so it can be world-readable.
++.It Pa %%CONF_PATH%%
++The main configuration file.
++.It Pa %%ERROR_LOG_PATH%%
++Error log file.
++.El
++.Sh EXIT STATUS
++Exit status is 0 on success, or 1 if the command fails.
++.Sh EXAMPLES
++Test configuration file
++.Pa ~/mynginx.conf
++with global directives for PID and quantity of worker processes:
++.Bd -literal -offset indent
++nginx -t -c ~/mynginx.conf \e
++ -g "pid /var/run/mynginx.pid; worker_processes 2;"
++.Ed
++.Sh SEE ALSO
++.\"Xr nginx.conf 5
++.\"Pp
++Documentation at
++.Pa http://nginx.org/en/docs/ .
++.Pp
++For questions and technical support, please refer to
++.Pa http://nginx.org/en/support.html .
++.Sh HISTORY
++Development of
++.Nm
++started in 2002, with the first public release on October 4, 2004.
++.Sh AUTHORS
++.An -nosplit
++.An Igor Sysoev Aq Mt igor@sysoev.ru .
++.Pp
++This manual page was originally written by
++.An Sergey A. Osokin Aq Mt osa@FreeBSD.org.ru
++as a result of compiling many
++.Nm
++documents from all over the world.
+diff -urN nginx-1.24.0/docs/text/LICENSE nginx/docs/text/LICENSE
+--- nginx-1.24.0/docs/text/LICENSE 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/text/LICENSE 2023-09-14 18:47:11.595428500 +0530
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2002-2021 Igor Sysoev
++ * Copyright (C) 2011-2022 Nginx, Inc.
++ * 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 AND CONTRIBUTORS ``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.
++ */
+diff -urN nginx-1.24.0/docs/text/README nginx/docs/text/README
+--- nginx-1.24.0/docs/text/README 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/text/README 2023-03-04 13:25:23.466101800 +0530
+@@ -0,0 +1,3 @@
++
++Documentation is available at http://nginx.org
++
+diff -urN nginx-1.24.0/docs/xml/change_log_conf.xml nginx/docs/xml/change_log_conf.xml
+--- nginx-1.24.0/docs/xml/change_log_conf.xml 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/xml/change_log_conf.xml 2023-03-04 13:25:23.467099100 +0530
+@@ -0,0 +1,47 @@
++
++
++
++
++
++76
++
++ *)
++
++
++
++ Изменения в
++ 66
++
++ Исправление
++ Добавление
++ Изменение
++ Безопасность
++ Изменение
++
++
++
++ Changes with
++ 65
++
++ Bugfix
++ Feature
++ Change
++ Security
++ Workaround
++
++ Jan
++ Feb
++ Mar
++ Apr
++ May
++ Jun
++ Jul
++ Aug
++ Sep
++ Oct
++ Nov
++ Dec
++
++
++
++
+diff -urN nginx-1.24.0/docs/xml/nginx/changes.xml nginx/docs/xml/nginx/changes.xml
+--- nginx-1.24.0/docs/xml/nginx/changes.xml 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/xml/nginx/changes.xml 2023-09-14 18:47:11.612380300 +0530
+@@ -0,0 +1,29894 @@
++
++
++
++
++
++
++
++
++
++
++
++Стабильная ветка 1.24.x.
++
++
++1.24.x stable branch.
++
++
++
++
++
++
++
++
++
++
++теперь протокол TLSv1.3 разрешён по умолчанию.
++
++
++now TLSv1.3 protocol is enabled by default.
++
++
++
++
++
++теперь nginx выдаёт предупреждение
++при переопределении параметров listen-сокета, задающих используемые протоколы.
++
++
++now nginx issues a warning
++if protocol parameters of a listening socket are redefined.
++
++
++
++
++
++теперь, если клиент использует pipelining,
++nginx закрывает соединения с ожиданием дополнительных данных (lingering close).
++
++
++now nginx closes connections with lingering
++if pipelining was used by the client.
++
++
++
++
++
++поддержка byte ranges для ответов модуля ngx_http_gzip_static_module.
++
++
++byte ranges support in the ngx_http_gzip_static_module.
++
++
++
++
++
++диапазоны портов в директиве listen не работали;
++ошибка появилась в 1.23.3.
++Спасибо Валентину Бартеневу.
++
++
++port ranges in the "listen" directive did not work;
++the bug had appeared in 1.23.3.
++Thanks to Valentin Bartenev.
++
++
++
++
++
++для обработки запроса мог быть выбран неверный location,
++если в конфигурации использовался
++префиксный location длиннее 255 символов.
++
++
++incorrect location might be chosen to process a request
++if a prefix location longer than 255 characters
++was used in the configuration.
++
++
++
++
++
++не-ASCII символы в именах файлов на Windows
++не поддерживались модулями ngx_http_autoindex_module и
++ngx_http_dav_module, а также директивой include.
++
++
++non-ASCII characters in file names on Windows were not supported
++by the ngx_http_autoindex_module, the ngx_http_dav_module,
++and the "include" directive.
++
++
++
++
++
++уровень логгирования ошибок SSL
++"data length too long", "length too short", "bad legacy version",
++"no shared signature algorithms", "bad digest length",
++"missing sigalgs extension", "encrypted length too long",
++"bad length", "bad key update", "mixed handshake and non handshake data",
++"ccs received early", "data between ccs and finished",
++"packet length too long", "too many warn alerts", "record too small",
++и "got a fin before a ccs"
++понижен с уровня crit до info.
++
++
++the logging level of the
++"data length too long", "length too short", "bad legacy version",
++"no shared signature algorithms", "bad digest length",
++"missing sigalgs extension", "encrypted length too long",
++"bad length", "bad key update", "mixed handshake and non handshake data",
++"ccs received early", "data between ccs and finished",
++"packet length too long", "too many warn alerts", "record too small",
++and "got a fin before a ccs" SSL errors
++has been lowered from "crit" to "info".
++
++
++
++
++
++при использовании HTTP/2 и директивы error_page
++для перенаправления ошибок с кодом 400
++могла происходить утечка сокетов.
++
++
++a socket leak might occur
++when using HTTP/2 and the "error_page" directive
++to redirect errors with code 400.
++
++
++
++
++
++сообщения об ошибках записи в syslog
++не содержали информации о том, что
++ошибки происходили в процессе записи в syslog.
++Спасибо Safar Safarly.
++
++
++messages about logging to syslog errors
++did not contain information
++that the errors happened while logging to syslog.
++Thanks to Safar Safarly.
++
++
++
++
++
++при использовании zlib-ng
++в логах появлялись сообщения "gzip filter failed to use preallocated memory".
++
++
++"gzip filter failed to use preallocated memory" alerts appeared in logs
++when using zlib-ng.
++
++
++
++
++
++в почтовом прокси-сервере.
++
++
++in the mail proxy server.
++
++
++
++
++
++
++
++
++
++
++при чтении заголовка протокола PROXY версии 2, содержащего
++большое количество TLV, могла возникать ошибка.
++
++
++an error might occur when reading PROXY protocol version 2 header
++with large number of TLVs.
++
++
++
++
++
++при использовании SSI для обработки подзапросов, созданных другими модулями,
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Ciel Zhao.
++
++
++a segmentation fault might occur in a worker process
++if SSI was used to process subrequests created by other modules.
++Thanks to Ciel Zhao.
++
++
++
++
++
++теперь, если при преобразовании в адреса имени хоста,
++указанного в директиве listen, возвращается несколько адресов,
++nginx игнорирует дубликаты среди этих адресов.
++
++
++when a hostname used in the "listen" directive
++resolves to multiple addresses,
++nginx now ignores duplicates within these addresses.
++
++
++
++
++
++nginx мог нагружать процессор
++при небуферизированном проксировании,
++если использовались SSL-соединения с бэкендами.
++
++
++nginx might hog CPU
++during unbuffered proxying
++if SSL connections to backends were used.
++
++
++
++
++
++
++
++
++
++
++обработка специально созданного mp4-файла модулем ngx_http_mp4_module
++могла приводить к падению рабочего процесса,
++отправке клиенту части содержимого памяти рабочего процесса,
++а также потенциально могла иметь другие последствия
++(CVE-2022-41741, CVE-2022-41742).
++
++
++processing of a specially crafted mp4 file by the ngx_http_mp4_module
++might cause a worker process crash,
++worker process memory disclosure,
++or might have potential other impact
++(CVE-2022-41741, CVE-2022-41742).
++
++
++
++
++
++переменные "$proxy_protocol_tlv_...".
++
++
++the "$proxy_protocol_tlv_..." variables.
++
++
++
++
++
++ключи шифрования TLS session tickets теперь автоматически меняются
++при использовании разделяемой памяти в ssl_session_cache.
++
++
++TLS session tickets encryption keys are now automatically rotated
++when using shared memory in the "ssl_session_cache" directive.
++
++
++
++
++
++уровень логгирования ошибок SSL "bad record type"
++понижен с уровня crit до info.
++Спасибо Murilo Andrade.
++
++
++the logging level of the "bad record type" SSL errors
++has been lowered from "crit" to "info".
++Thanks to Murilo Andrade.
++
++
++
++
++
++теперь при использовании разделяемой памяти в ssl_session_cache
++сообщения "could not allocate new session"
++логгируются на уровне warn вместо alert
++и не чаще одного раза в секунду.
++
++
++now when using shared memory in the "ssl_session_cache" directive
++the "could not allocate new session" errors
++are logged at the "warn" level instead of "alert"
++and not more often than once per second.
++
++
++
++
++
++nginx/Windows не собирался с OpenSSL 3.0.x.
++
++
++nginx/Windows could not be built with OpenSSL 3.0.x.
++
++
++
++
++
++в логгировании ошибок протокола PROXY.
++Спасибо Сергею Брестеру.
++
++
++in logging of the PROXY protocol errors.
++Thanks to Sergey Brester.
++
++
++
++
++
++при использовании TLSv1.3 с OpenSSL
++разделяемая память из ssl_session_cache расходовалась
++в том числе на сессии, использующие TLS session tickets.
++
++
++shared memory from the "ssl_session_cache" directive
++was spent on sessions using TLS session tickets
++when using TLSv1.3 with OpenSSL.
++
++
++
++
++
++таймаут, заданный с помощью директивы ssl_session_timeout,
++не работал при использовании TLSv1.3 с OpenSSL или BoringSSL.
++
++
++timeout specified with the "ssl_session_timeout" directive
++did not work when using TLSv1.3 with OpenSSL or BoringSSL.
++
++
++
++
++
++
++
++
++
++
++оптимизация использования памяти
++в конфигурациях с SSL-проксированием.
++
++
++memory usage optimization
++in configurations with SSL proxying.
++
++
++
++
++
++теперь с помощью параметра "ipv4=off" директивы "resolver"
++можно запретить поиск IPv4-адресов при преобразовании имён в адреса.
++
++
++looking up of IPv4 addresses while resolving now can be disabled
++with the "ipv4=off" parameter of the "resolver" directive.
++
++
++
++
++
++уровень логгирования ошибок SSL "bad key share", "bad extension",
++"bad cipher" и "bad ecpoint"
++понижен с уровня crit до info.
++
++
++the logging level of the "bad key share", "bad extension",
++"bad cipher", and "bad ecpoint" SSL errors
++has been lowered from "crit" to "info".
++
++
++
++
++
++при возврате диапазонов
++nginx не удалял строку заголовка "Content-Range",
++если она присутствовала в исходном ответе бэкенда.
++
++
++while returning byte ranges
++nginx did not remove the "Content-Range" header line
++if it was present in the original backend response.
++
++
++
++
++
++проксированный ответ мог быть отправлен не полностью
++при переконфигурации на Linux;
++ошибка появилась в 1.17.5.
++
++
++a proxied response might be truncated
++during reconfiguration on Linux;
++the bug had appeared in 1.17.5.
++
++
++
++
++
++
++
++
++
++
++Изменение во внутреннем API:
++теперь строки заголовков представлены связными списками.
++
++
++Change in internal API:
++now header lines are represented as linked lists.
++
++
++
++
++
++теперь nginx объединяет произвольные строки заголовков с одинаковыми именами
++при отправке на FastCGI-, SCGI- и uwsgi-бэкенды,
++в методе $r->header_in() модуля ngx_http_perl_module,
++и при доступе через переменные "$http_...", "$sent_http_...",
++"$sent_trailer_...", "$upstream_http_..." и "$upstream_trailer_...".
++
++
++now nginx combines arbitrary header lines with identical names
++when sending to FastCGI, SCGI, and uwsgi backends,
++in the $r->header_in() method of the ngx_http_perl_module,
++and during lookup of the "$http_...", "$sent_http_...",
++"$sent_trailer_...", "$upstream_http_...", and "$upstream_trailer_..."
++variables.
++
++
++
++
++
++если в заголовке ответа бэкенда было несколько строк "Vary",
++при кэшировании nginx учитывал только последнюю из них.
++
++
++if there were multiple "Vary" header lines in the backend response,
++nginx only used the last of them when caching.
++
++
++
++
++
++если в заголовке ответа бэкенда было несколько строк "WWW-Authenticate"
++и использовался перехват ошибок с кодом 401 от бэкенда
++или директива auth_request,
++nginx пересылал клиенту только первую из этих строк.
++
++
++if there were multiple "WWW-Authenticate" header lines in the backend response
++and errors with code 401 were intercepted
++or the "auth_request" directive was used,
++nginx only sent the first of the header lines to the client.
++
++
++
++
++
++уровень логгирования ошибок SSL "application data after close notify"
++понижен с уровня crit до info.
++
++
++the logging level of the "application data after close notify" SSL errors
++has been lowered from "crit" to "info".
++
++
++
++
++
++соединения могли зависать, если nginx был собран на Linux 2.6.17 и новее,
++а использовался на системах без поддержки EPOLLRDHUP, в частности, на
++системах с эмуляцией epoll;
++ошибка появилась в 1.17.5.
++Спасибо Marcus Ball.
++
++
++connections might hang if nginx was built on Linux 2.6.17 or newer,
++but was used on systems without EPOLLRDHUP support, notably with epoll
++emulation layers;
++the bug had appeared in 1.17.5.
++Thanks to Marcus Ball.
++
++
++
++
++
++nginx не кэшировал ответ,
++если строка заголовка ответа "Expires" запрещала кэширование,
++а последующая строка заголовка "Cache-Control" разрешала кэширование.
++
++
++nginx did not cache the response
++if the "Expires" response header line disabled caching,
++but following "Cache-Control" header line enabled caching.
++
++
++
++
++
++
++
++
++
++
++при использование EPOLLEXCLUSIVE на Linux
++распределение клиентских соединений между рабочими процессами
++было неравномерным.
++
++
++when using EPOLLEXCLUSIVE on Linux
++client connections were unevenly distributed
++among worker processes.
++
++
++
++
++
++во время плавного завершения старых рабочих процессов
++nginx возвращал в ответах строку заголовка "Connection: keep-alive".
++
++
++nginx returned the "Connection: keep-alive" header line in responses
++during graceful shutdown of old worker processes.
++
++
++
++
++
++в директиве ssl_session_ticket_key при использовании TLSv1.3.
++
++
++in the "ssl_session_ticket_key" when using TLSv1.3.
++
++
++
++
++
++
++
++
++
++
++теперь nginx по умолчанию собирается с библиотекой PCRE2.
++
++
++now nginx is built with the PCRE2 library by default.
++
++
++
++
++
++теперь nginx всегда использует sendfile(SF_NODISKIO) на FreeBSD.
++
++
++now nginx always uses sendfile(SF_NODISKIO) on FreeBSD.
++
++
++
++
++
++поддержка sendfile(SF_NOCACHE) на FreeBSD.
++
++
++support for sendfile(SF_NOCACHE) on FreeBSD.
++
++
++
++
++
++переменная $ssl_curve.
++
++
++the $ssl_curve variable.
++
++
++
++
++
++при использовании HTTP/2 без SSL вместе с директивами sendfile и aio
++соединения могли зависать.
++
++
++connections might hang
++when using HTTP/2 without SSL with the "sendfile" and "aio" directives.
++
++
++
++
++
++
++
++
++
++
++поддержка NPN вместо ALPN для установления HTTP/2-соединений
++упразднена.
++
++
++support for NPN instead of ALPN to establish HTTP/2 connections
++has been removed.
++
++
++
++
++
++теперь nginx закрывает SSL соединение, если клиент использует ALPN,
++но nginx не поддерживает ни один из присланных клиентом протоколов.
++
++
++now nginx rejects SSL connections if ALPN is used by the client,
++but no supported protocols can be negotiated.
++
++
++
++
++
++в директиве sendfile_max_chunk значение по умолчанию
++изменено на 2 мегабайта.
++
++
++the default value of the "sendfile_max_chunk" directive
++was changed to 2 megabytes.
++
++
++
++
++
++директива proxy_half_close в модуле stream.
++
++
++the "proxy_half_close" directive in the stream module.
++
++
++
++
++
++директива ssl_alpn в модуле stream.
++
++
++the "ssl_alpn" directive in the stream module.
++
++
++
++
++
++переменная $ssl_alpn_protocol.
++
++
++the $ssl_alpn_protocol variable.
++
++
++
++
++
++поддержка SSL_sendfile() при использовании OpenSSL 3.0.
++
++
++support for SSL_sendfile() when using OpenSSL 3.0.
++
++
++
++
++
++директива mp4_start_key_frame в модуле ngx_http_mp4_module.
++Спасибо Tracey Jaquith.
++
++
++the "mp4_start_key_frame" directive in the ngx_http_mp4_module.
++Thanks to Tracey Jaquith.
++
++
++
++
++
++в переменной $content_length при использовании chunked transfer encoding.
++
++
++in the $content_length variable when using chunked transfer encoding.
++
++
++
++
++
++при получении ответа некорректной длины от проксируемого бэкенда
++nginx мог тем не менее закэшировать соединение.
++Спасибо Awdhesh Mathpal.
++
++
++after receiving a response with incorrect length from a proxied backend
++nginx might nevertheless cache the connection.
++Thanks to Awdhesh Mathpal.
++
++
++
++
++
++некорректные заголовки от бэкендов
++логгировались на уровне info вместо error;
++ошибка появилась в 1.21.1.
++
++
++invalid headers from backends
++were logged at the "info" level instead of "error";
++the bug had appeared in 1.21.1.
++
++
++
++
++
++при использовании HTTP/2 и директивы aio_write
++запросы могли зависать.
++
++
++requests might hang
++when using HTTP/2 and the "aio_write" directive.
++
++
++
++
++
++
++
++
++
++
++оптимизация чтения тела запроса
++при использовании HTTP/2.
++
++
++optimization of client request body reading
++when using HTTP/2.
++
++
++
++
++
++во внутреннем API для обработки тела запроса
++при использовании HTTP/2 и буферизации обрабатываемых данных.
++
++
++in request body filters internal API
++when using HTTP/2 and buffering of the data being processed.
++
++
++
++
++
++
++
++
++
++
++теперь nginx возвращает ошибку,
++если в запросе по протоколу HTTP/1.0 присутствует
++строка заголовка "Transfer-Encoding".
++
++
++now nginx rejects HTTP/1.0 requests
++with the "Transfer-Encoding" header line.
++
++
++
++
++
++экспортные шифры больше не поддерживаются.
++
++
++export ciphers are no longer supported.
++
++
++
++
++
++совместимость с OpenSSL 3.0.
++
++
++OpenSSL 3.0 compatibility.
++
++
++
++
++
++теперь серверу аутентификации почтового прокси-сервера
++передаются строки заголовка "Auth-SSL-Protocol" и "Auth-SSL-Cipher".
++Спасибо Rob Mueller.
++
++
++the "Auth-SSL-Protocol" and "Auth-SSL-Cipher" header lines
++are now passed to the mail proxy authentication server.
++Thanks to Rob Mueller.
++
++
++
++
++
++API для обработки тела запроса
++теперь позволяет буферизировать обрабатываемые данные.
++
++
++request body filters API
++now permits buffering of the data being processed.
++
++
++
++
++
++SSL-соединения к бэкендам в модуле stream
++могли зависать после SSL handshake.
++
++
++backend SSL connections in the stream module
++might hang after an SSL handshake.
++
++
++
++
++
++уровень безопасности, доступный в OpenSSL 1.1.0 и новее,
++не учитывался при загрузке сертификатов сервера,
++если был задан через "@SECLEVEL=N" в директиве ssl_ciphers.
++
++
++the security level, which is available in OpenSSL 1.1.0 or newer,
++did not affect loading of the server certificates
++when set with "@SECLEVEL=N" in the "ssl_ciphers" directive.
++
++
++
++
++
++SSL-соединения с gRPC-бэкендами могли зависать,
++если использовались методы select, poll или /dev/poll.
++
++
++SSL connections with gRPC backends might hang
++if select, poll, or /dev/poll methods were used.
++
++
++
++
++
++при использовании HTTP/2
++тело запроса всегда записывалось на диск,
++если в запросе не было строки заголовка "Content-Length".
++
++
++when using HTTP/2
++client request body was always written to disk
++if the "Content-Length" header line was not present in the request.
++
++
++
++
++
++
++
++
++
++
++теперь nginx для метода CONNECT всегда возвращает ошибку.
++
++
++now nginx always returns an error for the CONNECT method.
++
++
++
++
++
++теперь nginx всегда возвращает ошибку,
++если в запросе одновременно присутствуют строки заголовка "Content-Length"
++и "Transfer-Encoding".
++
++
++now nginx always returns an error
++if both "Content-Length" and "Transfer-Encoding" header lines
++are present in the request.
++
++
++
++
++
++теперь nginx всегда возвращает ошибку,
++если в строке запроса используются пробелы или управляющие символы.
++
++
++now nginx always returns an error
++if spaces or control characters are used in the request line.
++
++
++
++
++
++теперь nginx всегда возвращает ошибку,
++если в имени заголовка используются пробелы или управляющие символы.
++
++
++now nginx always returns an error
++if spaces or control characters are used in a header name.
++
++
++
++
++
++теперь nginx всегда возвращает ошибку,
++если в строке "Host" заголовка запроса
++используются пробелы или управляющие символы.
++
++
++now nginx always returns an error
++if spaces or control characters
++are used in the "Host" request header line.
++
++
++
++
++
++оптимизация тестирования конфигурации
++при использовании большого количества listen-сокетов.
++
++
++optimization of configuration testing
++when using many listening sockets.
++
++
++
++
++
++nginx не экранировал
++символы """, "<", ">", "\", "^", "`", "{", "|", и "}"
++при проксировании с изменением URI запроса.
++
++
++nginx did not escape
++""", "<", ">", "\", "^", "`", "{", "|", and "}" characters
++when proxying with changed URI.
++
++
++
++
++
++SSL-переменные могли быть пустыми при записи в лог;
++ошибка появилась в 1.19.5.
++
++
++SSL variables might be empty when used in logs;
++the bug had appeared in 1.19.5.
++
++
++
++
++
++keepalive-соединения с gRPC-бэкендами могли не закрываться
++после получения GOAWAY-фрейма.
++
++
++keepalive connections with gRPC backends might not be closed
++after receiving a GOAWAY frame.
++
++
++
++
++
++уменьшено потребление памяти для долгоживущих запросов
++при проксировании с использованием более 64 буферов.
++
++
++reduced memory consumption for long-lived requests
++when proxying with more than 64 buffers.
++
++
++
++
++
++
++
++
++
++
++при использовании директивы resolver
++во время обработки ответа DNS-сервера
++могла происходить перезапись одного байта памяти,
++что позволяло атакующему,
++имеющему возможность подделывать UDP-пакеты от DNS-сервера,
++вызвать падение рабочего процесса
++или, потенциально, выполнение произвольного кода (CVE-2021-23017).
++
++
++1-byte memory overwrite might occur
++during DNS server response processing
++if the "resolver" directive was used,
++allowing an attacker
++who is able to forge UDP packets from the DNS server
++to cause worker process crash
++or, potentially, arbitrary code execution (CVE-2021-23017).
++
++
++
++
++
++директивы proxy_ssl_certificate, proxy_ssl_certificate_key,
++grpc_ssl_certificate, grpc_ssl_certificate_key,
++uwsgi_ssl_certificate и uwsgi_ssl_certificate_key
++поддерживают переменные.
++
++
++variables support
++in the "proxy_ssl_certificate", "proxy_ssl_certificate_key"
++"grpc_ssl_certificate", "grpc_ssl_certificate_key",
++"uwsgi_ssl_certificate", and "uwsgi_ssl_certificate_key" directives.
++
++
++
++
++
++директива max_errors в почтовом прокси-сервере.
++
++
++the "max_errors" directive in the mail proxy module.
++
++
++
++
++
++почтовый прокси-сервер поддерживает POP3 и IMAP pipelining.
++
++
++the mail proxy module supports POP3 and IMAP pipelining.
++
++
++
++
++
++параметр fastopen директивы listen в модуле stream.
++Спасибо Anbang Wen.
++
++
++the "fastopen" parameter of the "listen" directive in the stream module.
++Thanks to Anbang Wen.
++
++
++
++
++
++специальные символы не экранировались
++при автоматическом перенаправлении с добавлением завершающего слэша.
++
++
++special characters were not escaped
++during automatic redirect with appended trailing slash.
++
++
++
++
++
++при использовании SMTP pipelining
++соединения с клиентами в почтовом прокси-сервере
++могли неожиданно закрываться.
++
++
++connections with clients in the mail proxy module
++might be closed unexpectedly
++when using SMTP pipelining.
++
++
++
++
++
++
++
++
++
++
++в директиве keepalive_requests значение по умолчанию изменено на 1000.
++
++
++the default value of the "keepalive_requests" directive was changed to 1000.
++
++
++
++
++
++директива keepalive_time.
++
++
++the "keepalive_time" directive.
++
++
++
++
++
++переменная $connection_time.
++
++
++the $connection_time variable.
++
++
++
++
++
++при использовании zlib-ng
++в логах появлялись сообщения "gzip filter failed to use preallocated memory".
++
++
++"gzip filter failed to use preallocated memory" alerts appeared in logs
++when using zlib-ng.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с почтовым прокси-сервером,
++но без модуля ngx_mail_ssl_module;
++ошибка появилась в 1.19.8.
++
++
++nginx could not be built with the mail proxy module,
++but without the ngx_mail_ssl_module;
++the bug had appeared in 1.19.8.
++
++
++
++
++
++при работе с gRPC-бэкендами могли возникать ошибки
++"upstream sent response body larger than indicated content length";
++ошибка появилась в 1.19.1.
++
++
++"upstream sent response body larger than indicated content length"
++errors might occur when working with gRPC backends;
++the bug had appeared in 1.19.1.
++
++
++
++
++
++если клиент закрывал соединение в момент отбрасывания тела запроса,
++nginx мог не закрыть соединение до истечения keepalive-таймаута.
++
++
++nginx might not close a connection till keepalive timeout expiration
++if the connection was closed by the client while discarding the request body.
++
++
++
++
++
++при ожидании задержки limit_req или auth_delay, а также при работе с бэкендами
++nginx мог не обнаружить, что соединение уже закрыто клиентом.
++
++
++nginx might not detect that a connection was already closed by the client
++when waiting for auth_delay or limit_req delay, or when working with backends.
++
++
++
++
++
++в методе обработки соединений eventport.
++
++
++in the eventport method.
++
++
++
++
++
++
++
++
++
++
++в директиве proxy_cookie_flags теперь
++флаги можно задавать с помощью переменных.
++
++
++flags in the "proxy_cookie_flags" directive
++can now contain variables.
++
++
++
++
++
++параметр proxy_protocol в директиве listen,
++директивы proxy_protocol и set_real_ip_from
++в почтовом прокси-сервере.
++
++
++the "proxy_protocol" parameter of the "listen" directive,
++the "proxy_protocol" and "set_real_ip_from" directives
++in mail proxy.
++
++
++
++
++
++HTTP/2-соединения сразу закрывались
++при использовании "keepalive_timeout 0";
++ошибка появилась в 1.19.7.
++
++
++HTTP/2 connections were immediately closed
++when using "keepalive_timeout 0";
++the bug had appeared in 1.19.7.
++
++
++
++
++
++некоторые ошибки логгировались как неизвестные,
++если nginx был собран с glibc 2.32.
++
++
++some errors were logged as unknown
++if nginx was built with glibc 2.32.
++
++
++
++
++
++в методе обработки соединений eventport.
++
++
++in the eventport method.
++
++
++
++
++
++
++
++
++
++
++обработка соединений в HTTP/2 была изменена
++и теперь более соответствует HTTP/1.x;
++директивы http2_recv_timeout, http2_idle_timeout
++и http2_max_requests упразднены,
++вместо них следует использовать директивы
++keepalive_timeout и keepalive_requests.
++
++
++connections handling in HTTP/2 has been changed
++to better match HTTP/1.x;
++the "http2_recv_timeout", "http2_idle_timeout",
++and "http2_max_requests" directives have been removed,
++the "keepalive_timeout" and "keepalive_requests" directives
++should be used instead.
++
++
++
++
++
++директивы http2_max_field_size и http2_max_header_size упразднены,
++вместо них следует использовать директиву large_client_header_buffers.
++
++
++the "http2_max_field_size" and "http2_max_header_size" directives
++have been removed,
++the "large_client_header_buffers" directive should be used instead.
++
++
++
++
++
++теперь при исчерпании свободных соединений
++nginx закрывает не только keepalive-соединения,
++но и соединения в lingering close.
++
++
++now, if free worker connections are exhausted,
++nginx starts closing not only keepalive connections,
++but also connections in lingering close.
++
++
++
++
++
++в логах могли появляться сообщения "zero size buf in output",
++если бэкенд возвращал некорректный ответ
++при небуферизированном проксировании;
++ошибка появилась в 1.19.1.
++
++
++"zero size buf in output" alerts might appear in logs
++if an upstream server returned an incorrect response
++during unbuffered proxying;
++the bug had appeared in 1.19.1.
++
++
++
++
++
++при использовании директивы return
++вместе с image_filter или xslt_stylesheet
++HEAD-запросы обрабатывались некорректно.
++
++
++HEAD requests were handled incorrectly
++if the "return" directive was used
++with the "image_filter" or "xslt_stylesheet" directives.
++
++
++
++
++
++в директиве add_trailer.
++
++
++in the "add_trailer" directive.
++
++
++
++
++
++
++
++
++
++
++ошибки "no live upstreams",
++если server в блоке upstream был помечен как down.
++
++
++"no live upstreams" errors
++if a "server" inside "upstream" block was marked as "down".
++
++
++
++
++
++при использовании HTTPS в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.19.5.
++
++
++a segmentation fault might occur in a worker process if HTTPS was used;
++the bug had appeared in 1.19.5.
++
++
++
++
++
++nginx возвращал ошибку 400 на запросы вида
++"GET http://example.com?args HTTP/1.0".
++
++
++nginx returned the 400 response on requests like
++"GET http://example.com?args HTTP/1.0".
++
++
++
++
++
++в модулях ngx_http_flv_module и ngx_http_mp4_module.
++Спасибо Chris Newton.
++
++
++in the ngx_http_flv_module and ngx_http_mp4_module.
++Thanks to Chris Newton.
++
++
++
++
++
++
++
++
++
++
++ключ -e.
++
++
++the -e switch.
++
++
++
++
++
++при сборке дополнительных модулей
++теперь можно указывать одни и те же исходные файлы в разных модулях.
++
++
++the same source files can now be specified in different modules
++while building addon modules.
++
++
++
++
++
++SSL shutdown не работал
++при закрытии соединений с ожиданием дополнительных данных (lingering close).
++
++
++SSL shutdown did not work
++when lingering close was used.
++
++
++
++
++
++при работе с gRPC-бэкендами
++могли возникать ошибки "upstream sent frame for closed stream".
++
++
++"upstream sent frame for closed stream" errors might occur
++when working with gRPC backends.
++
++
++
++
++
++во внутреннем API для обработки тела запроса.
++
++
++in request body filters internal API.
++
++
++
++
++
++
++
++
++
++
++директивы ssl_conf_command, proxy_ssl_conf_command, grpc_ssl_conf_command
++и uwsgi_ssl_conf_command.
++
++
++the "ssl_conf_command", "proxy_ssl_conf_command", "grpc_ssl_conf_command",
++and "uwsgi_ssl_conf_command" directives.
++
++
++
++
++
++директива ssl_reject_handshake.
++
++
++the "ssl_reject_handshake" directive.
++
++
++
++
++
++директива proxy_smtp_auth в почтовом прокси-сервере.
++
++
++the "proxy_smtp_auth" directive in mail proxy.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_stream_set_module.
++
++
++the ngx_stream_set_module.
++
++
++
++
++
++директива proxy_cookie_flags.
++
++
++the "proxy_cookie_flags" directive.
++
++
++
++
++
++директива userid_flags.
++
++
++the "userid_flags" directive.
++
++
++
++
++
++расширение управления кэшированием stale-if-error
++ошибочно применялось, если бэкенд возвращал ответ
++с кодом 500, 502, 503, 504, 403, 404 или 429.
++
++
++the "stale-if-error" cache control extension
++was erroneously applied if backend returned a response
++with status code 500, 502, 503, 504, 403, 404, or 429.
++
++
++
++
++
++если использовалось кэширование
++и бэкенд возвращал ответы с строкой заголовка Vary,
++в логах могли появляться сообщения "[crit] cache file ... has too long header".
++
++
++"[crit] cache file ... has too long header" messages might appear in logs
++if caching was used
++and the backend returned responses with the "Vary" header line.
++
++
++
++
++
++при использовании OpenSSL 1.1.1
++в логах могли появляться сообщения "[crit] SSL_write() failed".
++
++
++"[crit] SSL_write() failed" messages might appear in logs
++when using OpenSSL 1.1.1.
++
++
++
++
++
++в логах могли появляться сообщения
++"SSL_shutdown() failed (SSL: ... bad write retry)";
++ошибка появилась в 1.19.2.
++
++
++"SSL_shutdown() failed (SSL: ... bad write retry)"
++messages might appear in logs;
++the bug had appeared in 1.19.2.
++
++
++
++
++
++при использовании HTTP/2
++в рабочем процессе мог произойти segmentation fault,
++если ошибки с кодом 400 с помощью директивы error_page
++перенаправлялись в проксируемый location.
++
++
++a segmentation fault might occur in a worker process
++when using HTTP/2
++if errors with code 400 were redirected to a proxied location
++using the "error_page" directive.
++
++
++
++
++
++утечки сокетов при использовании HTTP/2 и подзапросов в модуле njs.
++
++
++socket leak when using HTTP/2 and subrequests in the njs module.
++
++
++
++
++
++
++
++
++
++
++теперь nginx начинает закрывать keepalive-соединения,
++не дожидаясь исчерпания всех свободных соединений,
++а также пишет об этом предупреждение в лог ошибок.
++
++
++now nginx starts closing keepalive connections
++before all free worker connections are exhausted,
++and logs a warning about this to the error log.
++
++
++
++
++
++оптимизация чтения тела запроса
++при использовании chunked transfer encoding.
++
++
++optimization of client request body reading
++when using chunked transfer encoding.
++
++
++
++
++
++утечки памяти при использовании директивы ssl_ocsp.
++
++
++memory leak if the "ssl_ocsp" directive was used.
++
++
++
++
++
++в логах могли появляться сообщения "zero size buf in output",
++если FastCGI-сервер возвращал некорректный ответ;
++ошибка появилась в 1.19.1.
++
++
++"zero size buf in output" alerts might appear in logs
++if a FastCGI server returned an incorrect response;
++the bug had appeared in 1.19.1.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если размеры large_client_header_buffers отличались
++в разных виртуальных серверах.
++
++
++a segmentation fault might occur in a worker process
++if different large_client_header_buffers sizes were used
++in different virtual servers.
++
++
++
++
++
++SSL shutdown мог не работать.
++
++
++SSL shutdown might not work.
++
++
++
++
++
++в логах могли появляться сообщения
++"SSL_shutdown() failed (SSL: ... bad write retry)".
++
++
++"SSL_shutdown() failed (SSL: ... bad write retry)"
++messages might appear in logs.
++
++
++
++
++
++в модуле ngx_http_slice_module.
++
++
++in the ngx_http_slice_module.
++
++
++
++
++
++в модуле ngx_http_xslt_filter_module.
++
++
++in the ngx_http_xslt_filter_module.
++
++
++
++
++
++
++
++
++
++
++директивы lingering_close, lingering_time и lingering_timeout
++теперь работают при использовании HTTP/2.
++
++
++the "lingering_close", "lingering_time", and "lingering_timeout" directives
++now work when using HTTP/2.
++
++
++
++
++
++теперь лишние данные, присланные бэкендом, всегда отбрасываются.
++
++
++now extra data sent by a backend are always discarded.
++
++
++
++
++
++теперь при получении слишком короткого ответа от FastCGI-сервера
++nginx пытается отправить клиенту доступную часть ответа,
++после чего закрывает соединение с клиентом.
++
++
++now after receiving a too short response from a FastCGI server
++nginx tries to send the available part of the response to the client,
++and then closes the client connection.
++
++
++
++
++
++теперь при получении ответа некорректной длины от gRPC-бэкенда
++nginx прекращает обработку ответа с ошибкой.
++
++
++now after receiving a response with incorrect length from a gRPC backend
++nginx stops response processing with an error.
++
++
++
++
++
++параметр min_free в директивах proxy_cache_path, fastcgi_cache_path,
++scgi_cache_path и uwsgi_cache_path.
++Спасибо Adam Bambuch.
++
++
++the "min_free" parameter of the "proxy_cache_path", "fastcgi_cache_path",
++"scgi_cache_path", and "uwsgi_cache_path" directives.
++Thanks to Adam Bambuch.
++
++
++
++
++
++nginx не удалял unix domain listen-сокеты
++при плавном завершении по сигналу SIGQUIT.
++
++
++nginx did not delete unix domain listen sockets
++during graceful shutdown on the SIGQUIT signal.
++
++
++
++
++
++UDP-пакеты нулевого размера не проксировались.
++
++
++zero length UDP datagrams were not proxied.
++
++
++
++
++
++проксирование на uwsgi-бэкенды с использованием SSL могло не работать.
++Спасибо Guanzhong Chen.
++
++
++proxying to uwsgi backends using SSL might not work.
++Thanks to Guanzhong Chen.
++
++
++
++
++
++в обработке ошибок при использовании директивы ssl_ocsp.
++
++
++in error handling when using the "ssl_ocsp" directive.
++
++
++
++
++
++при использовании файловых систем XFS и NFS
++размер кэша на диске мог считаться некорректно.
++
++
++on XFS and NFS file systems
++disk cache size might be calculated incorrectly.
++
++
++
++
++
++если сервер memcached возвращал некорректный ответ,
++в логах могли появляться сообщения "negative size buf in writer".
++
++
++"negative size buf in writer" alerts might appear in logs
++if a memcached server returned a malformed response.
++
++
++
++
++
++
++
++
++
++
++проверка клиентских сертификатов с помощью OCSP.
++
++
++client certificate validation with OCSP.
++
++
++
++
++
++при работе с gRPC-бэкендами
++могли возникать ошибки "upstream sent frame for closed stream".
++
++
++"upstream sent frame for closed stream" errors might occur
++when working with gRPC backends.
++
++
++
++
++
++OCSP stapling мог не работать,
++если не была указана директива resolver.
++
++
++OCSP stapling might not work
++if the "resolver" directive was not specified.
++
++
++
++
++
++соединения с некорректным HTTP/2 preface не логгировались.
++
++
++connections with incorrect HTTP/2 preface were not logged.
++
++
++
++
++
++
++
++
++
++
++директива auth_delay.
++
++
++the "auth_delay" directive.
++
++
++
++
++
++
++
++
++
++
++теперь nginx не разрешает
++несколько строк "Host" в заголовке запроса.
++
++
++now nginx does not allow
++several "Host" request header lines.
++
++
++
++
++
++nginx игнорировал дополнительные
++строки "Transfer-Encoding" в заголовке запроса.
++
++
++nginx ignored additional
++"Transfer-Encoding" request header lines.
++
++
++
++
++
++утечки сокетов при использовании HTTP/2.
++
++
++socket leak when using HTTP/2.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался OCSP stapling.
++
++
++a segmentation fault might occur in a worker process
++if OCSP stapling was used.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++при перенаправлении ошибок с кодом 494 с помощью директивы error_page
++nginx возвращал ответ с кодом 494 вместо 400.
++
++
++nginx used status code 494 instead of 400
++if errors with code 494 were redirected with the "error_page" directive.
++
++
++
++
++
++утечки сокетов при использовании подзапросов в модуле njs и директивы aio.
++
++
++socket leak when using subrequests in the njs module and the "aio" directive.
++
++
++
++
++
++
++
++
++
++
++директива grpc_pass поддерживает переменные.
++
++
++variables support in the "grpc_pass" directive.
++
++
++
++
++
++при обработке pipelined-запросов по SSL-соединению мог произойти таймаут;
++ошибка появилась в 1.17.5.
++
++
++a timeout might occur while handling pipelined requests in an SSL connection;
++the bug had appeared in 1.17.5.
++
++
++
++
++
++в директиве debug_points при использовании HTTP/2.
++Спасибо Даниилу Бондареву.
++
++
++in the "debug_points" directive when using HTTP/2.
++Thanks to Daniil Bondarev.
++
++
++
++
++
++
++
++
++
++
++на старте или во время переконфигурации мог произойти segmentation fault,
++если в конфигурации использовалась
++директива rewrite с пустой строкой замены.
++
++
++a segmentation fault might occur on start or during reconfiguration
++if the "rewrite" directive with an empty replacement string
++was used in the configuration.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если директива break использовалась совместно с директивой alias
++или директивой proxy_pass с URI.
++
++
++a segmentation fault might occur in a worker process
++if the "break" directive was used with the "alias" directive
++or with the "proxy_pass" directive with a URI.
++
++
++
++
++
++строка Location заголовка ответа могла содержать мусор,
++если URI запроса был изменён на URI, содержащий нулевой символ.
++
++
++the "Location" response header line might contain garbage
++if the request URI was rewritten to the one containing a null character.
++
++
++
++
++
++при возврате перенаправлений с помощью директивы error_page
++запросы с телом обрабатывались некорректно;
++ошибка появилась в 0.7.12.
++
++
++requests with bodies were handled incorrectly
++when returning redirections with the "error_page" directive;
++the bug had appeared in 0.7.12.
++
++
++
++
++
++утечки сокетов при использовании HTTP/2.
++
++
++socket leak when using HTTP/2.
++
++
++
++
++
++при обработке pipelined-запросов по SSL-соединению мог произойти таймаут;
++ошибка появилась в 1.17.5.
++
++
++a timeout might occur while handling pipelined requests in an SSL connection;
++the bug had appeared in 1.17.5.
++
++
++
++
++
++в модуле ngx_http_dav_module.
++
++
++in the ngx_http_dav_module.
++
++
++
++
++
++
++
++
++
++
++переменные $proxy_protocol_server_addr и $proxy_protocol_server_port.
++
++
++the $proxy_protocol_server_addr and $proxy_protocol_server_port variables.
++
++
++
++
++
++директива limit_conn_dry_run.
++
++
++the "limit_conn_dry_run" directive.
++
++
++
++
++
++переменные $limit_req_status и $limit_conn_status.
++
++
++the $limit_req_status and $limit_conn_status variables.
++
++
++
++
++
++
++
++
++
++
++теперь nginx использует вызов ioctl(FIONREAD), если он доступен,
++чтобы избежать чтения из быстрого соединения в течение долгого времени.
++
++
++now nginx uses ioctl(FIONREAD), if available,
++to avoid reading from a fast connection for a long time.
++
++
++
++
++
++неполные закодированные символы в конце URI запроса игнорировались.
++
++
++incomplete escaped characters at the end of the request URI were ignored.
++
++
++
++
++
++"/." и "/.." в конце URI запроса не нормализовывались.
++
++
++"/." and "/.." at the end of the request URI were not normalized.
++
++
++
++
++
++в директиве merge_slashes.
++
++
++in the "merge_slashes" directive.
++
++
++
++
++
++в директиве ignore_invalid_headers.
++Спасибо Alan Kemp.
++
++
++in the "ignore_invalid_headers" directive.
++Thanks to Alan Kemp.
++
++
++
++
++
++nginx не собирался с MinGW-w64 gcc 8.1 и новее.
++
++
++nginx could not be built with MinGW-w64 gcc 8.1 or newer.
++
++
++
++
++
++
++
++
++
++
++улучшено детектирование некорректного поведения клиентов в HTTP/2.
++
++
++better detection of incorrect client behavior in HTTP/2.
++
++
++
++
++
++в обработке непрочитанного тела запроса
++при возврате ошибок в HTTP/2.
++
++
++in handling of not fully read client request body
++when returning errors in HTTP/2.
++
++
++
++
++
++директива worker_shutdown_timeout могла не работать
++при использовании HTTP/2.
++
++
++the "worker_shutdown_timeout" directive might not work
++when using HTTP/2.
++
++
++
++
++
++при использовании HTTP/2 и директивы proxy_request_buffering
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when using HTTP/2 and the "proxy_request_buffering" directive.
++
++
++
++
++
++на Windows при использовании SSL
++уровень записи в лог ошибки ECONNABORTED был "crit" вместо "error".
++
++
++the ECONNABORTED error log level was "crit" instead of "error"
++on Windows when using SSL.
++
++
++
++
++
++nginx игнорировал лишние данные при использовании chunked transfer encoding.
++
++
++nginx ignored extra data when using chunked transfer encoding.
++
++
++
++
++
++если использовалась директива return и
++при чтении тела запроса возникала ошибка,
++nginx всегда возвращал ошибку 500.
++
++
++nginx always returned the 500 error
++if the "return" directive was used
++and an error occurred during reading client request body.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++
++
++in memory allocation error handling.
++
++
++
++
++
++
++
++
++
++
++при использовании HTTP/2 клиент мог вызвать
++чрезмерное потребление памяти и ресурсов процессора
++(CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
++
++
++when using HTTP/2 a client might cause
++excessive memory consumption and CPU usage
++(CVE-2019-9511, CVE-2019-9513, CVE-2019-9516).
++
++
++
++
++
++при использовании сжатия в логах могли появляться сообщения "zero size buf";
++ошибка появилась в 1.17.2.
++
++
++"zero size buf" alerts might appear in logs when using gzipping;
++the bug had appeared in 1.17.2.
++
++
++
++
++
++при использовании директивы resolver в SMTP прокси-сервере
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if the "resolver" directive was used in SMTP proxy.
++
++
++
++
++
++
++
++
++
++
++минимальная поддерживаемая версия zlib—1.2.0.4.
++Спасибо Илье Леошкевичу.
++
++
++minimum supported zlib version is 1.2.0.4.
++Thanks to Ilya Leoshkevich.
++
++
++
++
++
++метод $r->internal_redirect() встроенного перла
++теперь ожидает закодированный URI.
++
++
++the $r->internal_redirect() embedded perl method
++now expects escaped URIs.
++
++
++
++
++
++теперь с помощью метода $r->internal_redirect() встроенного перла
++можно перейти в именованный location.
++
++
++it is now possible to switch to a named location
++using the $r->internal_redirect() embedded perl method.
++
++
++
++
++
++в обработке ошибок во встроенном перле.
++
++
++in error handling in embedded perl.
++
++
++
++
++
++на старте или во время переконфигурации мог произойти segmentation fault,
++если в конфигурации использовалось значение hash bucket size больше 64 килобайт.
++
++
++a segmentation fault might occur on start or during reconfiguration
++if hash bucket size larger than 64 kilobytes was used in the configuration.
++
++
++
++
++
++при использовании методов обработки соединений select, poll и /dev/poll
++nginx мог нагружать процессор во время небуферизованного проксирования
++и при проксировании WebSocket-соединений.
++
++
++nginx might hog CPU during unbuffered proxying
++and when proxying WebSocket connections
++if the select, poll, or /dev/poll methods were used.
++
++
++
++
++
++в модуле ngx_http_xslt_filter_module.
++
++
++in the ngx_http_xslt_filter_module.
++
++
++
++
++
++в модуле ngx_http_ssi_filter_module.
++
++
++in the ngx_http_ssi_filter_module.
++
++
++
++
++
++
++
++
++
++
++директива limit_req_dry_run.
++
++
++the "limit_req_dry_run" directive.
++
++
++
++
++
++при использовании директивы hash в блоке upstream
++пустой ключ хэширования теперь приводит к переключению
++на round-robin балансировку.
++Спасибо Niklas Keller.
++
++
++when using the "hash" directive inside the "upstream" block
++an empty hash key now triggers round-robin balancing.
++Thanks to Niklas Keller.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалось кэширование и директива image_filter,
++а ошибки с кодом 415 перенаправлялись с помощью директивы error_page;
++ошибка появилась в 1.11.10.
++
++
++a segmentation fault might occur in a worker process
++if caching was used along with the "image_filter" directive,
++and errors with code 415 were redirected with the "error_page" directive;
++the bug had appeared in 1.11.10.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался встроенный перл;
++ошибка появилась в 1.7.3.
++
++
++a segmentation fault might occur in a worker process
++if embedded perl was used;
++the bug had appeared in 1.7.3.
++
++
++
++
++
++
++
++
++
++
++директивы limit_rate и limit_rate_after поддерживают переменные.
++
++
++variables support in the "limit_rate" and "limit_rate_after" directives.
++
++
++
++
++
++директивы proxy_upload_rate и proxy_download_rate в модуле stream
++поддерживают переменные.
++
++
++variables support
++in the "proxy_upload_rate" and "proxy_download_rate" directives
++in the stream module.
++
++
++
++
++
++минимальная поддерживаемая версия OpenSSL—0.9.8.
++
++
++minimum supported OpenSSL version is 0.9.8.
++
++
++
++
++
++теперь postpone-фильтр собирается всегда.
++
++
++now the postpone filter is always built.
++
++
++
++
++
++директива include не работала в блоках if и limit_except.
++
++
++the "include" directive did not work inside the "if" and "limit_except" blocks.
++
++
++
++
++
++в обработке byte ranges.
++
++
++in byte ranges processing.
++
++
++
++
++
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если в директивах ssl_certificate или ssl_certificate_key
++использовались переменные
++и был включён OCSP stapling.
++
++
++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.
++
++
++
++
++
++
++
++
++
++
++в директиве ssl_stapling_file на Windows.
++
++
++in the "ssl_stapling_file" directive on Windows.
++
++
++
++
++
++
++
++
++
++
++теперь при использовании имени хоста в директиве listen
++nginx создаёт listen-сокеты для всех адресов,
++соответствующих этому имени
++(ранее использовался только первый адрес).
++
++
++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).
++
++
++
++
++
++диапазоны портов в директиве listen.
++
++
++port ranges in the "listen" directive.
++
++
++
++
++
++возможность загрузки SSL-сертификатов и секретных ключей из переменных.
++
++
++loading of SSL certificates and secret keys from variables.
++
++
++
++
++
++переменная $ssl_server_name могла быть пустой
++при использовании OpenSSL 1.1.1.
++
++
++the $ssl_server_name variable might be empty
++when using OpenSSL 1.1.1.
++
++
++
++
++
++nginx/Windows не собирался с Visual Studio 2015 и новее;
++ошибка появилась в 1.15.9.
++
++
++nginx/Windows could not be built with Visual Studio 2015 or newer;
++the bug had appeared in 1.15.9.
++
++
++
++
++
++
++
++
++
++
++директивы ssl_certificate и ssl_certificate_key
++поддерживают переменные.
++
++
++variables support
++in the "ssl_certificate" and "ssl_certificate_key" directives.
++
++
++
++
++
++метод poll теперь доступен на Windows
++при использовании Windows Vista и новее.
++
++
++the "poll" method is now available on Windows
++when using Windows Vista or newer.
++
++
++
++
++
++если при использовании метода select на Windows
++происходила ошибка при установлении соединения с бэкендом,
++nginx ожидал истечения таймаута на установление соединения.
++
++
++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.
++
++
++
++
++
++директивы proxy_upload_rate и proxy_download_rate
++в модуле stream
++работали некорректно при проксировании UDP-пакетов.
++
++
++the "proxy_upload_rate" and "proxy_download_rate" directives
++in the stream module
++worked incorrectly when proxying UDP datagrams.
++
++
++
++
++
++
++
++
++
++
++переменная $upstream_bytes_sent.
++Спасибо Piotr Sikora.
++
++
++the $upstream_bytes_sent variable.
++Thanks to Piotr Sikora.
++
++
++
++
++
++новые директивы в скриптах подсветки синтаксиса для vim.
++Спасибо Геннадию Махомеду.
++
++
++new directives in vim syntax highlighting scripts.
++Thanks to Gena Makhomed.
++
++
++
++
++
++в директиве proxy_cache_background_update.
++
++
++in the "proxy_cache_background_update" directive.
++
++
++
++
++
++в директиве geo при использовании unix domain listen-сокетов.
++
++
++in the "geo" directive when using unix domain listen sockets.
++
++
++
++
++
++при использовании директивы ssl_early_data с OpenSSL
++в логах могли появляться сообщения
++"ignoring stale global SSL error ... bad length".
++
++
++the "ignoring stale global SSL error ... bad length"
++alerts might appear in logs
++when using the "ssl_early_data" directive with OpenSSL.
++
++
++
++
++
++в nginx/Windows.
++
++
++in nginx/Windows.
++
++
++
++
++
++в модуле ngx_http_autoindex_module на 32-битных платформах.
++
++
++in the ngx_http_autoindex_module on 32-bit platforms.
++
++
++
++
++
++
++
++
++
++
++директива proxy_requests в модуле stream.
++
++
++the "proxy_requests" directive in the stream module.
++
++
++
++
++
++параметр "delay" директивы "limit_req".
++Спасибо Владиславу Шабанову и Петру Щучкину.
++
++
++the "delay" parameter of the "limit_req" directive.
++Thanks to Vladislav Shabanov and Peter Shchuchkin.
++
++
++
++
++
++утечки памяти в случае ошибок при переконфигурации.
++
++
++memory leak on errors during reconfiguration.
++
++
++
++
++
++в переменных $upstream_response_time, $upstream_connect_time и
++$upstream_header_time.
++
++
++in the $upstream_response_time, $upstream_connect_time, and
++$upstream_header_time variables.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_mp4_module на 32-битных платформах.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_mp4_module was used on 32-bit platforms.
++
++
++
++
++
++
++
++
++
++
++при использовании HTTP/2 клиент мог вызвать
++чрезмерное потреблению памяти (CVE-2018-16843)
++и ресурсов процессора (CVE-2018-16844).
++
++
++when using HTTP/2 a client might cause
++excessive memory consumption (CVE-2018-16843)
++and CPU usage (CVE-2018-16844).
++
++
++
++
++
++при обработке специально созданного mp4-файла модулем ngx_http_mp4_module
++содержимое памяти рабочего процесса могло быть отправлено клиенту
++(CVE-2018-16845).
++
++
++processing of a specially crafted mp4 file with the ngx_http_mp4_module
++might result in worker process memory disclosure
++(CVE-2018-16845).
++
++
++
++
++
++директивы proxy_socket_keepalive, fastcgi_socket_keepalive,
++grpc_socket_keepalive, memcached_socket_keepalive,
++scgi_socket_keepalive и uwsgi_socket_keepalive.
++
++
++the "proxy_socket_keepalive", "fastcgi_socket_keepalive",
++"grpc_socket_keepalive", "memcached_socket_keepalive",
++"scgi_socket_keepalive", and "uwsgi_socket_keepalive" directives.
++
++
++
++
++
++если nginx был собран с OpenSSL 1.1.0, а использовался с OpenSSL 1.1.1,
++протокол TLS 1.3 всегда был разрешён.
++
++
++if nginx was built with OpenSSL 1.1.0 and used with OpenSSL 1.1.1,
++the TLS 1.3 protocol was always enabled.
++
++
++
++
++
++при работе с gRPC-бэкендами могло расходоваться большое количество памяти.
++
++
++working with gRPC backends might result in excessive memory consumption.
++
++
++
++
++
++
++
++
++
++
++при использовании OpenSSL 1.1.0h и новее
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.15.4.
++
++
++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.
++
++
++
++
++
++незначительных потенциальных ошибок.
++
++
++of minor potential bugs.
++
++
++
++
++
++
++
++
++
++
++теперь директиву ssl_early_data можно использовать с OpenSSL.
++
++
++now the "ssl_early_data" directive can be used with OpenSSL.
++
++
++
++
++
++в модуле ngx_http_uwsgi_module.
++Спасибо Chris Caputo.
++
++
++in the ngx_http_uwsgi_module.
++Thanks to Chris Caputo.
++
++
++
++
++
++соединения к некоторым gRPC-бэкендам могли не кэшироваться
++при использовании директивы keepalive.
++
++
++connections with some gRPC backends might not be cached
++when using the "keepalive" directive.
++
++
++
++
++
++при использовании директивы error_page для перенаправления ошибок,
++возникающих на ранних этапах обработки запроса,
++в частности ошибок с кодом 400,
++могла происходить утечка сокетов.
++
++
++a socket leak might occur
++when using the "error_page" directive
++to redirect early request processing errors,
++notably errors with code 400.
++
++
++
++
++
++директива return при возврате ошибок не изменяла код ответа,
++если запрос был перенаправлен с помощью директивы error_page.
++
++
++the "return" directive did not change the response code when returning errors
++if the request was redirected by the "error_page" directive.
++
++
++
++
++
++стандартные сообщения об ошибках и ответы модуля ngx_http_autoindex_module
++содержали атрибут bgcolor, что могло приводить к их некорректному отображению
++при использовании пользовательских настроек цветов в браузерах.
++Спасибо Nova DasSarma.
++
++
++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.
++
++
++
++
++
++уровень логгирования ошибок SSL "no suitable key share" и
++"no suitable signature algorithm"
++понижен с уровня crit до info.
++
++
++the logging level of the "no suitable key share" and
++"no suitable signature algorithm" SSL errors
++has been lowered from "crit" to "info".
++
++
++
++
++
++
++
++
++
++
++теперь TLSv1.3 можно использовать с BoringSSL.
++
++
++now TLSv1.3 can be used with BoringSSL.
++
++
++
++
++
++директива ssl_early_data,
++сейчас доступна при использовании BoringSSL.
++
++
++the "ssl_early_data" directive,
++currently available with BoringSSL.
++
++
++
++
++
++директивы keepalive_timeout и keepalive_requests
++в блоке upstream.
++
++
++the "keepalive_timeout" and "keepalive_requests" directives
++in the "upstream" block.
++
++
++
++
++
++модуль ngx_http_dav_module
++при копировании файла поверх существующего файла с помощью метода COPY
++не обнулял целевой файл.
++
++
++the ngx_http_dav_module
++did not truncate destination file when copying a file over an existing one
++with the COPY method.
++
++
++
++
++
++модуль ngx_http_dav_module
++при перемещении файла между файловыми системами с помощью метода MOVE
++устанавливал нулевые права доступа на результирующий файл
++и не сохранял время изменения файла.
++
++
++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.
++
++
++
++
++
++модуль ngx_http_dav_module
++при копировании файла с помощью метода COPY
++для результирующего файла использовал права доступа по умолчанию.
++
++
++the ngx_http_dav_module
++used default access rights
++when copying a file with the COPY method.
++
++
++
++
++
++некоторые клиенты могли не работать при использовании HTTP/2;
++ошибка появилась в 1.13.5.
++
++
++some clients might not work when using HTTP/2;
++the bug had appeared in 1.13.5.
++
++
++
++
++
++nginx не собирался с LibreSSL 2.8.0.
++
++
++nginx could not be built with LibreSSL 2.8.0.
++
++
++
++
++
++
++
++
++
++
++переменная $ssl_preread_protocol
++в модуле ngx_stream_ssl_preread_module.
++
++
++the $ssl_preread_protocol variable
++in the ngx_stream_ssl_preread_module.
++
++
++
++
++
++теперь при использовании директивы reset_timedout_connection
++nginx сбрасывает соединения, закрываемые с кодом 444.
++
++
++now when using the "reset_timedout_connection" directive
++nginx will reset connections being closed with the 444 code.
++
++
++
++
++
++уровень логгирования ошибок SSL "http request", "https proxy request",
++"unsupported protocol" и "version too low"
++понижен с уровня crit до info.
++
++
++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".
++
++
++
++
++
++запросы к DNS-серверу не отправлялись повторно,
++если при первой попытке отправки происходила ошибка.
++
++
++DNS requests were not resent
++if initial sending of a request failed.
++
++
++
++
++
++параметр reuseport директивы listen игнорировался,
++если количество рабочих процессов было задано после директивы listen.
++
++
++the "reuseport" parameter of the "listen" directive was ignored
++if the number of worker processes was specified after the "listen" directive.
++
++
++
++
++
++при использовании OpenSSL 1.1.0 и новее
++директиву ssl_prefer_server_ciphers нельзя было выключить
++в виртуальном сервере, если она была включена в сервере по умолчанию.
++
++
++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.
++
++
++
++
++
++повторное использование SSL-сессий к бэкендам
++не работало с протоколом TLS 1.3.
++
++
++SSL session reuse with upstream servers
++did not work with the TLS 1.3 protocol.
++
++
++
++
++
++
++
++
++
++
++директива random в блоке upstream.
++
++
++the "random" directive inside the "upstream" block.
++
++
++
++
++
++улучшена производительность при использовании директив hash и ip_hash
++совместно с директивой zone.
++
++
++improved performance when using the "hash" and "ip_hash" directives
++with the "zone" directive.
++
++
++
++
++
++параметр reuseport директивы listen
++теперь использует SO_REUSEPORT_LB на FreeBSD 12.
++
++
++the "reuseport" parameter of the "listen" directive
++now uses SO_REUSEPORT_LB on FreeBSD 12.
++
++
++
++
++
++HTTP/2 server push не работал, если SSL терминировался прокси-сервером
++перед nginx'ом.
++
++
++HTTP/2 server push did not work if SSL was terminated by a proxy server
++in front of nginx.
++
++
++
++
++
++директива tcp_nopush всегда использовалась для соединений к бэкендам.
++
++
++the "tcp_nopush" directive was always used on backend connections.
++
++
++
++
++
++при отправке сохранённого на диск тела запроса на gRPC-бэкенд
++могли возникать ошибки.
++
++
++sending a disk-buffered request body to a gRPC backend
++might fail.
++
++
++
++
++
++
++
++
++
++
++директива "ssl" теперь считается устаревшей;
++вместо неё следует использовать параметр ssl директивы listen.
++
++
++the "ssl" directive is deprecated;
++the "ssl" parameter of the "listen" directive should be used instead.
++
++
++
++
++
++теперь при использовании директивы listen с параметром ssl
++nginx определяет отсутствие SSL-сертификатов при тестировании конфигурации.
++
++
++now nginx detects missing SSL certificates during configuration testing
++when using the "ssl" parameter of the "listen" directive.
++
++
++
++
++
++теперь модуль stream умеет обрабатывать
++несколько входящих UDP-пакетов от клиента в рамках одной сессии.
++
++
++now the stream module can handle
++multiple incoming UDP datagrams from a client within a single session.
++
++
++
++
++
++в директиве proxy_cache_valid
++можно было указать некорректный код ответа.
++
++
++it was possible to specify an incorrect response code
++in the "proxy_cache_valid" directive.
++
++
++
++
++
++nginx не собирался gcc 8.1.
++
++
++nginx could not be built by gcc 8.1.
++
++
++
++
++
++логгирование в syslog останавливалось при изменении локального IP-адреса.
++
++
++logging to syslog stopped on local IP address changes.
++
++
++
++
++
++nginx не собирался компилятором clang, если был установлен CUDA SDK;
++ошибка появилась в 1.13.8.
++
++
++nginx could not be built by clang with CUDA SDK installed;
++the bug had appeared in 1.13.8.
++
++
++
++
++
++при использовании unix domain listen-сокетов на FreeBSD
++в процессе обновления исполняемого файла
++в логе могли появляться сообщения "getsockopt(TCP_FASTOPEN) ... failed".
++
++
++"getsockopt(TCP_FASTOPEN) ... failed" messages might appear in logs
++during binary upgrade
++when using unix domain listen sockets on FreeBSD.
++
++
++
++
++
++nginx не собирался на Fedora 28 Linux.
++
++
++nginx could not be built on Fedora 28 Linux.
++
++
++
++
++
++при использовании директивы limit_req
++заданная скорость обработки запросов могла не соблюдаться.
++
++
++request processing rate might exceed configured rate
++when using the "limit_req" directive.
++
++
++
++
++
++в обработке адресов клиентов при использовании unix domain listen-сокетов
++для работы с датаграммами на Linux.
++
++
++in handling of client addresses when using unix domain listen sockets
++to work with datagrams on Linux.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++
++
++in memory allocation error handling.
++
++
++
++
++
++
++
++
++
++
++при возврате большого ответа
++соединения с gRPC-бэкендами могли неожиданно закрываться.
++
++
++connections with gRPC backends might be closed unexpectedly
++when returning a large response.
++
++
++
++
++
++
++
++
++
++
++параметр proxy_protocol директивы listen
++теперь поддерживает протокол PROXY версии 2.
++
++
++the "proxy_protocol" parameter of the "listen" directive
++now supports the PROXY protocol version 2.
++
++
++
++
++
++nginx не собирался с OpenSSL 1.1.1 статически на Linux.
++
++
++nginx could not be built with OpenSSL 1.1.1 statically on Linux.
++
++
++
++
++
++в параметрах http_404, http_500 и им подобных
++директивы proxy_next_upstream.
++
++
++in the "http_404", "http_500", etc. parameters
++of the "proxy_next_upstream" directive.
++
++
++
++
++
++
++
++
++
++
++теперь параметр set в SSI-директиве include
++позволяет сохранять в переменную любые ответы;
++максимальный размер ответа задаётся директивой subrequest_output_buffer_size.
++
++
++the "set" parameter of the "include" SSI directive now allows
++writing arbitrary responses to a variable;
++the "subrequest_output_buffer_size" directive defines maximum response size.
++
++
++
++
++
++теперь nginx использует вызов clock_gettime(CLOCK_MONOTONIC), если он доступен,
++что позволяет избежать некорректного срабатывания таймаутов
++при изменениях системного времени.
++
++
++now nginx uses clock_gettime(CLOCK_MONOTONIC) if available,
++to avoid timeouts being incorrectly triggered
++on system time changes.
++
++
++
++
++
++параметр "escape=none" директивы log_format.
++Спасибо Johannes Baiter и Calin Don.
++
++
++the "escape=none" parameter of the "log_format" directive.
++Thanks to Johannes Baiter and Calin Don.
++
++
++
++
++
++переменная $ssl_preread_alpn_protocols
++в модуле ngx_stream_ssl_preread_module.
++
++
++the $ssl_preread_alpn_protocols variable
++in the ngx_stream_ssl_preread_module.
++
++
++
++
++
++модуль ngx_http_grpc_module.
++
++
++the ngx_http_grpc_module.
++
++
++
++
++
++в обработке ошибок выделения памяти в директиве geo.
++
++
++in memory allocation error handling in the "geo" directive.
++
++
++
++
++
++при использовании переменных в директиве auth_basic_user_file
++в лог мог выводиться символ '\0'.
++Спасибо Вадиму Филимонову.
++
++
++when using variables in the "auth_basic_user_file" directive
++a null character might appear in logs.
++Thanks to Vadim Filimonov.
++
++
++
++
++
++
++
++
++
++
++поддержка HTTP/2 server push;
++директивы http2_push и http2_push_preload.
++
++
++HTTP/2 server push support;
++the "http2_push" and "http2_push_preload" directives.
++
++
++
++
++
++при использовании кэша
++в логах могли появляться сообщения "header already sent";
++ошибка появилась в 1.9.13.
++
++
++"header already sent" alerts might appear in logs
++when using cache;
++the bug had appeared in 1.9.13.
++
++
++
++
++
++при использовании директивы ssl_verify_client
++в рабочем процессе мог произойти segmentation fault,
++если в виртуальном сервере не был указан SSL-сертификат.
++
++
++a segmentation fault might occur in a worker process
++if the "ssl_verify_client" directive was used
++and no SSL certificate was specified in a virtual server.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++
++
++in the ngx_http_v2_module.
++
++
++
++
++
++в модуле ngx_http_dav_module.
++
++
++in the ngx_http_dav_module.
++
++
++
++
++
++
++
++
++
++
++теперь при использовании параметра transparent директив proxy_bind,
++fastcgi_bind, memcached_bind, scgi_bind и uwsgi_bind
++nginx автоматически сохраняет capability CAP_NET_RAW в рабочих процессах.
++
++
++now nginx automatically preserves the CAP_NET_RAW capability in worker processes
++when using the "transparent" parameter of the "proxy_bind",
++"fastcgi_bind", "memcached_bind", "scgi_bind", and "uwsgi_bind" directives.
++
++
++
++
++
++улучшения в определении размера строки кэша процессора.
++Спасибо Debayan Ghosh.
++
++
++improved CPU cache line size detection.
++Thanks to Debayan Ghosh.
++
++
++
++
++
++новые директивы в скриптах подсветки синтаксиса для vim.
++Спасибо Геннадию Махомеду.
++
++
++new directives in vim syntax highlighting scripts.
++Thanks to Gena Makhomed.
++
++
++
++
++
++процедура обновления исполняемого файла не работала,
++если после завершения родительского процесса
++новым родительским процессом nginx'а становился процесс с PID, отличным от 1.
++
++
++binary upgrade refused to work
++if nginx was re-parented to a process with PID different from 1
++after its parent process has finished.
++
++
++
++
++
++модуль ngx_http_autoindex_module неправильно обрабатывал запросы с телом.
++
++
++the ngx_http_autoindex_module incorrectly handled requests with bodies.
++
++
++
++
++
++в директиве proxy_limit_rate при использовании с директивой keepalive.
++
++
++in the "proxy_limit_rate" directive when used with the "keepalive" directive.
++
++
++
++
++
++при использовании "proxy_buffering off" часть ответа могла буферизироваться,
++если клиентское соединение использовало SSL.
++Спасибо Patryk Lesiewicz.
++
++
++some parts of a response might be buffered when using "proxy_buffering off"
++if the client connection used SSL.
++Thanks to Patryk Lesiewicz.
++
++
++
++
++
++в директиве proxy_cache_background_update.
++
++
++in the "proxy_cache_background_update" directive.
++
++
++
++
++
++переменную вида "${name}" с именем в фигурных скобках
++нельзя было использовать в начале параметра
++не заключив весь параметр в кавычки.
++
++
++it was not possible to start a parameter
++with a variable in the "${name}" form with the name in curly brackets
++without enclosing the parameter into single or double quotes.
++
++
++
++
++
++
++
++
++
++
++в переменной $upstream_status.
++
++
++in the $upstream_status variable.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если бэкенд возвращал ответ "101 Switching Protocols" на подзапрос.
++
++
++a segmentation fault might occur in a worker process
++if a backend returned a "101 Switching Protocols" response to a subrequest.
++
++
++
++
++
++если при переконфигурации изменялся размер зоны разделяемой памяти
++и переконфигурация завершалась неудачно,
++то в главном процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in a master process
++if a shared memory zone size was changed during a reconfiguration
++and the reconfiguration failed.
++
++
++
++
++
++в модуле ngx_http_fastcgi_module.
++
++
++in the ngx_http_fastcgi_module.
++
++
++
++
++
++nginx возвращал ошибку 500,
++если в директиве xslt_stylesheet
++были заданы параметры без использования переменных.
++
++
++nginx returned the 500 error
++if parameters without variables were specified
++in the "xslt_stylesheet" directive.
++
++
++
++
++
++при использовании варианта библиотеки zlib от Intel
++в лог писались сообщения "gzip filter failed to use preallocated memory".
++
++
++"gzip filter failed to use preallocated memory" alerts appeared in logs
++when using a zlib library variant from Intel.
++
++
++
++
++
++директива worker_shutdown_timeout не работала
++при использовании почтового прокси-сервера
++и при проксировании WebSocket-соединений.
++
++
++the "worker_shutdown_timeout" directive did not work
++when using mail proxy and when proxying WebSocket connections.
++
++
++
++
++
++
++
++
++
++
++при использовании директивы ssl_preread
++в модуле stream не работало переключение на следующий бэкенд.
++
++
++switching to the next upstream server in the stream module did not work
++when using the "ssl_preread" directive.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_v2_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++nginx не поддерживал даты после 2038 года
++на 32-битных платформах с 64-битным time_t.
++
++
++nginx did not support dates after the year 2038
++on 32-bit platforms with 64-bit time_t.
++
++
++
++
++
++в обработке дат до 1970 года и после 10000 года.
++
++
++in handling of dates prior to the year 1970 and after the year 10000.
++
++
++
++
++
++в модуле stream таймауты ожидания UDP-пакетов от бэкендов
++не логгировались или логгировались на уровне info вместо error.
++
++
++in the stream module timeouts waiting for UDP datagrams from upstream servers
++were not logged or logged at the "info" level instead of "error".
++
++
++
++
++
++при использовании HTTP/2 nginx мог вернуть ошибку 400,
++не указав в логе причину.
++
++
++when using HTTP/2 nginx might return the 400 response
++without logging the reason.
++
++
++
++
++
++в обработке повреждённых файлов кэша.
++
++
++in processing of corrupted cache files.
++
++
++
++
++
++при кэшировании ошибок, перехваченных error_page,
++не учитывались заголовки управления кэшированием.
++
++
++cache control headers were ignored
++when caching errors intercepted by error_page.
++
++
++
++
++
++при использовании HTTP/2 тело запроса могло быть повреждено.
++
++
++when using HTTP/2 client request body might be corrupted.
++
++
++
++
++
++в обработке адресов клиентов при использовании unix domain сокетов.
++
++
++in handling of client addresses when using unix domain sockets.
++
++
++
++
++
++при использовании директивы "hash ... consistent" в блоке upstream
++nginx нагружал процессор, если использовались большие веса
++и все или почти все бэкенды были недоступны.
++
++
++nginx hogged CPU
++when using the "hash ... consistent" directive in the upstream block
++if large weights were used and all or most of the servers were unavailable.
++
++
++
++
++
++
++
++
++
++
++переменная $ssl_client_escaped_cert.
++
++
++the $ssl_client_escaped_cert variable.
++
++
++
++
++
++директива ssl_session_ticket_key и параметр include директивы geo
++не работали на Windows.
++
++
++the "ssl_session_ticket_key" directive and
++the "include" parameter of the "geo" directive did not work on Windows.
++
++
++
++
++
++на 32-битных платформах
++при запросе более 4 гигабайт с помощью нескольких диапазонов
++возвращалась некорректная длина ответа.
++
++
++incorrect response length was returned
++on 32-bit platforms when requesting more than 4 gigabytes
++with multiple ranges.
++
++
++
++
++
++директива "expires modified" и
++обработка строки If-Range заголовка запроса
++не учитывали время последнего изменения ответа,
++если использовалось проксирование без кэширования.
++
++
++the "expires modified" directive and
++processing of the "If-Range" request header line
++did not use the response last modification time
++if proxying without caching was used.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_mirror_module.
++
++
++the ngx_http_mirror_module.
++
++
++
++
++
++клиентские соединения могли сбрасываться при тестировании конфигурации,
++если использовался параметр reuseport директивы listen на Linux.
++
++
++client connections might be dropped during configuration testing
++when using the "reuseport" parameter of the "listen" directive on Linux.
++
++
++
++
++
++тело запроса могло быть недоступно в подзапросах,
++если оно было сохранено в файл и использовалось проксирование.
++
++
++request body might not be available in subrequests
++if it was saved to a file and proxying was used.
++
++
++
++
++
++очистка кэша по max_size не работала на Windows.
++
++
++cleaning cache based on the "max_size" parameter did not work on Windows.
++
++
++
++
++
++любое выделение разделяемой памяти на Windows требовало 4096 байт памяти.
++
++
++any shared memory allocation required 4096 bytes on Windows.
++
++
++
++
++
++при использовании директивы zone в блоке upstream на Windows
++рабочий процесс мог завершаться аварийно.
++
++
++nginx worker might be terminated abnormally
++when using the "zone" directive inside the "upstream" block on Windows.
++
++
++
++
++
++
++
++
++
++
++специально созданный запрос мог вызвать целочисленное переполнение
++в range-фильтре и последующую некорректную обработку запрошенных диапазонов,
++что потенциально могло привести к утечке конфиденциальной информации
++(CVE-2017-7529).
++
++
++a specially crafted request might result in an integer overflow
++and incorrect processing of ranges in the range filter,
++potentially resulting in sensitive information leak
++(CVE-2017-7529).
++
++
++
++
++
++
++
++
++
++
++теперь при запросе диапазона, начинающегося с 0, из пустого файла
++nginx возвращает ответ 200 вместо 416.
++
++
++nginx now returns 200 instead of 416
++when a range starting with 0 is requested from an empty file.
++
++
++
++
++
++директива add_trailer.
++Спасибо Piotr Sikora.
++
++
++the "add_trailer" directive.
++Thanks to Piotr Sikora.
++
++
++
++
++
++nginx не собирался под Cygwin и NetBSD;
++ошибка появилась в 1.13.0.
++
++
++nginx could not be built on Cygwin and NetBSD;
++the bug had appeared in 1.13.0.
++
++
++
++
++
++nginx не собирался под MSYS2 / MinGW 64-bit.
++Спасибо Orgad Shaneh.
++
++
++nginx could not be built under MSYS2 / MinGW 64-bit.
++Thanks to Orgad Shaneh.
++
++
++
++
++
++при использовании SSI с большим количеством подзапросов
++и proxy_pass с переменными
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when using SSI with many includes
++and proxy_pass with variables.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_v2_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++теперь в качестве параметра директивы set_real_ip_from
++можно указывать имя хоста.
++
++
++now a hostname can be used
++as the "set_real_ip_from" directive parameter.
++
++
++
++
++
++улучшения в скриптах подсветки синтаксиса для vim.
++
++
++vim syntax highlighting scripts improvements.
++
++
++
++
++
++директива worker_cpu_affinity теперь работает на DragonFly BSD.
++Спасибо Sepherosa Ziehau.
++
++
++the "worker_cpu_affinity" directive now works on DragonFly BSD.
++Thanks to Sepherosa Ziehau.
++
++
++
++
++
++SSL renegotiation в соединениях к бэкендам
++не работал при использовании OpenSSL до 1.1.0.
++
++
++SSL renegotiation on backend connections
++did not work when using OpenSSL before 1.1.0.
++
++
++
++
++
++nginx не собирался с Oracle Developer Studio 12.5.
++
++
++nginx could not be built with Oracle Developer Studio 12.5.
++
++
++
++
++
++теперь cache manager пропускает заблокированные записи
++при очистке кэша по max_size.
++
++
++now cache manager ignores long locked cache entries
++when cleaning cache based on the "max_size" parameter.
++
++
++
++
++
++клиентские SSL-соединения сразу закрывались, если использовался
++отложенный accept и параметр proxy_protocol директивы listen.
++
++
++client SSL connections were immediately closed if deferred accept
++and the "proxy_protocol" parameter of the "listen" directive were used.
++
++
++
++
++
++в директиве proxy_cache_background_update.
++
++
++in the "proxy_cache_background_update" directive.
++
++
++
++
++
++теперь директива tcp_nodelay
++устанавливает опцию TCP_NODELAY перед SSL handshake.
++
++
++now the "tcp_nodelay" directive
++sets the TCP_NODELAY option before an SSL handshake.
++
++
++
++
++
++
++
++
++
++
++теперь SSL renegotiation допускается в соединениях к бэкендам.
++
++
++SSL renegotiation is now allowed on backend connections.
++
++
++
++
++
++параметры rcvbuf и sndbuf директив listen
++в почтовом прокси-сервере и модуле stream.
++
++
++the "rcvbuf" and "sndbuf" parameters of the "listen" directives
++of the mail proxy and stream modules.
++
++
++
++
++
++директивы return и error_page теперь могут использоваться для возврата
++перенаправлений с кодом 308.
++Спасибо Simon Leblanc.
++
++
++the "return" and "error_page" directives can now be used to return 308
++redirections.
++Thanks to Simon Leblanc.
++
++
++
++
++
++параметр TLSv1.3 в директиве ssl_protocols.
++
++
++the "TLSv1.3" parameter of the "ssl_protocols" directive.
++
++
++
++
++
++при логгировании сигналов теперь указывается PID отправившего сигнал процесса.
++
++
++when logging signals nginx now logs PID of the process which sent the signal.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++
++
++in memory allocation error handling.
++
++
++
++
++
++если сервер в модуле stream слушал на wildcard-адресе,
++исходящий адрес ответного UDP-пакета
++мог отличаться от адреса назначения исходного пакета.
++
++
++if a server in the stream module listened on a wildcard address,
++the source address of a response UDP datagram could differ
++from the original datagram destination address.
++
++
++
++
++
++
++
++
++
++
++параметр http_429 в директивах proxy_next_upstream, fastcgi_next_upstream,
++scgi_next_upstream и uwsgi_next_upstream.
++Спасибо Piotr Sikora.
++
++
++the "http_429" parameter of the "proxy_next_upstream", "fastcgi_next_upstream",
++"scgi_next_upstream", and "uwsgi_next_upstream" directives.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++
++
++in memory allocation error handling.
++
++
++
++
++
++при использовании директив sendfile и timer_resolution на Linux
++запросы могли зависать.
++
++
++requests might hang
++when using the "sendfile" and "timer_resolution" directives on Linux.
++
++
++
++
++
++при использовании с подзапросами директив sendfile и aio_write
++запросы могли зависать.
++
++
++requests might hang
++when using the "sendfile" and "aio_write" directives with subrequests.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_v2_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++при использовании HTTP/2 в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process when using HTTP/2.
++
++
++
++
++
++запросы могли зависать
++при использовании с подзапросами директив limit_rate, sendfile_max_chunk,
++limit_req или метода $r->sleep() встроенного перла.
++
++
++requests might hang
++when using the "limit_rate", "sendfile_max_chunk", "limit_req" directives,
++or the $r->sleep() embedded perl method with subrequests.
++
++
++
++
++
++в модуле ngx_http_slice_module.
++
++
++in the ngx_http_slice_module.
++
++
++
++
++
++
++
++
++
++
++nginx мог нагружать процессор;
++ошибка появилась в 1.11.11.
++
++
++nginx might hog CPU;
++the bug had appeared in 1.11.11.
++
++
++
++
++
++
++
++
++
++
++директива worker_shutdown_timeout.
++
++
++the "worker_shutdown_timeout" directive.
++
++
++
++
++
++улучшения в скриптах подсветки синтаксиса для vim.
++Спасибо Wei-Ko Kao.
++
++
++vim syntax highlighting scripts improvements.
++Thanks to Wei-Ko Kao.
++
++
++
++
++
++при попытке установить переменную $limit_rate в пустую строку
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if the $limit_rate variable was set to an empty string.
++
++
++
++
++
++директивы proxy_cache_background_update, fastcgi_cache_background_update,
++scgi_cache_background_update и uwsgi_cache_background_update
++могли работать некорректно, если использовалась директива if.
++
++
++the "proxy_cache_background_update", "fastcgi_cache_background_update",
++"scgi_cache_background_update", and "uwsgi_cache_background_update" directives
++might work incorrectly if the "if" directive was used.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если количество large_client_header_buffers в виртуальном сервере
++отличалось от такового в сервере по умолчанию.
++
++
++a segmentation fault might occur in a worker process
++if number of large_client_header_buffers in a virtual server
++was different from the one in the default server.
++
++
++
++
++
++в почтовом прокси-сервере.
++
++
++in the mail proxy server.
++
++
++
++
++
++
++
++
++
++
++формат заголовка кэша был изменен,
++ранее закэшированные ответы будут загружены заново.
++
++
++cache header format has been changed,
++previously cached responses will be invalidated.
++
++
++
++
++
++поддержка расширений stale-while-revalidate и stale-if-error
++в строке "Cache-Control" в заголовке ответа бэкенда.
++
++
++support of "stale-while-revalidate" and "stale-if-error" extensions
++in the "Cache-Control" backend response header line.
++
++
++
++
++
++директивы proxy_cache_background_update, fastcgi_cache_background_update,
++scgi_cache_background_update и uwsgi_cache_background_update.
++
++
++the "proxy_cache_background_update", "fastcgi_cache_background_update",
++"scgi_cache_background_update", and "uwsgi_cache_background_update" directives.
++
++
++
++
++
++теперь nginx может кэшировать ответы
++со строкой Vary заголовка длиной до 128 символов
++(вместо 42 символов в предыдущих версиях).
++
++
++nginx is now able to cache responses
++with the "Vary" header line up to 128 characters long
++(instead of 42 characters in previous versions).
++
++
++
++
++
++параметр build директивы server_tokens.
++Спасибо Tom Thorogood.
++
++
++the "build" parameter of the "server_tokens" directive.
++Thanks to Tom Thorogood.
++
++
++
++
++
++при обработке запросов со строкой "Expect: 100-continue" в заголовке запроса
++в логах могли появляться сообщения "[crit] SSL_write() failed".
++
++
++"[crit] SSL_write() failed" messages might appear in logs
++when handling requests with the "Expect: 100-continue" request header line.
++
++
++
++
++
++модуль ngx_http_slice_module не работал в именованных location'ах.
++
++
++the ngx_http_slice_module did not work in named locations.
++
++
++
++
++
++при использовании AIO после перенаправления запроса с помощью X-Accel-Redirect
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when using AIO after an "X-Accel-Redirect" redirection.
++
++
++
++
++
++уменьшено потребление памяти для долгоживущих запросов, использующих сжатие.
++
++
++reduced memory consumption for long-lived requests using gzipping.
++
++
++
++
++
++
++
++
++
++
++при использовании модуля stream nginx мог нагружать процессор;
++ошибка появилась в 1.11.5.
++
++
++nginx might hog CPU when using the stream module;
++the bug had appeared in 1.11.5.
++
++
++
++
++
++метод аутентификации EXTERNAL в почтовом прокси-сервере
++можно было использовать, даже если он не был разрешён в конфигурации.
++
++
++EXTERNAL authentication mechanism in mail proxy
++was accepted even if it was not enabled in the configuration.
++
++
++
++
++
++при использовании директивы ssl_verify_client модуля stream
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if the "ssl_verify_client" directive of the stream module was used.
++
++
++
++
++
++директива ssl_verify_client модуля stream могла не работать.
++
++
++the "ssl_verify_client" directive of the stream module might not work.
++
++
++
++
++
++при исчерпании рабочим процессом свободных соединений
++keepalive-соединения могли закрываться излишне агрессивно.
++Спасибо Joel Cunningham.
++
++
++closing keepalive connections due to no free worker connections
++might be too aggressive.
++Thanks to Joel Cunningham.
++
++
++
++
++
++при использовании директивы sendfile на FreeBSD и macOS
++мог возвращаться некорректный ответ;
++ошибка появилась в 1.7.8.
++
++
++an incorrect response might be returned
++when using the "sendfile" directive on FreeBSD and macOS;
++the bug had appeared in 1.7.8.
++
++
++
++
++
++при использовании директивы aio_write
++ответ мог сохраняться в кэш не полностью.
++
++
++a truncated response might be stored in cache
++when using the "aio_write" directive.
++
++
++
++
++
++при использовании директивы aio_write
++могла происходить утечка сокетов.
++
++
++a socket leak might occur
++when using the "aio_write" directive.
++
++
++
++
++
++
++
++
++
++
++директива absolute_redirect.
++
++
++the "absolute_redirect" directive.
++
++
++
++
++
++параметр escape директивы log_format.
++
++
++the "escape" parameter of the "log_format" directive.
++
++
++
++
++
++проверка клиентских SSL-сертификатов в модуле stream.
++
++
++client SSL certificates verification in the stream module.
++
++
++
++
++
++директива ssl_session_ticket_key поддерживает
++шифрование TLS session tickets с помощью AES256
++при использовании с 80-байтными ключами.
++
++
++the "ssl_session_ticket_key" directive supports
++AES256 encryption of TLS session tickets
++when used with 80-byte keys.
++
++
++
++
++
++поддержка vim-commentary в скриптах для vim.
++Спасибо Armin Grodon.
++
++
++vim-commentary support in vim scripts.
++Thanks to Armin Grodon.
++
++
++
++
++
++рекурсия при получении значений переменных не ограничивалась.
++
++
++recursion when evaluating variables was not limited.
++
++
++
++
++
++в модуле ngx_stream_ssl_preread_module.
++
++
++in the ngx_stream_ssl_preread_module.
++
++
++
++
++
++если сервер, описанный в блоке upstream в модуле stream,
++был признан неработающим, то после истечения fail_timeout он
++признавался работающим только после завершения тестового соединения;
++теперь достаточно, чтобы соединение было успешно установлено.
++
++
++if a server in an upstream in the stream module failed,
++it was considered alive only when a test connection sent
++to it after fail_timeout was closed;
++now a successfully established connection is enough.
++
++
++
++
++
++nginx/Windows не собирался с 64-битным Visual Studio.
++
++
++nginx/Windows could not be built with 64-bit Visual Studio.
++
++
++
++
++
++nginx/Windows не собирался с OpenSSL 1.1.0.
++
++
++nginx/Windows could not be built with OpenSSL 1.1.0.
++
++
++
++
++
++
++
++
++
++
++переменная $ssl_client_verify теперь
++в случае ошибки проверки клиентского сертификата
++содержит строку с описанием ошибки,
++например, "FAILED:certificate has expired".
++
++
++now in case of a client certificate verification error
++the $ssl_client_verify variable contains a string with the failure reason,
++for example, "FAILED:certificate has expired".
++
++
++
++
++
++переменные $ssl_ciphers, $ssl_curves,
++$ssl_client_v_start, $ssl_client_v_end и $ssl_client_v_remain.
++
++
++the $ssl_ciphers, $ssl_curves,
++$ssl_client_v_start, $ssl_client_v_end, and $ssl_client_v_remain variables.
++
++
++
++
++
++параметр volatile директивы map.
++
++
++the "volatile" parameter of the "map" directive.
++
++
++
++
++
++при сборке динамических модулей
++не учитывались заданные для модуля зависимости.
++
++
++dependencies specified for a module
++were ignored while building dynamic modules.
++
++
++
++
++
++при использовании HTTP/2 и директив limit_req или auth_request
++тело запроса могло быть повреждено;
++ошибка появилась в 1.11.0.
++
++
++when using HTTP/2 and the "limit_req" or "auth_request" directives
++client request body might be corrupted;
++the bug had appeared in 1.11.0.
++
++
++
++
++
++при использовании HTTP/2 в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.11.3.
++
++
++a segmentation fault might occur in a worker process when using HTTP/2;
++the bug had appeared in 1.11.3.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++Спасибо Congcong Hu.
++
++
++in the ngx_http_mp4_module.
++Thanks to Congcong Hu.
++
++
++
++
++
++в модуле ngx_http_perl_module.
++
++
++in the ngx_http_perl_module.
++
++
++
++
++
++
++
++
++
++
++формат переменных $ssl_client_s_dn и $ssl_client_i_dn
++изменён на соответствующий RFC 2253 (RFC 4514);
++значения в старом формате доступны через переменные
++$ssl_client_s_dn_legacy и $ssl_client_i_dn_legacy.
++
++
++format of the $ssl_client_s_dn and $ssl_client_i_dn variables
++has been changed to follow RFC 2253 (RFC 4514);
++values in the old format are available in
++the $ssl_client_s_dn_legacy and $ssl_client_i_dn_legacy variables.
++
++
++
++
++
++при сохранении временных файлов в каталоге кэша
++они теперь располагаются не в отдельном подкаталоге для временных файлов,
++а в том же подкаталоге, что и соответствующие файлы в кэше.
++
++
++when storing temporary files in a cache directory
++they will be stored in the same subdirectories as corresponding cache files
++instead of a separate subdirectory for temporary files.
++
++
++
++
++
++поддержка метода аутентификации EXTERNAL
++в почтовом прокси-сервере.
++Спасибо Robert Norris.
++
++
++EXTERNAL authentication mechanism support
++in mail proxy.
++Thanks to Robert Norris.
++
++
++
++
++
++поддержка WebP в модуле ngx_http_image_filter_module.
++
++
++WebP support in the ngx_http_image_filter_module.
++
++
++
++
++
++директива proxy_method поддерживает переменные.
++Спасибо Дмитрию Лазуркину.
++
++
++variables support in the "proxy_method" directive.
++Thanks to Dmitry Lazurkin.
++
++
++
++
++
++директива http2_max_requests в модуле ngx_http_v2_module.
++
++
++the "http2_max_requests" directive in the ngx_http_v2_module.
++
++
++
++
++
++директивы proxy_cache_max_range_offset, fastcgi_cache_max_range_offset,
++scgi_cache_max_range_offset и uwsgi_cache_max_range_offset.
++
++
++the "proxy_cache_max_range_offset", "fastcgi_cache_max_range_offset",
++"scgi_cache_max_range_offset", and "uwsgi_cache_max_range_offset" directives.
++
++
++
++
++
++плавное завершение старых рабочих процессов могло занимать бесконечное время
++при использовании HTTP/2.
++
++
++graceful shutdown of old worker processes might require infinite time
++when using HTTP/2.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++при проксировании WebSocket-соединений и включённом кэшировании
++в логах могли появляться сообщения "ignore long locked inactive cache entry".
++
++
++"ignore long locked inactive cache entry" alerts might appear in logs
++when proxying WebSocket connections with caching enabled.
++
++
++
++
++
++если во время SSL handshake с бэкендом происходил таймаут,
++nginx ничего не писал в лог
++и возвращал ответ с кодом 502 вместо 504.
++
++
++nginx did not write anything to log
++and returned a response with code 502 instead of 504
++when a timeout occurred during an SSL handshake to a backend.
++
++
++
++
++
++
++
++
++
++
++параметр configure --with-ipv6 упразднён,
++поддержка IPv6 теперь собирается автоматически.
++
++
++the --with-ipv6 configure option was removed,
++now IPv6 support is configured automatically.
++
++
++
++
++
++теперь, если в блоке upstream не оказалось доступных серверов,
++nginx не сбрасывает статистику ошибок всех серверов, как делал ранее,
++а ожидает истечения fail_timeout.
++
++
++now if there are no available servers in an upstream,
++nginx will not reset number of failures of all servers as it previously did,
++but will wait for fail_timeout to expire.
++
++
++
++
++
++модуль ngx_stream_ssl_preread_module.
++
++
++the ngx_stream_ssl_preread_module.
++
++
++
++
++
++директива server в блоке upstream поддерживает параметр max_conns.
++
++
++the "server" directive in the "upstream" context supports
++the "max_conns" parameter.
++
++
++
++
++
++параметр configure --with-compat.
++
++
++the --with-compat configure option.
++
++
++
++
++
++параметры manager_files, manager_threshold и manager_sleep
++директив proxy_cache_path, fastcgi_cache_path, scgi_cache_path и
++uwsgi_cache_path.
++
++
++"manager_files", "manager_threshold", and "manager_sleep" parameters
++of the "proxy_cache_path", "fastcgi_cache_path", "scgi_cache_path", and
++"uwsgi_cache_path" directives.
++
++
++
++
++
++при сборке perl-модуля не использовались флаги,
++заданные с помощью параметра configure --with-ld-opt.
++
++
++flags passed by the --with-ld-opt configure option
++were not used while building perl module.
++
++
++
++
++
++в директиве add_after_body при использовании совместно с директивой sub_filter.
++
++
++in the "add_after_body" directive when used with the "sub_filter" directive.
++
++
++
++
++
++в переменной $realip_remote_addr.
++
++
++in the $realip_remote_addr variable.
++
++
++
++
++
++директивы dav_access, proxy_store_access, fastcgi_store_access,
++scgi_store_access и uwsgi_store_access
++игнорировали права, заданные для пользователя.
++
++
++the "dav_access", "proxy_store_access", "fastcgi_store_access",
++"scgi_store_access", and "uwsgi_store_access" directives
++ignored permissions specified for user.
++
++
++
++
++
++unix domain listen-сокеты могли не наследоваться
++при обновлении исполняемого файла на Linux.
++
++
++unix domain listen sockets might not be inherited
++during binary upgrade on Linux.
++
++
++
++
++
++nginx возвращал ошибку 400 на запросы
++с символом "-" в HTTP-методе.
++
++
++nginx returned the 400 response on requests
++with the "-" character in the HTTP method.
++
++
++
++
++
++
++
++
++
++
++переменная $upstream_bytes_received.
++
++
++the $upstream_bytes_received variable.
++
++
++
++
++
++переменные $bytes_received, $session_time, $protocol, $status,
++$upstream_addr, $upstream_bytes_sent, $upstream_bytes_received,
++$upstream_connect_time, $upstream_first_byte_time
++и $upstream_session_time в модуле stream.
++
++
++the $bytes_received, $session_time, $protocol, $status,
++$upstream_addr, $upstream_bytes_sent, $upstream_bytes_received,
++$upstream_connect_time, $upstream_first_byte_time,
++and $upstream_session_time variables in the stream module.
++
++
++
++
++
++модуль ngx_stream_log_module.
++
++
++the ngx_stream_log_module.
++
++
++
++
++
++параметр proxy_protocol в директиве listen,
++переменные $proxy_protocol_addr и $proxy_protocol_port
++в модуле stream.
++
++
++the "proxy_protocol" parameter of the "listen" directive,
++the $proxy_protocol_addr and $proxy_protocol_port variables
++in the stream module.
++
++
++
++
++
++модуль ngx_stream_realip_module.
++
++
++the ngx_stream_realip_module.
++
++
++
++
++
++nginx не собирался с модулем stream и модулем ngx_http_ssl_module,
++но без модуля ngx_stream_ssl_module;
++ошибка появилась в 1.11.3.
++
++
++nginx could not be built with the stream module and the ngx_http_ssl_module,
++but without ngx_stream_ssl_module;
++the bug had appeared in 1.11.3.
++
++
++
++
++
++опция сокета IP_BIND_ADDRESS_NO_PORT не использовалась;
++ошибка появилась в 1.11.2.
++
++
++the IP_BIND_ADDRESS_NO_PORT socket option was not used;
++the bug had appeared in 1.11.2.
++
++
++
++
++
++в параметре ranges директивы geo.
++
++
++in the "ranges" parameter of the "geo" directive.
++
++
++
++
++
++при использовании директив "aio threads" и sendfile
++мог возвращаться некорректный ответ; ошибка появилась в 1.9.13.
++
++
++an incorrect response might be returned
++when using the "aio threads" and "sendfile" directives;
++the bug had appeared in 1.9.13.
++
++
++
++
++
++
++
++
++
++
++теперь accept_mutex по умолчанию выключен.
++
++
++now the "accept_mutex" directive is turned off by default.
++
++
++
++
++
++теперь nginx использует EPOLLEXCLUSIVE на Linux.
++
++
++now nginx uses EPOLLEXCLUSIVE on Linux.
++
++
++
++
++
++модуль ngx_stream_geo_module.
++
++
++the ngx_stream_geo_module.
++
++
++
++
++
++модуль ngx_stream_geoip_module.
++
++
++the ngx_stream_geoip_module.
++
++
++
++
++
++модуль ngx_stream_split_clients_module.
++
++
++the ngx_stream_split_clients_module.
++
++
++
++
++
++директивы proxy_pass и proxy_ssl_name в модуле stream
++поддерживают переменные.
++
++
++variables support
++in the "proxy_pass" and "proxy_ssl_name" directives in the stream module.
++
++
++
++
++
++утечки сокетов при использовании HTTP/2.
++
++
++socket leak when using HTTP/2.
++
++
++
++
++
++в configure.
++Спасибо Piotr Sikora.
++
++
++in configure tests.
++Thanks to Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++теперь nginx всегда использует внутренние реализации MD5 и SHA1;
++параметры configure --with-md5 и --with-sha1 упразднены.
++
++
++now nginx always uses internal MD5 and SHA1 implementations;
++the --with-md5 and --with-sha1 configure options were canceled.
++
++
++
++
++
++поддержка переменных в модуле stream.
++
++
++variables support in the stream module.
++
++
++
++
++
++модуль ngx_stream_map_module.
++
++
++the ngx_stream_map_module.
++
++
++
++
++
++модуль ngx_stream_return_module.
++
++
++the ngx_stream_return_module.
++
++
++
++
++
++в директивах proxy_bind, fastcgi_bind, memcached_bind, scgi_bind и uwsgi_bind
++теперь можно указывать порт.
++
++
++a port can be specified in the "proxy_bind", "fastcgi_bind",
++"memcached_bind", "scgi_bind", and "uwsgi_bind" directives.
++
++
++
++
++
++теперь nginx использует опцию сокета IP_BIND_ADDRESS_NO_PORT, если она доступна.
++
++
++now nginx uses the IP_BIND_ADDRESS_NO_PORT socket option when available.
++
++
++
++
++
++при использовании HTTP/2 и директивы proxy_request_buffering
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when using HTTP/2 and the "proxy_request_buffering" directive.
++
++
++
++
++
++при использовании HTTP/2
++к запросам, передаваемым на бэкенд,
++всегда добавлялась строка заголовка "Content-Length",
++даже если у запроса не было тела.
++
++
++the "Content-Length" request header line
++was always added to requests passed to backends,
++including requests without body,
++when using HTTP/2.
++
++
++
++
++
++при использовании HTTP/2
++в логах могли появляться сообщения "http request count is zero".
++
++
++"http request count is zero" alerts might appear in logs
++when using HTTP/2.
++
++
++
++
++
++при использовании директивы sub_filter
++могло буферизироваться больше данных, чем это необходимо;
++проблема появилась в 1.9.4.
++
++
++unnecessary buffering might occur
++when using the "sub_filter" directive;
++the issue had appeared in 1.9.4.
++
++
++
++
++
++
++
++
++
++
++при записи тела специально созданного запроса во временный файл
++в рабочем процессе мог происходить segmentation fault
++(CVE-2016-4450);
++ошибка появилась в 1.3.9.
++
++
++a segmentation fault might occur in a worker process
++while writing a specially crafted request body to a temporary file
++(CVE-2016-4450);
++the bug had appeared in 1.3.9.
++
++
++
++
++
++
++
++
++
++
++параметр transparent директив proxy_bind, fastcgi_bind,
++memcached_bind, scgi_bind и uwsgi_bind.
++
++
++the "transparent" parameter of the "proxy_bind", "fastcgi_bind",
++"memcached_bind", "scgi_bind", and "uwsgi_bind" directives.
++
++
++
++
++
++переменная $request_id.
++
++
++the $request_id variable.
++
++
++
++
++
++директива map поддерживает комбинации нескольких переменных
++в качестве результирующих значений.
++
++
++the "map" directive supports combinations of multiple variables
++as resulting values.
++
++
++
++
++
++теперь при использовании метода epoll
++nginx проверяет, поддерживает ли ядро события EPOLLRDHUP,
++и соответственно оптимизирует обработку соединений.
++
++
++now nginx checks if EPOLLRDHUP events are supported by kernel,
++and optimizes connection handling accordingly
++if the "epoll" method is used.
++
++
++
++
++
++директивы ssl_certificate и ssl_certificate_key
++теперь можно указывать несколько раз
++для загрузки сертификатов разных типов (например, RSA и ECDSA).
++
++
++the "ssl_certificate" and "ssl_certificate_key" directives
++can be specified multiple times
++to load certificates of different types (for example, RSA and ECDSA).
++
++
++
++
++
++при использовании OpenSSL 1.0.2 и новее
++с помощью директивы ssl_ecdh_curve теперь можно задать список кривых;
++по умолчанию используется встроенный в OpenSSL список кривых.
++
++
++the "ssl_ecdh_curve" directive now allows specifying a list of curves
++when using OpenSSL 1.0.2 or newer;
++by default a list built into OpenSSL is used.
++
++
++
++
++
++для использования DHE-шифров теперь надо явно задавать файл параметров
++с помощью директивы ssl_dhparam.
++
++
++to use DHE ciphers it is now required to specify parameters
++using the "ssl_dhparam" directive.
++
++
++
++
++
++переменная $proxy_protocol_port.
++
++
++the $proxy_protocol_port variable.
++
++
++
++
++
++переменная $realip_remote_port в модуле ngx_http_realip_module.
++
++
++the $realip_remote_port variable in the ngx_http_realip_module.
++
++
++
++
++
++модуль ngx_http_realip_module теперь позволяет устанавливать
++не только адрес, но и порт клиента.
++
++
++the ngx_http_realip_module is now able to set the client port
++in addition to the address.
++
++
++
++
++
++при попытке запросить виртуальный сервер,
++отличающийся от согласованного в процессе SSL handshake,
++теперь возвращается ответ "421 Misdirected Request";
++это улучшает совместимость с некоторыми HTTP/2-клиентами
++в случае использования клиентских сертификатов.
++
++
++the "421 Misdirected Request" response now used
++when rejecting requests to a virtual server
++different from one negotiated during an SSL handshake;
++this improves interoperability with some HTTP/2 clients
++when using client certificates.
++
++
++
++
++
++HTTP/2-клиенты теперь могут сразу присылать тело запроса;
++директива http2_body_preread_size позволяет указать размер буфера, который
++будет использоваться до того, как nginx начнёт читать тело.
++
++
++HTTP/2 clients can now start sending request body immediately;
++the "http2_body_preread_size" directive controls size of the buffer used
++before nginx will start reading client request body.
++
++
++
++
++
++при использовании директивы proxy_cache_bypass
++не обновлялись закэшированные ошибочные ответы.
++
++
++cached error responses were not updated
++when using the "proxy_cache_bypass" directive.
++
++
++
++
++
++
++
++
++
++
++при использовании HHVM в качестве FastCGI-сервера
++могли возникать ошибки "recv() failed".
++
++
++"recv() failed" errors might occur
++when using HHVM as a FastCGI server.
++
++
++
++
++
++при использовании HTTP/2 и директив limit_req или auth_request
++при чтении тела запроса мог произойти таймаут
++или ошибка "client violated flow control";
++ошибка появилась в 1.9.14.
++
++
++when using HTTP/2 and the "limit_req" or "auth_request" directives
++a timeout or a "client violated flow control" error
++might occur while reading client request body;
++the bug had appeared in 1.9.14.
++
++
++
++
++
++при использовании HTTP/2 ответ мог не показываться некоторыми браузерами,
++если тело запроса было прочитано не целиком;
++ошибка появилась в 1.9.14.
++
++
++a response might not be shown by some browsers
++if HTTP/2 was used and client request body was not fully read;
++the bug had appeared in 1.9.14.
++
++
++
++
++
++при использовании директивы "aio threads" соединения могли зависать.
++Спасибо Mindaugas Rasiukevicius.
++
++
++connections might hang when using the "aio threads" directive.
++Thanks to Mindaugas Rasiukevicius.
++
++
++
++
++
++
++
++
++
++
++совместимость с OpenSSL 1.1.0.
++
++
++OpenSSL 1.1.0 compatibility.
++
++
++
++
++
++директивы proxy_request_buffering, fastcgi_request_buffering,
++scgi_request_buffering и uwsgi_request_buffering
++теперь работают при использовании HTTP/2.
++
++
++the "proxy_request_buffering", "fastcgi_request_buffering",
++"scgi_request_buffering", and "uwsgi_request_buffering" directives
++now work with HTTP/2.
++
++
++
++
++
++при использовании HTTP/2
++в логах могли появляться сообщения "zero size buf in output".
++
++
++"zero size buf in output" alerts might appear in logs
++when using HTTP/2.
++
++
++
++
++
++при использовании HTTP/2
++директива client_max_body_size могла работать неверно.
++
++
++the "client_max_body_size" directive might work incorrectly
++when using HTTP/2.
++
++
++
++
++
++незначительных ошибок логгирования.
++
++
++of minor bugs in logging.
++
++
++
++
++
++
++
++
++
++
++неидемпотентные запросы (POST, LOCK, PATCH)
++теперь по умолчанию не передаются на другой сервер,
++если запрос уже был отправлен на бэкенд;
++параметр non_idempotent директивы proxy_next_upstream
++явно разрешает повторять такие запросы.
++
++
++non-idempotent requests (POST, LOCK, PATCH)
++are no longer passed to the next server by default
++if a request has been sent to a backend;
++the "non_idempotent" parameter of the "proxy_next_upstream" directive
++explicitly allows retrying such requests.
++
++
++
++
++
++модуль ngx_http_perl_module теперь можно собрать динамически.
++
++
++the ngx_http_perl_module can be built dynamically.
++
++
++
++
++
++поддержка UDP в модуле stream.
++
++
++UDP support in the stream module.
++
++
++
++
++
++директива aio_write.
++
++
++the "aio_write" directive.
++
++
++
++
++
++теперь cache manager следит за количеством элементов в кэше
++и старается не допускать переполнений зоны разделяемой памяти.
++
++
++now cache manager monitors number of elements in caches
++and tries to avoid cache keys zone overflows.
++
++
++
++
++
++при использовании директив sendfile и aio с подзапросами
++в логах могли появляться сообщения "task already active" и "second aio post".
++
++
++"task already active" and "second aio post" alerts might appear in logs
++when using the "sendfile" and "aio" directives with subrequests.
++
++
++
++
++
++при использовании кэширования
++в логах могли появляться сообщения "zero size buf in output",
++если клиент закрывал соединение преждевременно.
++
++
++"zero size buf in output" alerts might appear in logs
++if caching was used
++and a client closed a connection prematurely.
++
++
++
++
++
++при использовании кэширования
++соединения с клиентами могли закрываться без необходимости.
++Спасибо Justin Li.
++
++
++connections with clients might be closed needlessly
++if caching was used.
++Thanks to Justin Li.
++
++
++
++
++
++nginx мог нагружать процессор
++при использовании директивы sendfile на Linux и Solaris,
++если отправляемый файл был изменён в процессе отправки.
++
++
++nginx might hog CPU
++if the "sendfile" directive was used on Linux or Solaris
++and a file being sent was changed during sending.
++
++
++
++
++
++при использовании директив sendfile и "aio threads"
++соединения могли зависать.
++
++
++connections might hang
++when using the "sendfile" and "aio threads" directives.
++
++
++
++
++
++в директивах proxy_pass, fastcgi_pass, scgi_pass и uwsgi_pass
++при использовании переменных.
++Спасибо Piotr Sikora.
++
++
++in the "proxy_pass", "fastcgi_pass", "scgi_pass", and "uwsgi_pass" directives
++when using variables.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в модуле ngx_http_sub_filter_module.
++
++
++in the ngx_http_sub_filter_module.
++
++
++
++
++
++если в закэшированном соединении к бэкенду происходила ошибка,
++запрос передавался на другой сервер
++без учёта директивы proxy_next_upstream.
++
++
++if an error occurred in a cached backend connection,
++the request was passed to the next server
++regardless of the proxy_next_upstream directive.
++
++
++
++
++
++ошибки "CreateFile() failed" при создании временных файлов на Windows.
++
++
++"CreateFile() failed" errors when creating temporary files on Windows.
++
++
++
++
++
++
++
++
++
++
++кодирование Хаффмана заголовков ответов в HTTP/2.
++Спасибо Владу Краснову.
++
++
++Huffman encoding of response headers in HTTP/2.
++Thanks to Vlad Krasnov.
++
++
++
++
++
++директива worker_cpu_affinity теперь поддерживает более 64 процессоров.
++
++
++the "worker_cpu_affinity" directive now supports more than 64 CPUs.
++
++
++
++
++
++совместимость со сторонними модулями на C++;
++ошибка появилась в 1.9.11.
++Спасибо Piotr Sikora.
++
++
++compatibility with 3rd party C++ modules;
++the bug had appeared in 1.9.11.
++Thanks to Piotr Sikora.
++
++
++
++
++
++nginx не собирался статически с OpenSSL на Linux;
++ошибка появилась в 1.9.11.
++
++
++nginx could not be built statically with OpenSSL on Linux;
++the bug had appeared in 1.9.11.
++
++
++
++
++
++директива "add_header ... always" с пустым значением
++не удаляла из заголовков ошибочных ответов
++строки Last-Modified и ETag.
++
++
++the "add_header ... always" directive with an empty value
++did not delete "Last-Modified" and "ETag" header lines
++from error responses.
++
++
++
++
++
++при использовании OpenSSL 1.0.2f в логах могли появляться
++сообщения "called a function you should not call" и
++"shutdown while in init".
++
++
++"called a function you should not call"
++and "shutdown while in init" messages might appear in logs
++when using OpenSSL 1.0.2f.
++
++
++
++
++
++ошибочные заголовки могли логгироваться некорректно.
++
++
++invalid headers might be logged incorrectly.
++
++
++
++
++
++утечки сокетов при использовании HTTP/2.
++
++
++socket leak when using HTTP/2.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++
++
++in the ngx_http_v2_module.
++
++
++
++
++
++
++
++
++
++
++теперь resolver поддерживает TCP.
++
++
++TCP support in resolver.
++
++
++
++
++
++динамические модули.
++
++
++dynamic modules.
++
++
++
++
++
++при использовании HTTP/2
++переменная $request_length не учитывала размер заголовков запроса.
++
++
++the $request_length variable did not include size of request headers
++when using HTTP/2.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++
++
++in the ngx_http_v2_module.
++
++
++
++
++
++
++
++
++
++
++при использовании директивы resolver
++во время обработки ответов DNS-сервера
++могло происходить разыменование некорректного адреса,
++что позволяло атакующему,
++имеющему возможность подделывать UDP-пакеты от DNS-сервера,
++вызвать segmentation fault в рабочем процессе (CVE-2016-0742).
++
++
++invalid pointer dereference might occur
++during DNS server response processing
++if the "resolver" directive was used,
++allowing an attacker who is able to forge UDP packets from the DNS server
++to cause segmentation fault in a worker process (CVE-2016-0742).
++
++
++
++
++
++при использовании директивы resolver
++во время обработки CNAME-записей
++могло произойти обращение к ранее освобождённой памяти,
++что позволяло атакующему,
++имеющему возможность инициировать преобразование произвольных имён в адреса,
++вызвать segmentation fault в рабочем процессе,
++а также потенциально могло иметь другие последствия (CVE-2016-0746).
++
++
++use-after-free condition might occur
++during CNAME response processing
++if the "resolver" directive was used,
++allowing an attacker who is able to trigger name resolution
++to cause segmentation fault in a worker process,
++or might have potential other impact (CVE-2016-0746).
++
++
++
++
++
++при использовании директивы resolver
++во время обработки CNAME-записей
++не во всех случаях проверялось ограничение
++на максимальное количество записей в цепочке,
++что позволяло атакующему,
++имеющему возможность инициировать преобразование произвольных имён в адреса,
++вызвать чрезмерное потребление ресурсов рабочими процессами (CVE-2016-0747).
++
++
++CNAME resolution was insufficiently limited
++if the "resolver" directive was used,
++allowing an attacker who is able to trigger arbitrary name resolution
++to cause excessive resource consumption in worker processes (CVE-2016-0747).
++
++
++
++
++
++параметр auto директивы worker_cpu_affinity.
++
++
++the "auto" parameter of the "worker_cpu_affinity" directive.
++
++
++
++
++
++параметр proxy_protocol директивы listen не работал
++с IPv6 listen-сокетами.
++
++
++the "proxy_protocol" parameter of the "listen" directive did not work
++with IPv6 listen sockets.
++
++
++
++
++
++при использовании директивы keepalive
++соединения к бэкендам могли кэшироваться некорректно.
++
++
++connections to upstream servers might be cached incorrectly
++when using the "keepalive" directive.
++
++
++
++
++
++после перенаправления запроса с помощью X-Accel-Redirect
++при проксировании использовался HTTP-метод оригинального запроса.
++
++
++proxying used the HTTP method of the original request
++after an "X-Accel-Redirect" redirection.
++
++
++
++
++
++
++
++
++
++
++проксирование в unix domain сокеты не работало при использовании переменных;
++ошибка появилась в 1.9.8.
++
++
++proxying to unix domain sockets did not work when using variables;
++the bug had appeared in 1.9.8.
++
++
++
++
++
++
++
++
++
++
++поддержка pwritev().
++
++
++pwritev() support.
++
++
++
++
++
++директива include в блоке upstream.
++
++
++the "include" directive inside the "upstream" block.
++
++
++
++
++
++модуль ngx_http_slice_module.
++
++
++the ngx_http_slice_module.
++
++
++
++
++
++при использовании LibreSSL
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.9.6.
++
++
++a segmentation fault might occur in a worker process
++when using LibreSSL;
++the bug had appeared in 1.9.6.
++
++
++
++
++
++nginx мог не собираться на OS X.
++
++
++nginx could not be built on OS X in some cases.
++
++
++
++
++
++
++
++
++
++
++параметр nohostname логгирования в syslog.
++
++
++the "nohostname" parameter of logging to syslog.
++
++
++
++
++
++директива proxy_cache_convert_head.
++
++
++the "proxy_cache_convert_head" directive.
++
++
++
++
++
++переменная $realip_remote_addr в модуле ngx_http_realip_module.
++
++
++the $realip_remote_addr variable in the ngx_http_realip_module.
++
++
++
++
++
++директива expires могла не срабатывать при использовании переменных.
++
++
++the "expires" directive might not work when using variables.
++
++
++
++
++
++при использовании HTTP/2
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.9.6.
++
++
++a segmentation fault might occur in a worker process
++when using HTTP/2;
++the bug had appeared in 1.9.6.
++
++
++
++
++
++если nginx был собран с модулем ngx_http_v2_module,
++протокол HTTP/2 мог быть использован клиентом,
++даже если не был указан параметр http2 директивы listen.
++
++
++if nginx was built with the ngx_http_v2_module
++it was possible to use the HTTP/2 protocol
++even if the "http2" parameter of the "listen" directive was not specified.
++
++
++
++
++
++в модуле ngx_http_v2_module.
++
++
++in the ngx_http_v2_module.
++
++
++
++
++
++
++
++
++
++
++при использовании HTTP/2
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Piotr Sikora и Denis Andzakovic.
++
++
++a segmentation fault might occur in a worker process
++when using HTTP/2.
++Thanks to Piotr Sikora and Denis Andzakovic.
++
++
++
++
++
++при использовании HTTP/2 переменная $server_protocol была пустой.
++
++
++the $server_protocol variable was empty when using HTTP/2.
++
++
++
++
++
++SSL-соединения к бэкендам в модуле stream
++могли неожиданно завершаться по таймауту.
++
++
++backend SSL connections in the stream module
++might be timed out unexpectedly.
++
++
++
++
++
++при использовании различных настроек ssl_session_cache
++в разных виртуальных серверах
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if different ssl_session_cache settings were used
++in different virtual servers.
++
++
++
++
++
++nginx/Windows не собирался с MinGW gcc;
++ошибка появилась в 1.9.4.
++Спасибо Kouhei Sutou.
++
++
++nginx/Windows could not be built with MinGW gcc;
++the bug had appeared in 1.9.4.
++Thanks to Kouhei Sutou.
++
++
++
++
++
++при использовании директивы timer_resolution на Windows время не обновлялось.
++
++
++time was not updated when the timer_resolution directive was used on Windows.
++
++
++
++
++
++Незначительные исправления и улучшения.
++Спасибо Markus Linnala, Kurtis Nusbaum и Piotr Sikora.
++
++
++Miscellaneous minor fixes and improvements.
++Thanks to Markus Linnala, Kurtis Nusbaum and Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_v2_module (заменяет модуль ngx_http_spdy_module).
++Спасибо Dropbox и Automattic за спонсирование разработки.
++
++
++the ngx_http_v2_module (replaces ngx_http_spdy_module).
++Thanks to Dropbox and Automattic for sponsoring this work.
++
++
++
++
++
++теперь по умолчанию директива output_buffers использует два буфера.
++
++
++now the "output_buffers" directive uses two buffers by default.
++
++
++
++
++
++теперь nginx ограничивает максимальную вложенность подзапросов,
++а не количество одновременных подзапросов.
++
++
++now nginx limits subrequests recursion,
++not simultaneous subrequests.
++
++
++
++
++
++теперь при возврате ответов из кэша nginx проверяет ключ полностью.
++Спасибо Геннадию Махомеду и Сергею Брестеру.
++
++
++now nginx checks the whole cache key when returning a response from cache.
++Thanks to Gena Makhomed and Sergey Brester.
++
++
++
++
++
++при использовании кэша
++в логах могли появляться сообщения "header already sent";
++ошибка появилась в 1.7.5.
++
++
++"header already sent" alerts might appear in logs
++when using cache;
++the bug had appeared in 1.7.5.
++
++
++
++
++
++при использовании CephFS и директивы timer_resolution на Linux
++в логах могли появляться сообщения
++"writev() failed (4: Interrupted system call)".
++
++
++"writev() failed (4: Interrupted system call)"
++errors might appear in logs
++when using CephFS and the "timer_resolution" directive on Linux.
++
++
++
++
++
++в обработке ошибок конфигурации.
++Спасибо Markus Linnala.
++
++
++in invalid configurations handling.
++Thanks to Markus Linnala.
++
++
++
++
++
++при использовании директивы sub_filter на уровне http
++в рабочем процессе происходил segmentation fault;
++ошибка появилась в 1.9.4.
++
++
++a segmentation fault occurred in a worker process
++if the "sub_filter" directive was used at http level;
++the bug had appeared in 1.9.4.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_downstream_buffer и proxy_upstream_buffer в модуле stream
++заменены директивой proxy_buffer_size.
++
++
++the "proxy_downstream_buffer" and "proxy_upstream_buffer" directives
++of the stream module are replaced with the "proxy_buffer_size" directive.
++
++
++
++
++
++директива tcp_nodelay в модуле stream.
++
++
++the "tcp_nodelay" directive in the stream module.
++
++
++
++
++
++теперь можно указать несколько директив sub_filter одновременно.
++
++
++multiple "sub_filter" directives can be used simultaneously.
++
++
++
++
++
++директива sub_filter поддерживает переменные в строке поиска.
++
++
++variables support in the search string of the "sub_filter" directive.
++
++
++
++
++
++тестирование конфигурации могло не работать под Linux OpenVZ.
++Спасибо Геннадию Махомеду.
++
++
++configuration testing might fail under Linux OpenVZ.
++Thanks to Gena Makhomed.
++
++
++
++
++
++после переконфигурации старые рабочие процессы могли сильно нагружать процессор
++при больших значениях worker_connections.
++
++
++old worker processes might hog CPU after reconfiguration
++with a large number of worker_connections.
++
++
++
++
++
++при совместном использовании директив try_files и alias
++внутри location'а, заданного регулярным выражением,
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.7.1.
++
++
++a segmentation fault might occur in a worker process
++if the "try_files" and "alias" directives were used
++inside a location given by a regular expression;
++the bug had appeared in 1.7.1.
++
++
++
++
++
++директива try_files внутри вложенного location'а, заданного регулярным
++выражением, работала неправильно, если во внешнем location'е использовалась
++директива alias.
++
++
++the "try_files" directive inside a nested location
++given by a regular expression worked incorrectly
++if the "alias" directive was used in the outer location.
++
++
++
++
++
++в обработке ошибок при построении хэш-таблиц.
++
++
++in hash table initialization error handling.
++
++
++
++
++
++nginx не собирался с Visual Studio 2015.
++
++
++nginx could not be built with Visual Studio 2015.
++
++
++
++
++
++
++
++
++
++
++дублирующиеся блоки http, mail и stream теперь запрещены.
++
++
++duplicate "http", "mail", and "stream" blocks are now disallowed.
++
++
++
++
++
++ограничение количества соединений в модуле stream.
++
++
++connection limiting in the stream module.
++
++
++
++
++
++ограничение скорости в модуле stream.
++
++
++data rate limiting in the stream module.
++
++
++
++
++
++директива zone в блоке upstream не работала на Windows.
++
++
++the "zone" directive inside the "upstream" block did not work on Windows.
++
++
++
++
++
++совместимость с LibreSSL в модуле stream.
++Спасибо Piotr Sikora.
++
++
++compatibility with LibreSSL in the stream module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в параметре --builddir в configure.
++Спасибо Piotr Sikora.
++
++
++in the "--builddir" configure parameter.
++Thanks to Piotr Sikora.
++
++
++
++
++
++директива ssl_stapling_file не работала;
++ошибка появилась в 1.9.2.
++Спасибо Faidon Liambotis и Brandon Black.
++
++
++the "ssl_stapling_file" directive did not work;
++the bug had appeared in 1.9.2.
++Thanks to Faidon Liambotis and Brandon Black.
++
++
++
++
++
++при использовании директивы ssl_stapling
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 1.9.2.
++Спасибо Matthew Baldwin.
++
++
++a segmentation fault might occur in a worker process
++if the "ssl_stapling" directive was used;
++the bug had appeared in 1.9.2.
++Thanks to Matthew Baldwin.
++
++
++
++
++
++
++
++
++
++
++параметр backlog директивы listen
++в почтовом прокси-сервере и модуле stream.
++
++
++the "backlog" parameter of the "listen" directives
++of the mail proxy and stream modules.
++
++
++
++
++
++директивы allow и deny в модуле stream.
++
++
++the "allow" and "deny" directives in the stream module.
++
++
++
++
++
++директива proxy_bind в модуле stream.
++
++
++the "proxy_bind" directive in the stream module.
++
++
++
++
++
++директива proxy_protocol в модуле stream.
++
++
++the "proxy_protocol" directive in the stream module.
++
++
++
++
++
++ключ -T.
++
++
++the -T switch.
++
++
++
++
++
++параметр REQUEST_SCHEME добавлен в стандартные конфигурационные файлы
++fastcgi.conf, fastcgi_params, scgi_params и uwsgi_params.
++
++
++the REQUEST_SCHEME parameter added to the fastcgi.conf, fastcgi_params,
++scgi_params, and uwsgi_params standard configuration files.
++
++
++
++
++
++параметр reuseport директивы listen в модуле stream
++не работал.
++
++
++the "reuseport" parameter of the "listen" directive of the stream module
++did not work.
++
++
++
++
++
++OCSP stapling в некоторых случаях мог вернуть устаревший OCSP-ответ.
++
++
++OCSP stapling might return an expired OCSP response in some cases.
++
++
++
++
++
++
++
++
++
++
++теперь протокол SSLv3 по умолчанию запрещён.
++
++
++now SSLv3 protocol is disabled by default.
++
++
++
++
++
++некоторые давно устаревшие директивы больше не поддерживаются.
++
++
++some long deprecated directives are not supported anymore.
++
++
++
++
++
++параметр reuseport директивы listen.
++Спасибо Yingqi Lu из Intel и Sepherosa Ziehau.
++
++
++the "reuseport" parameter of the "listen" directive.
++Thanks to Yingqi Lu at Intel and Sepherosa Ziehau.
++
++
++
++
++
++переменная $upstream_connect_time.
++
++
++the $upstream_connect_time variable.
++
++
++
++
++
++в директиве hash на big-endian платформах.
++
++
++in the "hash" directive on big-endian platforms.
++
++
++
++
++
++nginx мог не запускаться на некоторых старых версиях Linux;
++ошибка появилась в 1.7.11.
++
++
++nginx might fail to start on some old Linux variants;
++the bug had appeared in 1.7.11.
++
++
++
++
++
++в парсинге IP-адресов.
++Спасибо Сергею Половко.
++
++
++in IP address parsing.
++Thanks to Sergey Polovko.
++
++
++
++
++
++
++
++
++
++
++устаревшие методы обработки соединений aio и rtsig больше не поддерживаются.
++
++
++obsolete aio and rtsig event methods have been removed.
++
++
++
++
++
++директива zone в блоке upstream.
++
++
++the "zone" directive inside the "upstream" block.
++
++
++
++
++
++модуль stream.
++
++
++the stream module.
++
++
++
++
++
++поддержка byte ranges для ответов модуля ngx_http_memcached_module.
++Спасибо Martin Mlynář.
++
++
++byte ranges support in the ngx_http_memcached_module.
++Thanks to Martin Mlynář.
++
++
++
++
++
++разделяемую память теперь можно использовать на версиях Windows
++с рандомизацией адресного пространства.
++Спасибо Сергею Брестеру.
++
++
++shared memory can now be used on Windows versions
++with address space layout randomization.
++Thanks to Sergey Brester.
++
++
++
++
++
++директиву error_log теперь можно использовать
++на уровнях mail и server в почтовом прокси-сервере.
++
++
++the "error_log" directive can now be used
++on mail and server levels in mail proxy.
++
++
++
++
++
++параметр proxy_protocol директивы listen не работал,
++если не был указан в первой директиве listen для данного listen-сокета.
++
++
++the "proxy_protocol" parameter of the "listen" directive did not work
++if not specified in the first "listen" directive for a listen socket.
++
++
++
++
++
++
++
++
++
++
++теперь директива tcp_nodelay работает для SSL-соединений с бэкендами.
++
++
++now the "tcp_nodelay" directive works with backend SSL connections.
++
++
++
++
++
++теперь потоки могут использоваться для чтения заголовков файлов в кэше.
++
++
++now thread pools can be used to read cache file headers.
++
++
++
++
++
++в директиве proxy_request_buffering.
++
++
++in the "proxy_request_buffering" directive.
++
++
++
++
++
++при использовании потоков на Linux
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when using thread pools on Linux.
++
++
++
++
++
++в обработке ошибок при использовании директивы ssl_stapling.
++Спасибо Filipe da Silva.
++
++
++in error handling when using the "ssl_stapling" directive.
++Thanks to Filipe da Silva.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++параметр sendfile директивы aio более не нужен;
++теперь nginx автоматически использует AIO для подгрузки данных для sendfile,
++если одновременно используются директивы aio и sendfile.
++
++
++the "sendfile" parameter of the "aio" directive is deprecated;
++now nginx automatically uses AIO to pre-load data for sendfile
++if both "aio" and "sendfile" directives are used.
++
++
++
++
++
++экспериментальная поддержка потоков.
++
++
++experimental thread pools support.
++
++
++
++
++
++директивы proxy_request_buffering, fastcgi_request_buffering,
++scgi_request_buffering и uwsgi_request_buffering.
++
++
++the "proxy_request_buffering", "fastcgi_request_buffering",
++"scgi_request_buffering", and "uwsgi_request_buffering" directives.
++
++
++
++
++
++экспериментальное API для обработки тела запроса.
++
++
++request body filters experimental API.
++
++
++
++
++
++проверка клиентских SSL-сертификатов в почтовом прокси-сервере.
++Спасибо Sven Peter, Franck Levionnois и Filipe Da Silva.
++
++
++client SSL certificates support in mail proxy.
++Thanks to Sven Peter, Franck Levionnois, and Filipe Da Silva.
++
++
++
++
++
++уменьшение времени запуска
++при использовании директивы "hash ... consistent" в блоке upstream.
++Спасибо Wai Keen Woon.
++
++
++startup speedup
++when using the "hash ... consistent" directive in the upstream block.
++Thanks to Wai Keen Woon.
++
++
++
++
++
++отладочное логгирование в кольцевой буфер в памяти.
++
++
++debug logging into a cyclic memory buffer.
++
++
++
++
++
++в обработке хэш-таблиц.
++Спасибо Chris West.
++
++
++in hash table handling.
++Thanks to Chris West.
++
++
++
++
++
++в директиве proxy_cache_revalidate.
++
++
++in the "proxy_cache_revalidate" directive.
++
++
++
++
++
++SSL-соединения могли зависать, если использовался отложенный accept
++или параметр proxy_protocol директивы listen.
++Спасибо James Hamlin.
++
++
++SSL connections might hang if deferred accept
++or the "proxy_protocol" parameter of the "listen" directive were used.
++Thanks to James Hamlin.
++
++
++
++
++
++переменная $upstream_response_time могла содержать неверное значение
++при использовании директивы image_filter.
++
++
++the $upstream_response_time variable might contain a wrong value
++if the "image_filter" directive was used.
++
++
++
++
++
++в обработке целочисленных переполнений.
++Спасибо Régis Leroy.
++
++
++in integer overflow handling.
++Thanks to Régis Leroy.
++
++
++
++
++
++при использовании LibreSSL было невозможно включить поддержку SSLv3.
++
++
++it was not possible to enable SSLv3 with LibreSSL.
++
++
++
++
++
++при использовании LibreSSL в логах появлялись сообщения
++"ignoring stale global SSL error ... called a function you should not call".
++
++
++the "ignoring stale global SSL error ... called a function you should not call"
++alerts appeared in logs when using LibreSSL.
++
++
++
++
++
++сертификаты, указанные в директивах ssl_client_certificate и
++ssl_trusted_certificate, использовались
++для автоматического построения цепочек сертификатов.
++
++
++certificates specified by the "ssl_client_certificate" and
++"ssl_trusted_certificate" directives were inadvertently used
++to automatically construct certificate chains.
++
++
++
++
++
++
++
++
++
++
++параметр use_temp_path директив proxy_cache_path, fastcgi_cache_path,
++scgi_cache_path и uwsgi_cache_path.
++
++
++the "use_temp_path" parameter of the "proxy_cache_path", "fastcgi_cache_path",
++"scgi_cache_path", and "uwsgi_cache_path" directives.
++
++
++
++
++
++переменная $upstream_header_time.
++
++
++the $upstream_header_time variable.
++
++
++
++
++
++теперь при переполнении диска nginx пытается писать error_log'и только
++раз в секунду.
++
++
++now on disk overflow nginx tries to write error logs once a second only.
++
++
++
++
++
++директива try_files при тестировании каталогов
++не игнорировала обычные файлы.
++Спасибо Damien Tournoud.
++
++
++the "try_files" directive did not ignore normal files
++while testing directories.
++Thanks to Damien Tournoud.
++
++
++
++
++
++при использовании директивы sendfile на OS X
++возникали ошибки "sendfile() failed";
++ошибка появилась в nginx 1.7.8.
++
++
++alerts "sendfile() failed"
++if the "sendfile" directive was used on OS X;
++the bug had appeared in 1.7.8.
++
++
++
++
++
++в лог могли писаться сообщения "sem_post() failed".
++
++
++alerts "sem_post() failed" might appear in logs.
++
++
++
++
++
++nginx не собирался с musl libc.
++Спасибо James Taylor.
++
++
++nginx could not be built with musl libc.
++Thanks to James Taylor.
++
++
++
++
++
++nginx не собирался на Tru64 UNIX.
++Спасибо Goetz T. Fischer.
++
++
++nginx could not be built on Tru64 UNIX.
++Thanks to Goetz T. Fischer.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_cache, fastcgi_cache, scgi_cache и uwsgi_cache
++поддерживают переменные.
++
++
++variables support in the "proxy_cache", "fastcgi_cache", "scgi_cache",
++and "uwsgi_cache" directives.
++
++
++
++
++
++директива expires поддерживает переменные.
++
++
++variables support in the "expires" directive.
++
++
++
++
++
++возможность загрузки секретных ключей с аппаратных устройств
++с помощью OpenSSL engines.
++Спасибо Дмитрию Пичулину.
++
++
++loading of secret keys from hardware tokens
++with OpenSSL engines.
++Thanks to Dmitrii Pichulin.
++
++
++
++
++
++директива autoindex_format.
++
++
++the "autoindex_format" directive.
++
++
++
++
++
++ревалидация элементов кэша теперь используется только для ответов
++с кодами 200 и 206.
++Спасибо Piotr Sikora.
++
++
++cache revalidation is now only used for responses
++with 200 and 206 status codes.
++Thanks to Piotr Sikora.
++
++
++
++
++
++строка "TE" заголовка запроса клиента передавалась на бэкенд при проксировании.
++
++
++the "TE" client request header line was passed to backends while proxying.
++
++
++
++
++
++директивы proxy_pass, fastcgi_pass, scgi_pass и uwsgi_pass
++могли неправильно работать внутри блоков if и limit_except.
++
++
++the "proxy_pass", "fastcgi_pass", "scgi_pass", and "uwsgi_pass" directives
++might not work correctly inside the "if" and "limit_except" blocks.
++
++
++
++
++
++директива proxy_store с параметром "on" игнорировалась,
++если на предыдущем уровне использовалась директива proxy_store
++с явно заданным путём к файлам.
++
++
++the "proxy_store" directive with the "on" parameter was ignored
++if the "proxy_store" directive with an explicitly specified file path
++was used on a previous level.
++
++
++
++
++
++nginx не собирался с BoringSSL.
++Спасибо Lukas Tribus.
++
++
++nginx could not be built with BoringSSL.
++Thanks to Lukas Tribus.
++
++
++
++
++
++
++
++
++
++
++теперь строки "If-Modified-Since", "If-Range" и им подобные
++в заголовке запроса клиента передаются бэкенду при включённом кэшировании,
++если nginx заранее знает, что не будет кэшировать ответ
++(например, при использовании proxy_cache_min_uses).
++
++
++now the "If-Modified-Since", "If-Range", etc.
++client request header lines are passed to a backend while caching
++if nginx knows in advance that the response will not be cached
++(e.g., when using proxy_cache_min_uses).
++
++
++
++
++
++теперь после истечения proxy_cache_lock_timeout
++nginx отправляет запрос на бэкенд без кэширования;
++новые директивы proxy_cache_lock_age, fastcgi_cache_lock_age,
++scgi_cache_lock_age и uwsgi_cache_lock_age позволяют указать,
++через какое время блокировка будет принудительно снята
++и будет сделана ещё одна попытка закэшировать ответ.
++
++
++now after proxy_cache_lock_timeout
++nginx sends a request to a backend with caching disabled;
++the new directives "proxy_cache_lock_age", "fastcgi_cache_lock_age",
++"scgi_cache_lock_age", and "uwsgi_cache_lock_age" specify a time
++after which the lock will be released
++and another attempt to cache a response will be made.
++
++
++
++
++
++директива log_format теперь может использоваться только на уровне http.
++
++
++the "log_format" directive can now be used only at http level.
++
++
++
++
++
++директивы proxy_ssl_certificate, proxy_ssl_certificate_key,
++proxy_ssl_password_file, uwsgi_ssl_certificate,
++uwsgi_ssl_certificate_key и uwsgi_ssl_password_file.
++Спасибо Piotr Sikora.
++
++
++the "proxy_ssl_certificate", "proxy_ssl_certificate_key",
++"proxy_ssl_password_file", "uwsgi_ssl_certificate",
++"uwsgi_ssl_certificate_key", and "uwsgi_ssl_password_file" directives.
++Thanks to Piotr Sikora.
++
++
++
++
++
++теперь с помощью X-Accel-Redirect
++можно перейти в именованный location.
++Спасибо Toshikuni Fukaya.
++
++
++it is now possible to switch to a named location
++using "X-Accel-Redirect".
++Thanks to Toshikuni Fukaya.
++
++
++
++
++
++теперь директива tcp_nodelay работает для SPDY-соединений.
++
++
++now the "tcp_nodelay" directive works with SPDY connections.
++
++
++
++
++
++новые директивы в скриптах подсветки синтаксиса для vim.
++Спасибо Peter Wu.
++
++
++new directives in vim syntax highliting scripts.
++Thanks to Peter Wu.
++
++
++
++
++
++nginx игнорировал значение "s-maxage"
++в строке "Cache-Control" в заголовке ответа бэкенда.
++Спасибо Piotr Sikora.
++
++
++nginx ignored the "s-maxage" value
++in the "Cache-Control" backend response header line.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_spdy_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в директиве ssl_password_file
++при использовании OpenSSL 0.9.8zc, 1.0.0o, 1.0.1j.
++
++
++in the "ssl_password_file" directive
++when using OpenSSL 0.9.8zc, 1.0.0o, 1.0.1j.
++
++
++
++
++
++при использовании директивы post_action
++в лог писались сообщения "header already sent";
++ошибка появилась в nginx 1.5.4.
++
++
++alerts "header already sent" appeared in logs
++if the "post_action" directive was used;
++the bug had appeared in 1.5.4.
++
++
++
++
++
++при использовании директивы "postpone_output 0" с SSI-подзапросами
++в лог могли писаться сообщения "the http output chain is empty".
++
++
++alerts "the http output chain is empty" might appear in logs
++if the "postpone_output 0" directive was used with SSI includes.
++
++
++
++
++
++в директиве proxy_cache_lock при использовании SSI-подзапросов.
++Спасибо Yichun Zhang.
++
++
++in the "proxy_cache_lock" directive with SSI subrequests.
++Thanks to Yichun Zhang.
++
++
++
++
++
++
++
++
++
++
++теперь nginx учитывает при кэшировании строку "Vary"
++в заголовке ответа бэкенда.
++
++
++now nginx takes into account the "Vary"
++header line in a backend response while caching.
++
++
++
++
++
++директивы proxy_force_ranges, fastcgi_force_ranges,
++scgi_force_ranges и uwsgi_force_ranges.
++
++
++the "proxy_force_ranges", "fastcgi_force_ranges",
++"scgi_force_ranges", and "uwsgi_force_ranges" directives.
++
++
++
++
++
++директивы proxy_limit_rate, fastcgi_limit_rate,
++scgi_limit_rate и uwsgi_limit_rate.
++
++
++the "proxy_limit_rate", "fastcgi_limit_rate",
++"scgi_limit_rate", and "uwsgi_limit_rate" directives.
++
++
++
++
++
++параметр Vary директив proxy_ignore_headers, fastcgi_ignore_headers,
++scgi_ignore_headers и uwsgi_ignore_headers.
++
++
++the "Vary" parameter of the "proxy_ignore_headers", "fastcgi_ignore_headers",
++"scgi_ignore_headers", and "uwsgi_ignore_headers" directives.
++
++
++
++
++
++последняя часть ответа, полученного от бэкенда
++при небуферизированном проксировании,
++могла не отправляться клиенту,
++если использовались директивы gzip или gunzip.
++
++
++the last part of a response received from a backend
++with unbufferred proxy
++might not be sent to a client
++if "gzip" or "gunzip" directives were used.
++
++
++
++
++
++в директиве proxy_cache_revalidate.
++Спасибо Piotr Sikora.
++
++
++in the "proxy_cache_revalidate" directive.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в обработке ошибок.
++Спасибо Yichun Zhang и Даниилу Бондареву.
++
++
++in error handling.
++Thanks to Yichun Zhang and Daniil Bondarev.
++
++
++
++
++
++в директивах
++proxy_next_upstream_tries и proxy_next_upstream_timeout.
++Спасибо Feng Gu.
++
++
++in the "proxy_next_upstream_tries" and "proxy_next_upstream_timeout"
++directives.
++Thanks to Feng Gu.
++
++
++
++
++
++nginx/Windows не собирался с MinGW-w64 gcc.
++Спасибо Kouhei Sutou.
++
++
++nginx/Windows could not be built with MinGW-w64 gcc.
++Thanks to Kouhei Sutou.
++
++
++
++
++
++
++
++
++
++
++устаревшая директива limit_zone больше не поддерживается.
++
++
++the deprecated "limit_zone" directive is not supported anymore.
++
++
++
++
++
++в директивах limit_conn_zone и limit_req_zone теперь можно использовать
++комбинации нескольких переменных.
++
++
++the "limit_conn_zone" and "limit_req_zone" directives now can be used
++with combinations of multiple variables.
++
++
++
++
++
++при повторной отправке FastCGI-запроса на бэкенд
++тело запроса могло передаваться неправильно.
++
++
++request body might be transmitted incorrectly
++when retrying a FastCGI request to the next upstream server.
++
++
++
++
++
++в логгировании в syslog.
++
++
++in logging to syslog.
++
++
++
++
++
++
++
++
++
++
++при использовании общего для нескольких блоков server
++разделяемого кэша SSL-сессий или общего ключа для шифрования
++TLS session tickets было возможно повторно использовать
++SSL-сессию в контексте другого блока server (CVE-2014-3616).
++Спасибо Antoine Delignat-Lavaud.
++
++
++it was possible to reuse SSL sessions in unrelated contexts
++if a shared SSL session cache or the same TLS session ticket key
++was used for multiple "server" blocks (CVE-2014-3616).
++Thanks to Antoine Delignat-Lavaud.
++
++
++
++
++
++директиву stub_status теперь можно указывать без параметров.
++
++
++now the "stub_status" directive does not require a parameter.
++
++
++
++
++
++параметр always директивы add_header.
++
++
++the "always" parameter of the "add_header" directive.
++
++
++
++
++
++директивы
++proxy_next_upstream_tries, proxy_next_upstream_timeout,
++fastcgi_next_upstream_tries, fastcgi_next_upstream_timeout,
++memcached_next_upstream_tries, memcached_next_upstream_timeout,
++scgi_next_upstream_tries, scgi_next_upstream_timeout,
++uwsgi_next_upstream_tries и uwsgi_next_upstream_timeout.
++
++
++the
++"proxy_next_upstream_tries", "proxy_next_upstream_timeout",
++"fastcgi_next_upstream_tries", "fastcgi_next_upstream_timeout",
++"memcached_next_upstream_tries", "memcached_next_upstream_timeout",
++"scgi_next_upstream_tries", "scgi_next_upstream_timeout",
++"uwsgi_next_upstream_tries", and "uwsgi_next_upstream_timeout"
++directives.
++
++
++
++
++
++в параметре if директивы access_log.
++
++
++in the "if" parameter of the "access_log" directive.
++
++
++
++
++
++в модуле ngx_http_perl_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_perl_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++директива listen почтового прокси-сервера
++не позволяла указать более двух параметров.
++
++
++the "listen" directive of the mail proxy module
++did not allow to specify more than two parameters.
++
++
++
++
++
++директива sub_filter не работала
++с заменяемой строкой из одного символа.
++
++
++the "sub_filter" directive did not work
++with a string to replace consisting of a single character.
++
++
++
++
++
++запросы могли зависать, если использовался resolver
++и в процессе обращения к DNS-серверу происходил таймаут.
++
++
++requests might hang if resolver was used
++and a timeout occurred during a DNS request.
++
++
++
++
++
++в модуле ngx_http_spdy_module при использовании совместно с AIO.
++
++
++in the ngx_http_spdy_module when using with AIO.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если с помощью директивы set изменялись переменные
++"$http_...", "$sent_http_..." или "$upstream_http_...".
++
++
++a segmentation fault might occur in a worker process
++if the "set" directive was used to change the "$http_...",
++"$sent_http_...", or "$upstream_http_..." variables.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++Спасибо Markus Linnala и Feng Gu.
++
++
++in memory allocation error handling.
++Thanks to Markus Linnala and Feng Gu.
++
++
++
++
++
++
++
++
++
++
++pipelined-команды не отбрасывались
++после команды STARTTLS в SMTP прокси-сервере (CVE-2014-3556);
++ошибка появилась в 1.5.6.
++Спасибо Chris Boulton.
++
++
++pipelined commands were not discarded
++after STARTTLS command in SMTP proxy (CVE-2014-3556);
++the bug had appeared in 1.5.6.
++Thanks to Chris Boulton.
++
++
++
++
++
++экранирование символов в URI теперь использует
++шестнадцатеричные цифры в верхнем регистре.
++Спасибо Piotr Sikora.
++
++
++URI escaping now uses
++uppercase hexadecimal digits.
++Thanks to Piotr Sikora.
++
++
++
++
++
++теперь nginx можно собрать с BoringSSL и LibreSSL.
++Спасибо Piotr Sikora.
++
++
++now nginx can be build with BoringSSL and LibreSSL.
++Thanks to Piotr Sikora.
++
++
++
++
++
++запросы могли зависать, если использовался resolver
++и DNS-сервер возвращал некорректный ответ;
++ошибка появилась в 1.5.8.
++
++
++requests might hang if resolver was used
++and a DNS server returned a malformed response;
++the bug had appeared in 1.5.8.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_spdy_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++переменная $uri могла содержать мусор
++при возврате ошибок с кодом 400.
++Спасибо Сергею Боброву.
++
++
++the $uri variable might contain garbage
++when returning errors with code 400.
++Thanks to Sergey Bobrov.
++
++
++
++
++
++в обработке ошибок в директиве proxy_store
++и в модуле ngx_http_dav_module.
++Спасибо Feng Gu.
++
++
++in error handling in the "proxy_store" directive
++and the ngx_http_dav_module.
++Thanks to Feng Gu.
++
++
++
++
++
++при логгировании ошибок в syslog мог происходить segmentation fault;
++ошибка появилась в 1.7.1.
++
++
++a segmentation fault might occur if logging of errors to syslog was used;
++the bug had appeared in 1.7.1.
++
++
++
++
++
++переменные $geoip_latitude, $geoip_longitude, $geoip_dma_code
++и $geoip_area_code могли не работать.
++Спасибо Yichun Zhang.
++
++
++the $geoip_latitude, $geoip_longitude, $geoip_dma_code,
++and $geoip_area_code variables might not work.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++Спасибо Tatsuhiko Kubo и Piotr Sikora.
++
++
++in memory allocation error handling.
++Thanks to Tatsuhiko Kubo and Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++weak entity tags теперь не удаляются при изменениях ответа,
++а strong entity tags преобразуются в weak.
++
++
++weak entity tags are now preserved on response modifications,
++and strong ones are changed to weak.
++
++
++
++
++
++ревалидация элементов кэша теперь, если это возможно,
++использует заголовок If-None-Match.
++
++
++cache revalidation now uses If-None-Match header
++if possible.
++
++
++
++
++
++директива ssl_password_file.
++
++
++the "ssl_password_file" directive.
++
++
++
++
++
++при возврате ответа из кэша
++заголовок запроса If-None-Match игнорировался,
++если в ответе не было заголовка Last-Modified.
++
++
++the If-None-Match request header line was ignored
++if there was no Last-Modified header
++in a response returned from cache.
++
++
++
++
++
++сообщения "peer closed connection in SSL handshake"
++при соединении с бэкендами логгировались на уровне info вместо error.
++
++
++"peer closed connection in SSL handshake" messages
++were logged at "info" level instead of "error" while connecting to backends.
++
++
++
++
++
++в модуле ngx_http_dav_module в nginx/Windows.
++
++
++in the ngx_http_dav_module module in nginx/Windows.
++
++
++
++
++
++SPDY-соединения могли неожиданно закрываться,
++если использовалось кэширование.
++
++
++SPDY connections might be closed prematurely
++if caching was used.
++
++
++
++
++
++
++
++
++
++
++директива hash в блоке upstream.
++
++
++the "hash" directive inside the "upstream" block.
++
++
++
++
++
++дефрагментация свободных блоков разделяемой памяти.
++Спасибо Wandenberg Peixoto и Yichun Zhang.
++
++
++defragmentation of free shared memory blocks.
++Thanks to Wandenberg Peixoto and Yichun Zhang.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалось значение access_log по умолчанию;
++ошибка появилась в 1.7.0.
++Спасибо Piotr Sikora.
++
++
++a segmentation fault might occur in a worker process
++if the default value of the "access_log" directive was used;
++the bug had appeared in 1.7.0.
++Thanks to Piotr Sikora.
++
++
++
++
++
++завершающий слэш ошибочно удалялся
++из последнего параметра директивы try_files.
++
++
++trailing slash was mistakenly removed
++from the last parameter of the "try_files" directive.
++
++
++
++
++
++nginx мог не собираться на OS X.
++
++
++nginx could not be built on OS X in some cases.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++переменные "$upstream_cookie_...".
++
++
++the "$upstream_cookie_..." variables.
++
++
++
++
++
++переменная $ssl_client_fingerprint.
++
++
++the $ssl_client_fingerprint variable.
++
++
++
++
++
++директивы error_log и access_log теперь поддерживают логгирование в syslog.
++
++
++the "error_log" and "access_log" directives now support logging to syslog.
++
++
++
++
++
++почтовый прокси-сервер теперь логгирует порт клиента при соединении.
++
++
++the mail proxy now logs client port on connect.
++
++
++
++
++
++утечки памяти при использовании директивы "ssl_stapling".
++Спасибо Filipe da Silva.
++
++
++memory leak if the "ssl_stapling" directive was used.
++Thanks to Filipe da Silva.
++
++
++
++
++
++директива alias внутри location'а, заданного регулярным выражением,
++работала неправильно, если использовались директивы if или limit_except.
++
++
++the "alias" directive used inside a location given by a regular expression
++worked incorrectly if the "if" or "limit_except" directives were used.
++
++
++
++
++
++директива charset не ставила кодировку для сжатых ответов бэкендов.
++
++
++the "charset" directive did not set a charset to encoded backend responses.
++
++
++
++
++
++директива proxy_pass без URI могла использовать оригинальный запрос
++после установки переменной $args.
++Спасибо Yichun Zhang.
++
++
++a "proxy_pass" directive without URI part might use original request
++after the $args variable was set.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в работе параметра none директивы smtp_auth;
++ошибка появилась в 1.5.6.
++Спасибо Святославу Никольскому.
++
++
++in the "none" parameter in the "smtp_auth" directive;
++the bug had appeared in 1.5.6.
++Thanks to Svyatoslav Nikolsky.
++
++
++
++
++
++при совместном использовании sub_filter и SSI
++ответы могли передаваться неверно.
++
++
++if sub_filter and SSI were used together,
++then responses might be transferred incorrectly.
++
++
++
++
++
++nginx не собирался с параметром --with-file-aio на Linux/aarch64.
++
++
++nginx could not be built with the --with-file-aio option on Linux/aarch64.
++
++
++
++
++
++
++
++
++
++
++проверка SSL-сертификатов бэкендов.
++
++
++backend SSL certificate verification.
++
++
++
++
++
++поддержка SNI при работе с бэкендами по SSL.
++
++
++support for SNI while working with SSL backends.
++
++
++
++
++
++переменная $ssl_server_name.
++
++
++the $ssl_server_name variable.
++
++
++
++
++
++параметр if директивы access_log.
++
++
++the "if" parameter of the "access_log" directive.
++
++
++
++
++
++
++
++
++
++
++улучшена обработка хэш-таблиц;
++в директивах variables_hash_max_size и types_hash_bucket_size
++значения по умолчанию изменены на 1024 и 64 соответственно.
++
++
++improved hash table handling;
++the default values of the "variables_hash_max_size" and
++"types_hash_bucket_size" were changed to 1024 and 64 respectively.
++
++
++
++
++
++модуль ngx_http_mp4_module теперь понимает аргумент end.
++
++
++the ngx_http_mp4_module now supports the "end" argument.
++
++
++
++
++
++поддержка byte ranges модулем ngx_http_mp4_module и при сохранении
++ответов в кэш.
++
++
++byte ranges support in the ngx_http_mp4_module and while saving responses
++to cache.
++
++
++
++
++
++теперь nginx не пишет в лог сообщения "ngx_slab_alloc() failed: no memory"
++при использовании разделяемой памяти в ssl_session_cache
++и в модуле ngx_http_limit_req_module.
++
++
++alerts "ngx_slab_alloc() failed: no memory" no longer logged
++when using shared memory in the "ssl_session_cache" directive
++and in the ngx_http_limit_req_module.
++
++
++
++
++
++директива underscores_in_headers
++не разрешала подчёркивание в первом символе заголовка.
++Спасибо Piotr Sikora.
++
++
++the "underscores_in_headers" directive
++did not allow underscore as a first character of a header.
++Thanks to Piotr Sikora.
++
++
++
++
++
++cache manager мог нагружать процессор при выходе в nginx/Windows.
++
++
++cache manager might hog CPU on exit in nginx/Windows.
++
++
++
++
++
++при использовании ssl_session_cache с параметром shared
++рабочий процесс nginx/Windows завершался аварийно.
++
++
++nginx/Windows terminated abnormally
++if the "ssl_session_cache" directive was used with the "shared" parameter.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++при обработке специально созданного запроса модулем ngx_http_spdy_module
++могло происходить переполнение буфера в рабочем процессе,
++что потенциально могло приводить к выполнению произвольного кода
++(CVE-2014-0133).
++Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel
++Sadosky, Buenos Aires, Argentina.
++
++
++a heap memory buffer overflow might occur in a worker process
++while handling a specially crafted request by ngx_http_spdy_module,
++potentially resulting in arbitrary code execution
++(CVE-2014-0133).
++Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr. Manuel
++Sadosky, Buenos Aires, Argentina.
++
++
++
++
++
++параметр proxy_protocol в директивах listen и real_ip_header,
++переменная $proxy_protocol_addr.
++
++
++the "proxy_protocol" parameters of the "listen" and "real_ip_header" directives,
++the $proxy_protocol_addr variable.
++
++
++
++
++
++в директиве fastcgi_next_upstream.
++Спасибо Lucas Molas.
++
++
++in the "fastcgi_next_upstream" directive.
++Thanks to Lucas Molas.
++
++
++
++
++
++
++
++
++
++
++при обработке специально созданного запроса модулем ngx_http_spdy_module
++на 32-битных платформах могла повреждаться память рабочего процесса,
++что потенциально могло приводить к выполнению произвольного кода
++(CVE-2014-0088);
++ошибка появилась в 1.5.10.
++Спасибо Lucas Molas из Programa STIC, Fundación Dr. Manuel
++Sadosky, Buenos Aires, Argentina.
++
++
++memory corruption might occur in a worker process on 32-bit platforms
++while handling a specially crafted request by ngx_http_spdy_module,
++potentially resulting in arbitrary code execution (CVE-2014-0088);
++the bug had appeared in 1.5.10.
++Thanks to Lucas Molas, researcher at Programa STIC, Fundación Dr. Manuel
++Sadosky, Buenos Aires, Argentina.
++
++
++
++
++
++переменная $ssl_session_reused.
++
++
++the $ssl_session_reused variable.
++
++
++
++
++
++директива client_max_body_size могла не работать
++при чтении тела запроса с использованием chunked transfer encoding;
++ошибка появилась в 1.3.9.
++Спасибо Lucas Molas.
++
++
++the "client_max_body_size" directive might not work
++when reading a request body using chunked transfer encoding;
++the bug had appeared in 1.3.9.
++Thanks to Lucas Molas.
++
++
++
++
++
++при проксировании WebSocket-соединений
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++when proxying WebSocket connections.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_spdy_module на 32-битных платформах;
++ошибка появилась в 1.5.10.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_spdy_module was used on 32-bit platforms;
++the bug had appeared in 1.5.10.
++
++
++
++
++
++значение переменной $upstream_status могло быть неверным,
++если использовались директивы proxy_cache_use_stale
++или proxy_cache_revalidate.
++Спасибо Piotr Sikora.
++
++
++the $upstream_status variable might contain wrong data
++if the "proxy_cache_use_stale" or "proxy_cache_revalidate" directives
++were used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если ошибки с кодом 400 с помощью директивы error_page
++перенаправлялись в именованный location.
++
++
++a segmentation fault might occur in a worker process
++if errors with code 400 were redirected to a named location
++using the "error_page" directive.
++
++
++
++
++
++nginx/Windows не собирался с Visual Studio 2013.
++
++
++nginx/Windows could not be built with Visual Studio 2013.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_spdy_module теперь использует протокол SPDY 3.1.
++Спасибо Automattic и MaxCDN за спонсирование разработки.
++
++
++the ngx_http_spdy_module now uses SPDY 3.1 protocol.
++Thanks to Automattic and MaxCDN for sponsoring this work.
++
++
++
++
++
++модуль ngx_http_mp4_module теперь пропускает дорожки,
++имеющие меньшую длину, чем запрошенная перемотка.
++
++
++the ngx_http_mp4_module now skips tracks
++too short for a seek requested.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если переменная $ssl_session_id использовалась при логгировании;
++ошибка появилась в 1.5.9.
++
++
++a segmentation fault might occur in a worker process
++if the $ssl_session_id variable was used in logs;
++the bug had appeared in 1.5.9.
++
++
++
++
++
++переменные $date_local и $date_gmt использовали неверный формат
++вне модуля ngx_http_ssi_filter_module.
++
++
++the $date_local and $date_gmt variables used wrong format
++outside of the ngx_http_ssi_filter_module.
++
++
++
++
++
++клиентские соединения могли сразу закрываться,
++если использовался отложенный accept;
++ошибка появилась в 1.3.15.
++
++
++client connections might be immediately closed
++if deferred accept was used;
++the bug had appeared in 1.3.15.
++
++
++
++
++
++сообщения "getsockopt(TCP_FASTOPEN) ... failed" записывались в лог
++в процессе обновления исполняемого файла на Linux;
++ошибка появилась в 1.5.8.
++Спасибо Piotr Sikora.
++
++
++alerts "getsockopt(TCP_FASTOPEN) ... failed" appeared in logs
++during binary upgrade on Linux;
++the bug had appeared in 1.5.8.
++Thanks to Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++теперь в заголовке X-Accel-Redirect nginx ожидает закодированный URI.
++
++
++now nginx expects escaped URIs in "X-Accel-Redirect" headers.
++
++
++
++
++
++директива ssl_buffer_size.
++
++
++the "ssl_buffer_size" directive.
++
++
++
++
++
++директиву limit_rate теперь можно использовать для
++ограничения скорости передачи ответов клиенту в SPDY-соединениях.
++
++
++the "limit_rate" directive can now be used to
++rate limit responses sent in SPDY connections.
++
++
++
++
++
++директива spdy_chunk_size.
++
++
++the "spdy_chunk_size" directive.
++
++
++
++
++
++директива ssl_session_tickets.
++Спасибо Dirkjan Bussink.
++
++
++the "ssl_session_tickets" directive.
++Thanks to Dirkjan Bussink.
++
++
++
++
++
++переменная $ssl_session_id содержала всю сессию в сериализованном виде
++вместо её идентификатора.
++Спасибо Ivan Ristić.
++
++
++the $ssl_session_id variable contained full session serialized
++instead of just a session id.
++Thanks to Ivan Ristić.
++
++
++
++
++
++nginx неправильно обрабатывал закодированный символ "?" в команде SSI include.
++
++
++nginx incorrectly handled escaped "?" character in the "include" SSI command.
++
++
++
++
++
++модуль ngx_http_dav_module не раскодировал целевой URI при
++обработке методов COPY и MOVE.
++
++
++the ngx_http_dav_module did not unescape destination URI
++of the COPY and MOVE methods.
++
++
++
++
++
++resolver не понимал доменные имена с точкой в конце.
++Спасибо Yichun Zhang.
++
++
++resolver did not understand domain names with a trailing dot.
++Thanks to Yichun Zhang.
++
++
++
++
++
++при проксировании в логах могли появляться сообщения "zero size buf in output";
++ошибка появилась в 1.3.9.
++
++
++alerts "zero size buf in output" might appear in logs while proxying;
++the bug had appeared in 1.3.9.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_spdy_module.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_spdy_module was used.
++
++
++
++
++
++при использовании методов обработки соединений select, poll и /dev/poll
++проксируемые WebSocket-соединения могли зависать сразу после открытия.
++
++
++proxied WebSocket connections might hang right after handshake
++if the select, poll, or /dev/poll methods were used.
++
++
++
++
++
++директива xclient почтового прокси-сервера
++некорректно передавала IPv6-адреса.
++
++
++the "xclient" directive of the mail proxy module
++incorrectly handled IPv6 client addresses.
++
++
++
++
++
++
++
++
++
++
++теперь resolver поддерживает IPv6.
++
++
++IPv6 support in resolver.
++
++
++
++
++
++директива listen поддерживает параметр fastopen.
++Спасибо Mathew Rodley.
++
++
++the "listen" directive supports the "fastopen" parameter.
++Thanks to Mathew Rodley.
++
++
++
++
++
++поддержка SSL в модуле ngx_http_uwsgi_module.
++Спасибо Roberto De Ioris.
++
++
++SSL support in the ngx_http_uwsgi_module.
++Thanks to Roberto De Ioris.
++
++
++
++
++
++скрипты подсветки синтаксиса для vim добавлены в contrib.
++Спасибо Evan Miller.
++
++
++vim syntax highlighting scripts were added to contrib.
++Thanks to Evan Miller.
++
++
++
++
++
++при чтении тела запроса с использованием chunked transfer encoding
++по SSL-соединению мог произойти таймаут.
++
++
++a timeout might occur while reading client request body
++in an SSL connection using chunked transfer encoding.
++
++
++
++
++
++директива master_process работала неправильно в nginx/Windows.
++
++
++the "master_process" directive did not work correctly in nginx/Windows.
++
++
++
++
++
++параметр setfib директивы listen мог не работать.
++
++
++the "setfib" parameter of the "listen" directive might not work.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++символ, следующий за незакодированным пробелом в строке запроса,
++обрабатывался неправильно (CVE-2013-4547);
++ошибка появилась в 0.8.41.
++Спасибо Ivan Fratric из Google Security Team.
++
++
++a character following an unescaped space in a request line
++was handled incorrectly (CVE-2013-4547);
++the bug had appeared in 0.8.41.
++Thanks to Ivan Fratric of the Google Security Team.
++
++
++
++
++
++уровень логгирования ошибок auth_basic об отсутствии пароля
++понижен с уровня error до info.
++
++
++a logging level of auth_basic errors about no user/password provided
++has been lowered from "error" to "info".
++
++
++
++
++
++директивы proxy_cache_revalidate, fastcgi_cache_revalidate,
++scgi_cache_revalidate и uwsgi_cache_revalidate.
++
++
++the "proxy_cache_revalidate", "fastcgi_cache_revalidate",
++"scgi_cache_revalidate", and "uwsgi_cache_revalidate" directives.
++
++
++
++
++
++директива ssl_session_ticket_key.
++Спасибо Piotr Sikora.
++
++
++the "ssl_session_ticket_key" directive.
++Thanks to Piotr Sikora.
++
++
++
++
++
++директива "add_header Cache-Control ''"
++добавляла строку заголовка ответа "Cache-Control" с пустым значением.
++
++
++the directive "add_header Cache-Control ''"
++added a "Cache-Control" response header line with an empty value.
++
++
++
++
++
++директива "satisfy any" могла вернуть ошибку 403 вместо 401
++при использовании директив auth_request и auth_basic.
++Спасибо Jan Marc Hoffmann.
++
++
++the "satisfy any" directive might return 403 error instead of 401
++if auth_request and auth_basic directives were used.
++Thanks to Jan Marc Hoffmann.
++
++
++
++
++
++параметры accept_filter и deferred директивы listen игнорировались
++для listen-сокетов, создаваемых в процессе обновления исполняемого файла.
++Спасибо Piotr Sikora.
++
++
++the "accept_filter" and "deferred" parameters of the "listen" directive
++were ignored for listen sockets created during binary upgrade.
++Thanks to Piotr Sikora.
++
++
++
++
++
++часть данных, полученных от бэкенда при небуферизированном проксировании,
++могла не отправляться клиенту сразу,
++если использовались директивы gzip или gunzip.
++Спасибо Yichun Zhang.
++
++
++some data received from a backend with unbufferred proxy
++might not be sent to a client immediately
++if "gzip" or "gunzip" directives were used.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в обработке ошибок в модуле ngx_http_gunzip_filter_module.
++
++
++in error handling in ngx_http_gunzip_filter_module.
++
++
++
++
++
++ответы могли зависать,
++если использовался модуль ngx_http_spdy_module
++и директива auth_request.
++
++
++responses might hang
++if the ngx_http_spdy_module was used
++with the "auth_request" directive.
++
++
++
++
++
++утечки памяти в nginx/Windows.
++
++
++memory leak in nginx/Windows.
++
++
++
++
++
++
++
++
++
++
++директива fastcgi_buffering.
++
++
++the "fastcgi_buffering" directive.
++
++
++
++
++
++директивы proxy_ssl_protocols и proxy_ssl_ciphers.
++Спасибо Piotr Sikora.
++
++
++the "proxy_ssl_protocols" and "proxy_ssl_ciphers" directives.
++Thanks to Piotr Sikora.
++
++
++
++
++
++оптимизация SSL handshake при использовании длинных цепочек сертификатов.
++
++
++optimization of SSL handshakes when using long certificate chains.
++
++
++
++
++
++почтовый прокси-сервер поддерживает SMTP pipelining.
++
++
++the mail proxy supports SMTP pipelining.
++
++
++
++
++
++в модуле ngx_http_auth_basic_module
++при использовании метода шифрования паролей "$apr1$".
++Спасибо Markus Linnala.
++
++
++in the ngx_http_auth_basic_module
++when using "$apr1$" password encryption method.
++Thanks to Markus Linnala.
++
++
++
++
++
++на MacOSX, Cygwin и nginx/Windows
++для обработки запроса мог использоваться неверный location,
++если для задания location'ов использовались символы разных регистров.
++
++
++in MacOSX, Cygwin, and nginx/Windows
++incorrect location might be used to process a request
++if locations were given using characters in different cases.
++
++
++
++
++
++автоматическое перенаправление с добавлением завершающего слэша
++для проксированных location'ов могло не работать.
++
++
++automatic redirect with appended trailing slash
++for proxied locations might not work.
++
++
++
++
++
++в почтовом прокси-сервере.
++
++
++in the mail proxy server.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++теперь nginx по умолчанию использует HTTP/1.0,
++если точно определить протокол не удалось.
++
++
++now nginx assumes HTTP/1.0 by default
++if it is not able to detect protocol reliably.
++
++
++
++
++
++директива disable_symlinks теперь использует O_PATH на Linux.
++
++
++the "disable_symlinks" directive now uses O_PATH on Linux.
++
++
++
++
++
++для определения того, что клиент закрыл соединение,
++при использовании метода epoll
++теперь используются события EPOLLRDHUP.
++
++
++now nginx uses EPOLLRDHUP events
++to detect premature connection close by clients
++if the "epoll" method is used.
++
++
++
++
++
++в директиве valid_referers при использовании параметра server_names.
++
++
++in the "valid_referers" directive if the "server_names" parameter was used.
++
++
++
++
++
++переменная $request_time не работала в nginx/Windows.
++
++
++the $request_time variable did not work in nginx/Windows.
++
++
++
++
++
++в директиве image_filter.
++Спасибо Lanshun Zhou.
++
++
++in the "image_filter" directive.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++совместимость с OpenSSL 1.0.1f.
++Спасибо Piotr Sikora.
++
++
++OpenSSL 1.0.1f compatibility.
++Thanks to Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++
++MIME-тип для расширения js изменён на "application/javascript";
++значение по умолчанию директивы charset_types изменено соответственно.
++
++
++the "js" extension MIME type has been changed to "application/javascript";
++default value of the "charset_types" directive was changed accordingly.
++
++
++
++
++
++теперь директива image_filter с параметром size
++возвращает ответ с MIME-типом "application/json".
++
++
++now the "image_filter" directive with the "size" parameter
++returns responses with the "application/json" MIME type.
++
++
++
++
++
++модуль ngx_http_auth_request_module.
++
++
++the ngx_http_auth_request_module.
++
++
++
++
++
++на старте или во время переконфигурации мог произойти segmentation fault,
++если использовалась директива try_files с пустым параметром.
++
++
++a segmentation fault might occur on start or during reconfiguration
++if the "try_files" directive was used with an empty parameter.
++
++
++
++
++
++утечки памяти при использовании в директивах root и auth_basic_user_file
++относительных путей, заданных с помощью переменных.
++
++
++memory leak if relative paths were specified using variables
++in the "root" or "auth_basic_user_file" directives.
++
++
++
++
++
++директива valid_referers неправильно выполняла регулярные выражения,
++если заголовок Referer начинался с "https://".
++Спасибо Liangbin Li.
++
++
++the "valid_referers" directive incorrectly executed regular expressions
++if a "Referer" header started with "https://".
++Thanks to Liangbin Li.
++
++
++
++
++
++ответы могли зависать, если использовались подзапросы и при обработке подзапроса
++происходила ошибка во время SSL handshake с бэкендом.
++Спасибо Aviram Cohen.
++
++
++responses might hang if subrequests were used
++and an SSL handshake error happened during subrequest processing.
++Thanks to Aviram Cohen.
++
++
++
++
++
++в модуле ngx_http_autoindex_module.
++
++
++in the ngx_http_autoindex_module.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++
++
++in the ngx_http_spdy_module.
++
++
++
++
++
++
++
++
++
++
++Изменение во внутреннем API:
++теперь при небуферизированной работе с бэкендами
++u->length по умолчанию устанавливается в -1.
++
++
++Change in internal API:
++now u->length defaults to -1
++if working with backends in unbuffered mode.
++
++
++
++
++
++теперь при получении неполного ответа от бэкенда
++nginx отправляет полученную часть ответа,
++после чего закрывает соединение с клиентом.
++
++
++now after receiving an incomplete response from a backend server
++nginx tries to send an available part of the response to a client,
++and then closes client connection.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_spdy_module
++и директива client_body_in_file_only.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_spdy_module was used
++with the "client_body_in_file_only" directive.
++
++
++
++
++
++параметр so_keepalive директивы listen
++мог работать некорректно на DragonFlyBSD.
++Спасибо Sepherosa Ziehau.
++
++
++the "so_keepalive" parameter of the "listen" directive
++might be handled incorrectly on DragonFlyBSD.
++Thanks to Sepherosa Ziehau.
++
++
++
++
++
++в модуле ngx_http_xslt_filter_module.
++
++
++in the ngx_http_xslt_filter_module.
++
++
++
++
++
++в модуле ngx_http_sub_filter_module.
++
++
++in the ngx_http_sub_filter_module.
++
++
++
++
++
++
++
++
++
++
++теперь можно использовать несколько директив error_log.
++
++
++now several "error_log" directives can be used.
++
++
++
++
++
++метод $r->header_in() встроенного перла не возвращал значения строк
++"Cookie" и "X-Forwarded-For" из заголовка запроса;
++ошибка появилась в 1.3.14.
++
++
++the $r->header_in() embedded perl method did not return value of the
++"Cookie" and "X-Forwarded-For" request header lines;
++the bug had appeared in 1.3.14.
++
++
++
++
++
++в модуле ngx_http_spdy_module.
++Спасибо Jim Radford.
++
++
++in the ngx_http_spdy_module.
++Thanks to Jim Radford.
++
++
++
++
++
++nginx не собирался на Linux при использовании x32 ABI.
++Спасибо Сергею Иванцову.
++
++
++nginx could not be built on Linux with x32 ABI.
++Thanks to Serguei Ivantsov.
++
++
++
++
++
++
++
++
++
++
++директивы ssi_last_modified, sub_filter_last_modified и
++xslt_last_modified.
++Спасибо Алексею Колпакову.
++
++
++the "ssi_last_modified", "sub_filter_last_modified", and
++"xslt_last_modified" directives.
++Thanks to Alexey Kolpakov.
++
++
++
++
++
++параметр http_403 в директивах proxy_next_upstream, fastcgi_next_upstream,
++scgi_next_upstream и uwsgi_next_upstream.
++
++
++the "http_403" parameter of the "proxy_next_upstream", "fastcgi_next_upstream",
++"scgi_next_upstream", and "uwsgi_next_upstream" directives.
++
++
++
++
++
++директивы allow и deny теперь поддерживают unix domain сокеты.
++
++
++the "allow" and "deny" directives now support unix domain sockets.
++
++
++
++
++
++nginx не собирался с модулем ngx_mail_ssl_module,
++но без модуля ngx_http_ssl_module;
++ошибка появилась в 1.3.14.
++
++
++nginx could not be built with the ngx_mail_ssl_module,
++but without ngx_http_ssl_module;
++the bug had appeared in 1.3.14.
++
++
++
++
++
++в директиве proxy_set_body.
++Спасибо Lanshun Zhou.
++
++
++in the "proxy_set_body" directive.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++в директиве lingering_time.
++Спасибо Lanshun Zhou.
++
++
++in the "lingering_time" directive.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++параметр fail_timeout директивы server
++в блоке upstream мог не работать,
++если использовался параметр max_fails;
++ошибка появилась в 1.3.0.
++
++
++the "fail_timeout" parameter of the "server" directive
++in the "upstream" context might not work
++if "max_fails" parameter was used;
++the bug had appeared in 1.3.0.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива ssl_stapling.
++Спасибо Piotr Sikora.
++
++
++a segmentation fault might occur in a worker process
++if the "ssl_stapling" directive was used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в почтовом прокси-сервере.
++Спасибо Filipe Da Silva.
++
++
++in the mail proxy server.
++Thanks to Filipe Da Silva.
++
++
++
++
++
++nginx/Windows мог перестать принимать соединения,
++если использовалось несколько рабочих процессов.
++
++
++nginx/Windows might stop accepting connections
++if several worker processes were used.
++
++
++
++
++
++
++
++
++
++
++при обработке специально созданного запроса
++мог перезаписываться стек рабочего процесса,
++что могло приводить к выполнению произвольного кода (CVE-2013-2028);
++ошибка появилась в 1.3.9.
++Спасибо Greg MacManus, iSIGHT Partners Labs.
++
++
++a stack-based buffer overflow might occur in a worker process
++while handling a specially crafted request,
++potentially resulting in arbitrary code execution (CVE-2013-2028);
++the bug had appeared in 1.3.9.
++Thanks to Greg MacManus, iSIGHT Partners Labs.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с модулем ngx_http_perl_module,
++если использовался параметр --with-openssl;
++ошибка появилась в 1.3.16.
++
++
++nginx could not be built with the ngx_http_perl_module
++if the --with-openssl option was used;
++the bug had appeared in 1.3.16.
++
++
++
++
++
++в работе с телом запроса из модуля ngx_http_perl_module;
++ошибка появилась в 1.3.9.
++
++
++in a request body handling in the ngx_http_perl_module;
++the bug had appeared in 1.3.9.
++
++
++
++
++
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовались подзапросы;
++ошибка появилась в 1.3.9.
++
++
++a segmentation fault might occur in a worker process
++if subrequests were used;
++the bug had appeared in 1.3.9.
++
++
++
++
++
++директива tcp_nodelay вызывала ошибку
++при проксировании WebSocket-соединений в unix domain сокет.
++
++
++the "tcp_nodelay" directive caused an error
++if a WebSocket connection was proxied into a unix domain socket.
++
++
++
++
++
++переменная $upstream_response_length возвращала значение "0",
++если не использовалась буферизация.
++Спасибо Piotr Sikora.
++
++
++the $upstream_response_length variable has an incorrect value "0"
++if buffering was not used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в методах обработки соединений eventport и /dev/poll.
++
++
++in the eventport and /dev/poll methods.
++
++
++
++
++
++
++
++
++
++
++открытие и закрытие соединения без отправки в нём каких-либо данных
++больше не записывается в access_log с кодом ошибки 400.
++
++
++opening and closing a connection without sending any data in it
++is no longer logged to access_log with error code 400.
++
++
++
++
++
++модуль ngx_http_spdy_module.
++Спасибо Automattic за спонсирование разработки.
++
++
++the ngx_http_spdy_module.
++Thanks to Automattic for sponsoring this work.
++
++
++
++
++
++директивы limit_req_status и limit_conn_status.
++Спасибо Nick Marden.
++
++
++the "limit_req_status" and "limit_conn_status" directives.
++Thanks to Nick Marden.
++
++
++
++
++
++директива image_filter_interlace.
++Спасибо Ивану Боброву.
++
++
++the "image_filter_interlace" directive.
++Thanks to Ian Babrou.
++
++
++
++
++
++переменная $connections_waiting в модуле ngx_http_stub_status_module.
++
++
++$connections_waiting variable in the ngx_http_stub_status_module.
++
++
++
++
++
++теперь почтовый прокси-сервер поддерживает IPv6-бэкенды.
++
++
++the mail proxy module now supports IPv6 backends.
++
++
++
++
++
++при повторной отправке запроса на бэкенд
++тело запроса могло передаваться неправильно;
++ошибка появилась в 1.3.9.
++Спасибо Piotr Sikora.
++
++
++request body might be transmitted incorrectly
++when retrying a request to the next upstream server;
++the bug had appeared in 1.3.9.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в директиве client_body_in_file_only;
++ошибка появилась в 1.3.9.
++
++
++in the "client_body_in_file_only" directive;
++the bug had appeared in 1.3.9.
++
++
++
++
++
++ответы могли зависать,
++если использовались подзапросы
++и при обработке подзапроса происходила DNS-ошибка.
++Спасибо Lanshun Zhou.
++
++
++responses might hang
++if subrequests were used
++and a DNS error happened during subrequest processing.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++в процедуре учёта использования бэкендов.
++
++
++in backend usage accounting.
++
++
++
++
++
++
++
++
++
++
++переменные $connections_active, $connections_reading и $connections_writing
++в модуле ngx_http_stub_status_module.
++
++
++$connections_active, $connections_reading, and $connections_writing variables
++in the ngx_http_stub_status_module.
++
++
++
++
++
++поддержка WebSocket-соединений
++в модулях ngx_http_uwsgi_module и ngx_http_scgi_module.
++
++
++support of WebSocket connections
++in the ngx_http_uwsgi_module and ngx_http_scgi_module.
++
++
++
++
++
++в обработке виртуальных серверов при использовании SNI.
++
++
++in virtual servers handling with SNI.
++
++
++
++
++
++при использовании директивы "ssl_session_cache shared"
++новые сессии могли не сохраняться,
++если заканчивалось место в разделяемой памяти.
++Спасибо Piotr Sikora.
++
++
++new sessions were not always stored
++if the "ssl_session_cache shared" directive was used
++and there was no free space in shared memory.
++Thanks to Piotr Sikora.
++
++
++
++
++
++несколько заголовков X-Forwarded-For обрабатывались неправильно.
++Спасибо Neal Poole за спонсирование разработки.
++
++
++multiple X-Forwarded-For headers were handled incorrectly.
++Thanks to Neal Poole for sponsoring this work.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++Спасибо Gernot Vormayr.
++
++
++in the ngx_http_mp4_module.
++Thanks to Gernot Vormayr.
++
++
++
++
++
++
++
++
++
++
++теперь для сборки по умолчанию используется компилятор с именем "cc".
++
++
++a compiler with name "cc" is now used by default.
++
++
++
++
++
++поддержка проксирования WebSocket-соединений.
++Спасибо Apcera и CloudBees за спонсирование разработки.
++
++
++support for proxying of WebSocket connections.
++Thanks to Apcera and CloudBees for sponsoring this work.
++
++
++
++
++
++директива auth_basic_user_file поддерживает шифрование паролей
++методом "{SHA}".
++Спасибо Louis Opter.
++
++
++the "auth_basic_user_file" directive supports "{SHA}"
++password encryption method.
++Thanks to Louis Opter.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_bind, fastcgi_bind, memcached_bind, scgi_bind и uwsgi_bind
++поддерживают переменные.
++
++
++variables support in the "proxy_bind", "fastcgi_bind", "memcached_bind",
++"scgi_bind", and "uwsgi_bind" directives.
++
++
++
++
++
++переменные $pipe, $request_length, $time_iso8601 и $time_local
++теперь можно использовать не только в директиве log_format.
++Спасибо Kiril Kalchev.
++
++
++the $pipe, $request_length, $time_iso8601, and $time_local variables
++can now be used not only in the "log_format" directive.
++Thanks to Kiril Kalchev.
++
++
++
++
++
++поддержка IPv6 в модуле ngx_http_geoip_module.
++Спасибо Gregor Kališnik.
++
++
++IPv6 support in the ngx_http_geoip_module.
++Thanks to Gregor Kališnik.
++
++
++
++
++
++директива proxy_method работала неверно, если была указана на уровне http.
++
++
++in the "proxy_method" directive.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался resolver и метод poll.
++
++
++a segmentation fault might occur in a worker process
++if resolver was used with the poll method.
++
++
++
++
++
++nginx мог нагружать процессор во время SSL handshake с бэкендом
++при использовании методов обработки соединений select, poll и /dev/poll.
++
++
++nginx might hog CPU during SSL handshake with a backend
++if the select, poll, or /dev/poll methods were used.
++
++
++
++
++
++ошибка "[crit] SSL_write() failed (SSL:)".
++
++
++the "[crit] SSL_write() failed (SSL:)" error.
++
++
++
++
++
++в директиве client_body_in_file_only;
++ошибка появилась в 1.3.9.
++
++
++in the "client_body_in_file_only" directive;
++the bug had appeared in 1.3.9.
++
++
++
++
++
++в директиве fastcgi_keep_conn.
++
++
++in the "fastcgi_keep_conn" directive.
++
++
++
++
++
++
++
++
++
++
++при записи в лог мог происходить segmentation fault;
++ошибка появилась в 1.3.10.
++
++
++a segmentation fault might occur if logging was used;
++the bug had appeared in 1.3.10.
++
++
++
++
++
++директива proxy_pass не работала с IP-адресами
++без явного указания порта;
++ошибка появилась в 1.3.10.
++
++
++the "proxy_pass" directive did not work with IP addresses
++without port specified;
++the bug had appeared in 1.3.10.
++
++
++
++
++
++на старте или во время переконфигурации происходил segmentation fault,
++если директива keepalive была указана несколько раз
++в одном блоке upstream.
++
++
++a segmentation fault occurred on start or during reconfiguration
++if the "keepalive" directive was specified more than once
++in a single upstream block.
++
++
++
++
++
++параметр default директивы geo не определял значение по умолчанию
++для IPv6-адресов.
++
++
++parameter "default" of the "geo" directive did not set default value
++for IPv6 addresses.
++
++
++
++
++
++
++
++
++
++
++для указанных в конфигурационном файле доменных имён теперь
++используются не только IPv4, но и IPv6 адреса.
++
++
++domain names specified in configuration file
++are now resolved to IPv6 addresses as well as IPv4 ones.
++
++
++
++
++
++теперь при использовании директивы include с маской на Unix-системах
++включаемые файлы сортируются в алфавитном порядке.
++
++
++now if the "include" directive with mask is used on Unix systems,
++included files are sorted in alphabetical order.
++
++
++
++
++
++директива add_header добавляет строки в ответы с кодом 201.
++
++
++the "add_header" directive adds headers to 201 responses.
++
++
++
++
++
++директива geo теперь поддерживает IPv6 адреса в формате CIDR.
++
++
++the "geo" directive now supports IPv6 addresses in CIDR notation.
++
++
++
++
++
++параметры flush и gzip в директиве access_log.
++
++
++the "flush" and "gzip" parameters of the "access_log" directive.
++
++
++
++
++
++директива auth_basic поддерживает переменные.
++
++
++variables support in the "auth_basic" directive.
++
++
++
++
++
++nginx в некоторых случаях не собирался с модулем ngx_http_perl_module.
++
++
++nginx could not be built with the ngx_http_perl_module in some cases.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_xslt_module.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_xslt_module was used.
++
++
++
++
++
++nginx мог не собираться на MacOSX.
++Спасибо Piotr Sikora.
++
++
++nginx could not be built on MacOSX in some cases.
++Thanks to Piotr Sikora.
++
++
++
++
++
++при использовании директивы limit_rate с большими значениями скорости
++на 32-битных системах ответ мог возвращаться не целиком.
++Спасибо Алексею Антропову.
++
++
++the "limit_rate" directive with high rates
++might result in truncated responses on 32-bit platforms.
++Thanks to Alexey Antropov.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива if.
++Спасибо Piotr Sikora.
++
++
++a segmentation fault might occur in a worker process
++if the "if" directive was used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++ответ "100 Continue" выдавался
++вместе с ответом "413 Request Entity Too Large".
++
++
++a "100 Continue" response was issued
++with "413 Request Entity Too Large" responses.
++
++
++
++
++
++директивы image_filter, image_filter_jpeg_quality и image_filter_sharpen
++могли наследоваться некорректно.
++Спасибо Ивану Боброву.
++
++
++the "image_filter", "image_filter_jpeg_quality"
++and "image_filter_sharpen" directives
++might be inherited incorrectly.
++Thanks to Ian Babrou.
++
++
++
++
++
++при использовании директивы auth_basic под Linux
++могли возникать ошибки "crypt_r() failed".
++
++
++"crypt_r() failed" errors might appear
++if the "auth_basic" directive was used on Linux.
++
++
++
++
++
++в обработке backup-серверов.
++Спасибо Thomas Chen.
++
++
++in backup servers handling.
++Thanks to Thomas Chen.
++
++
++
++
++
++при проксировании HEAD-запросов мог возвращаться некорректный ответ,
++если использовалась директива gzip.
++
++
++proxied HEAD requests might return incorrect response
++if the "gzip" directive was used.
++
++
++
++
++
++
++
++
++
++
++поддержка chunked transfer encoding при получении тела запроса.
++
++
++support for chunked transfer encoding while reading client request body.
++
++
++
++
++
++переменные $request_time и $msec
++теперь можно использовать не только в директиве log_format.
++
++
++the $request_time and $msec variables
++can now be used not only in the "log_format" directive.
++
++
++
++
++
++cache manager и cache loader могли не запускаться,
++если использовалось более 512 listen-сокетов.
++
++
++cache manager and cache loader processes might not be able to start
++if more than 512 listen sockets were used.
++
++
++
++
++
++в модуле ngx_http_dav_module.
++
++
++in the ngx_http_dav_module.
++
++
++
++
++
++
++
++
++
++
++параметр optional_no_ca директивы ssl_verify_client.
++Спасибо Михаилу Казанцеву и Eric O'Connor.
++
++
++the "optional_no_ca" parameter of the "ssl_verify_client" directive.
++Thanks to Mike Kazantsev and Eric O'Connor.
++
++
++
++
++
++переменные $bytes_sent, $connection и $connection_requests
++теперь можно использовать не только в директиве log_format.
++Спасибо Benjamin Grössing.
++
++
++the $bytes_sent, $connection, and $connection_requests variables
++can now be used not only in the "log_format" directive.
++Thanks to Benjamin Grössing.
++
++
++
++
++
++параметр auto директивы worker_processes.
++
++
++the "auto" parameter of the "worker_processes" directive.
++
++
++
++
++
++сообщения "cache file ... has md5 collision".
++
++
++"cache file ... has md5 collision" alert.
++
++
++
++
++
++в модуле ngx_http_gunzip_filter_module.
++
++
++in the ngx_http_gunzip_filter_module.
++
++
++
++
++
++в директиве ssl_stapling.
++
++
++in the "ssl_stapling" directive.
++
++
++
++
++
++
++
++
++
++
++поддержка OCSP stapling.
++Спасибо Comodo, DigiCert и GlobalSign за спонсирование разработки.
++
++
++OCSP stapling support.
++Thanks to Comodo, DigiCert and GlobalSign for sponsoring this work.
++
++
++
++
++
++директива ssl_trusted_certificate.
++
++
++the "ssl_trusted_certificate" directive.
++
++
++
++
++
++теперь resolver случайным образом меняет порядок
++возвращаемых закэшированных адресов.
++Спасибо Антону Жулину.
++
++
++resolver now randomly rotates addresses
++returned from cache.
++Thanks to Anton Jouline.
++
++
++
++
++
++совместимость с OpenSSL 0.9.7.
++
++
++OpenSSL 0.9.7 compatibility.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_gunzip_filter_module.
++
++
++the ngx_http_gunzip_filter_module.
++
++
++
++
++
++директива memcached_gzip_flag.
++
++
++the "memcached_gzip_flag" directive.
++
++
++
++
++
++параметр always директивы gzip_static.
++
++
++the "always" parameter of the "gzip_static" directive.
++
++
++
++
++
++в директиве "limit_req";
++ошибка появилась в 1.1.14.
++Спасибо Charles Chen.
++
++
++in the "limit_req" directive;
++the bug had appeared in 1.1.14.
++Thanks to Charles Chen.
++
++
++
++
++
++nginx не собирался gcc 4.7 с оптимизацией -O2
++если использовался параметр --with-ipv6.
++
++
++nginx could not be built by gcc 4.7 with -O2 optimization
++if the --with-ipv6 option was used.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_mp4_module больше не отфильтровывает дорожки
++в форматах, отличных от H.264 и AAC.
++
++
++the ngx_http_mp4_module module no longer skips
++tracks in formats other than H.264 and AAC.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если в директиве map в качестве значений использовались переменные.
++
++
++a segmentation fault might occur in a worker process
++if the "map" directive was used with variables as values.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault
++при использовании директивы geo с параметром ranges,
++но без параметра default; ошибка появилась в 0.8.43.
++Спасибо Zhen Chen и Weibin Yao.
++
++
++a segmentation fault might occur in a worker process
++if the "geo" directive was used with the "ranges" parameter
++but without the "default" parameter; the bug had appeared in 0.8.43.
++Thanks to Zhen Chen and Weibin Yao.
++
++
++
++
++
++в обработке параметра командной строки -p.
++
++
++in the -p command-line parameter handling.
++
++
++
++
++
++в почтовом прокси-сервере.
++
++
++in the mail proxy server.
++
++
++
++
++
++незначительных потенциальных ошибок.
++Спасибо Coverity.
++
++
++of minor potential bugs.
++Thanks to Coverity.
++
++
++
++
++
++nginx/Windows не собирался с Visual Studio 2005 Express.
++Спасибо HAYASHI Kentaro.
++
++
++nginx/Windows could not be built with Visual Studio 2005 Express.
++Thanks to HAYASHI Kentaro.
++
++
++
++
++
++
++
++
++
++
++теперь на слушающих IPv6-сокетах параметр ipv6only
++включён по умолчанию.
++
++
++the "ipv6only" parameter is now turned on by default for
++listening IPv6 sockets.
++
++
++
++
++
++поддержка компилятора Clang.
++
++
++the Clang compiler support.
++
++
++
++
++
++могли создаваться лишние слушающие сокеты.
++Спасибо Роману Одайскому.
++
++
++extra listening sockets might be created.
++Thanks to Roman Odaisky.
++
++
++
++
++
++nginx/Windows мог нагружать процессор, если при запуске рабочего процесса
++происходила ошибка.
++Спасибо Ricardo Villalobos Guevara.
++
++
++nginx/Windows might hog CPU if a worker process failed to start.
++Thanks to Ricardo Villalobos Guevara.
++
++
++
++
++
++директивы proxy_pass_header, fastcgi_pass_header, scgi_pass_header,
++uwsgi_pass_header, proxy_hide_header, fastcgi_hide_header,
++scgi_hide_header и uwsgi_hide_header
++могли наследоваться некорректно.
++
++
++the "proxy_pass_header", "fastcgi_pass_header", "scgi_pass_header",
++"uwsgi_pass_header", "proxy_hide_header", "fastcgi_hide_header",
++"scgi_hide_header", and "uwsgi_hide_header" directives
++might be inherited incorrectly.
++
++
++
++
++
++
++
++
++
++
++поддержка entity tags и директива etag.
++
++
++entity tags support and the "etag" directive.
++
++
++
++
++
++при использовании директивы map с параметром hostnames
++не игнорировалась конечная точка в исходном значении.
++
++
++trailing dot in a source value was not ignored
++if the "map" directive was used with the "hostnames" parameter.
++
++
++
++
++
++для обработки запроса мог использоваться неверный location,
++если переход в именованный location происходил
++после изменения URI с помощью директивы rewrite.
++
++
++incorrect location might be used to process a request
++if a URI was changed via a "rewrite" directive
++before an internal redirect to a named location.
++
++
++
++
++
++
++
++
++
++
++параметр single директивы keepalive теперь игнорируется.
++
++
++the "single" parameter of the "keepalive" directive is now ignored.
++
++
++
++
++
++сжатие SSL теперь отключено
++в том числе при использовании OpenSSL старее 1.0.0.
++
++
++SSL compression is now disabled when using all versions of OpenSSL,
++including ones prior to 1.0.0.
++
++
++
++
++
++директиву "ip_hash" теперь можно использовать для балансировки IPv6 клиентов.
++
++
++it is now possible to use the "ip_hash" directive to balance IPv6 clients.
++
++
++
++
++
++переменную $status теперь можно использовать не только в директиве log_format.
++
++
++the $status variable can now be used not only in the "log_format" directive.
++
++
++
++
++
++при завершении рабочего процесса мог произойти segmentation fault,
++если использовалась директива resolver.
++
++
++a segmentation fault might occur in a worker process on shutdown
++if the "resolver" directive was used.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался модуль ngx_http_mp4_module.
++
++
++a segmentation fault might occur in a worker process
++if the ngx_http_mp4_module was used.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовались конфликтующие имена серверов с масками.
++
++
++a segmentation fault might occur in a worker process
++if conflicting wildcard server names were used.
++
++
++
++
++
++на платформе ARM nginx мог аварийно завершаться по сигналу SIGBUS.
++
++
++nginx might be terminated abnormally on a SIGBUS signal on ARM platform.
++
++
++
++
++
++во время переконфигурации на HP-UX в лог
++записывался alert "sendmsg() failed (9: Bad file number)".
++
++
++an alert "sendmsg() failed (9: Bad file number)" on HP-UX
++while reconfiguration.
++
++
++
++
++
++
++
++
++
++
++теперь nginx/Windows игнорирует точку в конце компонента URI
++и не разрешает URI, содержащие последовательность ":$".
++Спасибо Владимиру Кочеткову, Positive Research Center.
++
++
++now nginx/Windows ignores trailing dot in URI path component, and
++does not allow URIs with ":$" in it.
++Thanks to Vladimir Kochetkov, Positive Research Center.
++
++
++
++
++
++директивы proxy_pass, fastcgi_pass, scgi_pass, uwsgi_pass и
++директива server в блоке upstream
++теперь поддерживают IPv6-адреса.
++
++
++the "proxy_pass", "fastcgi_pass", "scgi_pass", "uwsgi_pass" directives, and
++the "server" directive inside the "upstream" block,
++now support IPv6 addresses.
++
++
++
++
++
++в директиве resolver теперь можно указывать порт и
++задавать IPv6-адреса DNS-серверов.
++
++
++the "resolver" directive now supports IPv6 addresses and
++an optional port specification.
++
++
++
++
++
++директива least_conn в блоке upstream.
++
++
++the "least_conn" directive inside the "upstream" block.
++
++
++
++
++
++при использовании директивы ip_hash
++теперь можно задавать веса серверов.
++
++
++it is now possible to specify a weight for servers
++while using the "ip_hash" directive.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива image_filter;
++ошибка появилась в 1.3.0.
++
++
++a segmentation fault might occur in a worker process
++if the "image_filter" directive was used;
++the bug had appeared in 1.3.0.
++
++
++
++
++
++nginx не собирался с модулем ngx_cpp_test_module;
++ошибка появилась в 1.1.12.
++
++
++nginx could not be built with ngx_cpp_test_module;
++the bug had appeared in 1.1.12.
++
++
++
++
++
++доступ к переменным из SSI и встроенного перла мог не работать после
++переконфигурации.
++Спасибо Yichun Zhang.
++
++
++access to variables from SSI and embedded perl module might not work after
++reconfiguration.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в модуле ngx_http_xslt_filter_module.
++Спасибо Kuramoto Eiji.
++
++
++in the ngx_http_xslt_filter_module.
++Thanks to Kuramoto Eiji.
++
++
++
++
++
++утечки памяти при использовании переменной $geoip_org.
++Спасибо Денису Латыпову.
++
++
++memory leak if $geoip_org variable was used.
++Thanks to Denis F. Latypoff.
++
++
++
++
++
++в директивах proxy_cookie_domain и proxy_cookie_path.
++
++
++in the "proxy_cookie_domain" and "proxy_cookie_path" directives.
++
++
++
++
++
++
++
++
++
++
++директива debug_connection теперь поддерживает IPv6-адреса
++и параметр "unix:".
++
++
++the "debug_connection" directive now supports IPv6 addresses
++and the "unix:" parameter.
++
++
++
++
++
++директива set_real_ip_from и параметр proxy
++директивы geo теперь поддерживают IPv6-адреса.
++
++
++the "set_real_ip_from" directive and the "proxy" parameter
++of the "geo" directive now support IPv6 addresses.
++
++
++
++
++
++директивы real_ip_recursive, geoip_proxy и geoip_proxy_recursive.
++
++
++the "real_ip_recursive", "geoip_proxy", and "geoip_proxy_recursive" directives.
++
++
++
++
++
++параметр proxy_recursive директивы geo.
++
++
++the "proxy_recursive" parameter of the "geo" directive.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива resolver.
++
++
++a segmentation fault might occur in a worker process
++if the "resolver" directive was used.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовались директивы fastcgi_pass, scgi_pass или uwsgi_pass
++и бэкенд возвращал некорректный ответ.
++
++
++a segmentation fault might occur in a worker process
++if the "fastcgi_pass", "scgi_pass", or "uwsgi_pass" directives were used
++and backend returned incorrect response.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива rewrite и в новых аргументах запроса в строке
++замены использовались переменные.
++
++
++a segmentation fault might occur in a worker process
++if the "rewrite" directive was used and new request arguments
++in a replacement used variables.
++
++
++
++
++
++nginx мог нагружать процессор,
++если было достигнуто ограничение на количество открытых файлов.
++
++
++nginx might hog CPU
++if the open file resource limit was reached.
++
++
++
++
++
++при использовании директивы proxy_next_upstream с параметром http_404
++nginx мог бесконечно перебирать бэкенды, если в блоке upstream был
++хотя бы один сервер с флагом backup.
++
++
++nginx might loop infinitely over backends
++if the "proxy_next_upstream" directive with the "http_404" parameter was used
++and there were backup servers specified in an upstream block.
++
++
++
++
++
++при использовании директивы ip_hash
++установка параметра down директивы server
++могла приводить к ненужному перераспределению клиентов между бэкендами.
++
++
++adding the "down" parameter of the "server" directive
++might cause unneeded client redistribution among backend servers
++if the "ip_hash" directive was used.
++
++
++
++
++
++утечки сокетов.
++Спасибо Yichun Zhang.
++
++
++socket leak.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в модуле ngx_http_fastcgi_module.
++
++
++in the ngx_http_fastcgi_module.
++
++
++
++
++
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива try_files;
++ошибка появилась в 1.1.19.
++
++
++a segmentation fault might occur in a worker process
++if the "try_files" directive was used;
++the bug had appeared in 1.1.19.
++
++
++
++
++
++ответ мог быть передан не полностью,
++если использовалось больше IOV_MAX буферов.
++
++
++response might be truncated
++if there were more than IOV_MAX buffers used.
++
++
++
++
++
++в работе параметра crop директивы image_filter.
++Спасибо Maxim Bublis.
++
++
++in the "crop" parameter of the "image_filter" directive.
++Thanks to Maxim Bublis.
++
++
++
++
++
++
++
++
++
++
++при обработке специально созданного mp4 файла модулем ngx_http_mp4_module
++могли перезаписываться области памяти рабочего процесса, что могло
++приводить к выполнению произвольного кода (CVE-2012-2089).
++Спасибо Matthew Daley.
++
++
++specially crafted mp4 file might allow to overwrite
++memory locations in a worker process
++if the ngx_http_mp4_module was used,
++potentially resulting in arbitrary code execution (CVE-2012-2089).
++Thanks to Matthew Daley.
++
++
++
++
++
++nginx/Windows мог завершаться аварийно.
++Спасибо Vincent Lee.
++
++
++nginx/Windows might be terminated abnormally.
++Thanks to Vincent Lee.
++
++
++
++
++
++nginx нагружал процессор, если все серверы в upstream'е были помечены
++флагом backup.
++
++
++nginx hogged CPU if all servers in an upstream were marked as "backup".
++
++
++
++
++
++директивы allow и deny могли наследоваться некорректно,
++если в них использовались IPv6 адреса.
++
++
++the "allow" and "deny" directives might be inherited incorrectly
++if they were used with IPv6 addresses.
++
++
++
++
++
++директивы modern_browser и ancient_browser
++могли наследоваться некорректно.
++
++
++the "modern_browser" and "ancient_browser" directives
++might be inherited incorrectly.
++
++
++
++
++
++таймауты могли работать некорректно на Solaris/SPARC.
++
++
++timeouts might be handled incorrectly on Solaris/SPARC.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++
++
++
++
++
++теперь keepalive соединения не запрещены для Safari по умолчанию.
++
++
++keepalive connections are no longer disabled for Safari by default.
++
++
++
++
++
++переменная $connection_requests.
++
++
++the $connection_requests variable.
++
++
++
++
++
++переменные $tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd и
++$tcpinfo_rcv_space.
++
++
++$tcpinfo_rtt, $tcpinfo_rttvar, $tcpinfo_snd_cwnd and
++$tcpinfo_rcv_space variables.
++
++
++
++
++
++директива worker_cpu_affinity теперь работает на FreeBSD.
++
++
++the "worker_cpu_affinity" directive now works on FreeBSD.
++
++
++
++
++
++директивы xslt_param и xslt_string_param.
++Спасибо Samuel Behan.
++
++
++the "xslt_param" and "xslt_string_param" directives.
++Thanks to Samuel Behan.
++
++
++
++
++
++в configure.
++Спасибо Piotr Sikora.
++
++
++in configure tests.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в модуле ngx_http_xslt_filter_module.
++
++
++in the ngx_http_xslt_filter_module.
++
++
++
++
++
++nginx не собирался на Debian GNU/Hurd.
++
++
++nginx could not be built on Debian GNU/Hurd.
++
++
++
++
++
++
++
++
++
++
++содержимое ранее освобождённой памяти могло быть отправлено клиенту,
++если бэкенд возвращал специально созданный ответ.
++Спасибо Matthew Daley.
++
++
++content of previously freed memory might be sent to a client
++if backend returned specially crafted response.
++Thanks to Matthew Daley.
++
++
++
++
++
++при использовании встроенного перла из SSI.
++Спасибо Matthew Daley.
++
++
++in the embedded perl module if used from SSI.
++Thanks to Matthew Daley.
++
++
++
++
++
++в модуле ngx_http_uwsgi_module.
++
++
++in the ngx_http_uwsgi_module.
++
++
++
++
++
++
++
++
++
++
++ограничение на количество одновременных подзапросов поднято до 200.
++
++
++the simultaneous subrequest limit has been raised to 200.
++
++
++
++
++
++параметр from в директиве disable_symlinks.
++
++
++the "from" parameter of the "disable_symlinks" directive.
++
++
++
++
++
++директивы return и error_page теперь могут использоваться для возврата
++перенаправлений с кодом 307.
++
++
++the "return" and "error_page" directives can now be used to return 307
++redirections.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива resolver
++и на глобальном уровне не была задана директива error_log.
++Спасибо Роману Арутюняну.
++
++
++a segmentation fault might occur in a worker process
++if the "resolver" directive was used
++and there was no "error_log" directive specified at global level.
++Thanks to Roman Arutyunyan.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовались директивы "proxy_http_version 1.1" или
++"fastcgi_keep_conn on".
++
++
++a segmentation fault might occur in a worker process
++if the "proxy_http_version 1.1" or "fastcgi_keep_conn on" directives
++were used.
++
++
++
++
++
++утечек памяти.
++Спасибо Lanshun Zhou.
++
++
++memory leaks.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++в директиве disable_symlinks.
++
++
++in the "disable_symlinks" directive.
++
++
++
++
++
++при использовании ZFS размер кэша на диске мог считаться некорректно;
++ошибка появилась в 1.0.1.
++
++
++on ZFS filesystem disk cache size might be calculated incorrectly;
++the bug had appeared in 1.0.1.
++
++
++
++
++
++nginx не собирался компилятором icc 12.1.
++
++
++nginx could not be built by the icc 12.1 compiler.
++
++
++
++
++
++nginx не собирался gcc на Solaris;
++ошибка появилась в 1.1.15.
++
++
++nginx could not be built by gcc on Solaris;
++the bug had appeared in 1.1.15.
++
++
++
++
++
++
++
++
++
++
++директива disable_symlinks.
++
++
++the "disable_symlinks" directive.
++
++
++
++
++
++директивы proxy_cookie_domain и proxy_cookie_path.
++
++
++the "proxy_cookie_domain" and "proxy_cookie_path" directives.
++
++
++
++
++
++nginx мог некорректно сообщать об ошибке "upstream prematurely closed
++connection" вместо "upstream sent too big header".
++Спасибо Feibo Li.
++
++
++nginx might log incorrect error "upstream prematurely closed connection"
++instead of correct "upstream sent too big header" one.
++Thanks to Feibo Li.
++
++
++
++
++
++nginx не собирался с модулем ngx_http_perl_module,
++если использовался параметр --with-openssl.
++
++
++nginx could not be built with the ngx_http_perl_module
++if the --with-openssl option was used.
++
++
++
++
++
++количество внутренних перенаправлений в именованные location'ы
++не ограничивалось.
++
++
++the number of internal redirects to named locations was not limited.
++
++
++
++
++
++вызов $r->flush() несколько раз подряд мог приводить к ошибкам
++в модуле ngx_http_gzip_filter_module.
++
++
++calling $r->flush() multiple times might cause errors
++in the ngx_http_gzip_filter_module.
++
++
++
++
++
++при использовании директивы proxy_store с SSI-подзапросами
++временные файлы могли не удаляться.
++
++
++temporary files might be not removed
++if the "proxy_store" directive was used with SSI includes.
++
++
++
++
++
++в некоторых случаях некэшируемые переменные (такие, как $args)
++возвращали старое пустое закэшированное значение.
++
++
++in some cases non-cacheable variables (such as the $args variable)
++returned old empty cached value.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если одновременно создавалось слишком много SSI-подзапросов;
++ошибка появилась в 0.7.25.
++
++
++a segmentation fault might occur in a worker process
++if too many SSI subrequests were issued simultaneously;
++the bug had appeared in 0.7.25.
++
++
++
++
++
++
++
++
++
++
++теперь можно указать несколько ограничений limit_req одновременно.
++
++
++multiple "limit_req" limits may be used simultaneously.
++
++
++
++
++
++в обработке ошибок при соединении с бэкендом.
++Спасибо Piotr Sikora.
++
++
++in error handling while connecting to a backend.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в обработке ошибок при использовании AIO на FreeBSD.
++
++
++in AIO error handling on FreeBSD.
++
++
++
++
++
++в инициализации библиотеки OpenSSL.
++
++
++in the OpenSSL library initialization.
++
++
++
++
++
++директивы proxy_redirect могли наследоваться некорректно.
++
++
++the "proxy_redirect" directives might be inherited incorrectly.
++
++
++
++
++
++утечки памяти при переконфигурации, если использовалась директива pcre_jit.
++
++
++memory leak during reconfiguration if the "pcre_jit" directive was used.
++
++
++
++
++
++
++
++
++
++
++параметры TLSv1.1 и TLSv1.2 в директиве ssl_protocols.
++
++
++the "TLSv1.1" and "TLSv1.2" parameters of the "ssl_protocols" directive.
++
++
++
++
++
++параметры директивы limit_req наследовались некорректно;
++ошибка появилась в 1.1.12.
++
++
++the "limit_req" directive parameters were not inherited correctly;
++the bug had appeared in 1.1.12.
++
++
++
++
++
++директива proxy_redirect некорректно обрабатывала заголовок Refresh
++при использовании регулярных выражений.
++
++
++the "proxy_redirect" directive incorrectly processed "Refresh" header
++if regular expression were used.
++
++
++
++
++
++директива proxy_cache_use_stale с параметром error не возвращала ответ из
++кэша, если все бэкенды были признаны неработающими.
++
++
++the "proxy_cache_use_stale" directive with "error" parameter did not return
++answer from cache if there were no live upstreams.
++
++
++
++
++
++директива worker_cpu_affinity могла не работать.
++
++
++the "worker_cpu_affinity" directive might not work.
++
++
++
++
++
++nginx не собирался на Solaris;
++ошибка появилась в 1.1.12.
++
++
++nginx could not be built on Solaris;
++the bug had appeared in 1.1.12.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++
++
++
++
++
++после перенаправления запроса с помощью директивы error_page
++директива proxy_pass без URI теперь использует изменённый URI.
++Спасибо Lanshun Zhou.
++
++
++a "proxy_pass" directive without URI part now uses changed URI
++after redirection with the "error_page" directive.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++директивы proxy/fastcgi/scgi/uwsgi_cache_lock,
++proxy/fastcgi/scgi/uwsgi_cache_lock_timeout.
++
++
++the "proxy/fastcgi/scgi/uwsgi_cache_lock",
++"proxy/fastcgi/scgi/uwsgi_cache_lock_timeout" directives.
++
++
++
++
++
++директива pcre_jit.
++
++
++the "pcre_jit" directive.
++
++
++
++
++
++SSI команда if поддерживает выделения в регулярных выражениях.
++
++
++the "if" SSI command supports captures in regular expressions.
++
++
++
++
++
++SSI команда if не работала внутри команды block.
++
++
++the "if" SSI command did not work inside the "block" command.
++
++
++
++
++
++директивы limit_conn_log_level и limit_req_log_level могли не работать.
++
++
++the "limit_conn_log_level" and "limit_req_log_level" directives might not work.
++
++
++
++
++
++директива limit_rate не позволяла передавать на полной скорости,
++даже если был указан очень большой лимит.
++
++
++the "limit_rate" directive did not allow to use full throughput,
++even if limit value was very high.
++
++
++
++
++
++директива sendfile_max_chunk не работала,
++если использовалась директива limit_rate.
++
++
++the "sendfile_max_chunk" directive did not work,
++if the "limit_rate" directive was used.
++
++
++
++
++
++если в директиве proxy_pass использовались переменные и не был указан URI,
++всегда использовался URI исходного запроса.
++
++
++a "proxy_pass" directive without URI part always used original request URI
++if variables were used.
++
++
++
++
++
++после перенаправления запроса с помощью директивы try_files
++директива proxy_pass без URI могла использовать URI исходного запроса.
++Спасибо Lanshun Zhou.
++
++
++a "proxy_pass" directive without URI part might use original request
++after redirection with the "try_files" directive.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++в модуле ngx_http_scgi_module.
++
++
++in the ngx_http_scgi_module.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++nginx не собирался на Solaris;
++ошибка появилась в 1.1.9.
++
++
++nginx could not be built on Solaris;
++the bug had appeared in 1.1.9.
++
++
++
++
++
++
++
++
++
++
++параметр so_keepalive в директиве listen.
++Спасибо Всеволоду Стахову.
++
++
++the "so_keepalive" parameter of the "listen" directive.
++Thanks to Vsevolod Stakhov.
++
++
++
++
++
++параметр if_not_empty в директивах fastcgi/scgi/uwsgi_param.
++
++
++the "if_not_empty" parameter of the "fastcgi/scgi/uwsgi_param" directives.
++
++
++
++
++
++переменная $https.
++
++
++the $https variable.
++
++
++
++
++
++директива proxy_redirect поддерживает переменные в первом параметре.
++
++
++the "proxy_redirect" directive supports variables in the first parameter.
++
++
++
++
++
++директива proxy_redirect поддерживает регулярные выражения.
++
++
++the "proxy_redirect" directive supports regular expressions.
++
++
++
++
++
++переменная $sent_http_cache_control могла содержать неверное значение при
++использовании директивы expires.
++Спасибо Yichun Zhang.
++
++
++the $sent_http_cache_control variable might contain a wrong value if the
++"expires" directive was used.
++Thanks to Yichun Zhang.
++
++
++
++
++
++директива read_ahead могла не работать при использовании совместно с
++try_files и open_file_cache.
++
++
++the "read_ahead" directive might not work combined with "try_files"
++and "open_file_cache".
++
++
++
++
++
++если в параметре inactive директивы proxy_cache_path
++было указано малое время,
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if small time was used in the "inactive" parameter of
++the "proxy_cache_path" directive.
++
++
++
++
++
++ответы из кэша могли зависать.
++
++
++responses from cache might hang.
++
++
++
++
++
++
++
++
++
++
++при использовании AIO на Linux в рабочем процессе происходил segmentation fault;
++ошибка появилась в 1.1.9.
++
++
++a segmentation fault occurred in a worker process if AIO was used on Linux;
++the bug had appeared in 1.1.9.
++
++
++
++
++
++
++
++
++
++
++теперь двойные кавычки экранируется при выводе SSI-командой echo.
++Спасибо Зауру Абасмирзоеву.
++
++
++now double quotes are encoded in an "echo" SSI-command output.
++Thanks to Zaur Abasmirzoev.
++
++
++
++
++
++параметр valid в директиве resolver. По умолчанию теперь
++используется TTL, возвращённый DNS-сервером.
++Спасибо Кириллу Коринскому.
++
++
++the "valid" parameter of the "resolver" directive. By default TTL
++returned by a DNS server is used.
++Thanks to Kirill A. Korinskiy.
++
++
++
++
++
++nginx мог перестать отвечать, если рабочий процесс завершался аварийно.
++
++
++nginx might hang after a worker process abnormal termination.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалось SNI;
++ошибка появилась в 1.1.2.
++
++
++a segmentation fault might occur in a worker process
++if SNI was used;
++the bug had appeared in 1.1.2.
++
++
++
++
++
++в директиве keepalive_disable;
++ошибка появилась в 1.1.8.
++Спасибо Александру Усову.
++
++
++in the "keepalive_disable" directive;
++the bug had appeared in 1.1.8.
++Thanks to Alexander Usov.
++
++
++
++
++
++сигнал SIGWINCH переставал работать после первого обновления исполняемого
++файла;
++ошибка появилась в 1.1.1.
++
++
++SIGWINCH signal did not work after first binary upgrade;
++the bug had appeared in 1.1.1.
++
++
++
++
++
++теперь ответы бэкендов, длина которых не соответствует заголовку
++Content-Length, не кэширутся.
++
++
++backend responses with length not matching "Content-Length" header line
++are no longer cached.
++
++
++
++
++
++в директиве scgi_param при использовании составных параметров.
++
++
++in the "scgi_param" directive, if complex parameters were used.
++
++
++
++
++
++в методе epoll.
++Спасибо Yichun Zhang.
++
++
++in the "epoll" event method.
++Thanks to Yichun Zhang.
++
++
++
++
++
++в модуле ngx_http_flv_module.
++Спасибо Piotr Sikora.
++
++
++in the ngx_http_flv_module.
++Thanks to Piotr Sikora.
++
++
++
++
++
++в модуле ngx_http_mp4_module.
++
++
++in the ngx_http_mp4_module.
++
++
++
++
++
++теперь nginx понимает IPv6-адреса в строке запроса и в заголовке Host.
++
++
++IPv6 addresses are now handled properly in a request line and in a "Host"
++request header line.
++
++
++
++
++
++директивы add_header и expires не работали для ответов с кодом 206,
++если запрос проксировался.
++
++
++"add_header" and "expires" directives did not work if a request was proxied
++and response status code was 206.
++
++
++
++
++
++nginx не собирался на FreeBSD 10.
++
++
++nginx could not be built on FreeBSD 10.
++
++
++
++
++
++nginx не собирался на AIX.
++
++
++nginx could not be built on AIX.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_limit_zone_module переименован в ngx_http_limit_conn_module.
++
++
++the ngx_http_limit_zone_module was renamed to the ngx_http_limit_conn_module.
++
++
++
++
++
++директива limit_zone заменена директивой limit_conn_zone с новым синтаксисом.
++
++
++the "limit_zone" directive was superseded by the "limit_conn_zone" directive
++with a new syntax.
++
++
++
++
++
++поддержка ограничения по нескольким limit_conn на одном уровне.
++
++
++support for multiple "limit_conn" limits on the same level.
++
++
++
++
++
++директива image_filter_sharpen.
++
++
++the "image_filter_sharpen" directive.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если resolver получил большой DNS-ответ.
++Спасибо Ben Hawkes.
++
++
++a segmentation fault might occur in a worker process
++if resolver got a big DNS response.
++Thanks to Ben Hawkes.
++
++
++
++
++
++в вычислении ключа для кэширования,
++если использовалась внутренняя реализация MD5;
++ошибка появилась в 1.0.4.
++
++
++in cache key calculation
++if internal MD5 implementation was used;
++the bug had appeared in 1.0.4.
++
++
++
++
++
++строки "If-Modified-Since", "If-Range" и им подобные в заголовке запроса
++клиента могли передаваться бэкенду при кэшировании; или не передаваться при
++выключенном кэшировании, если кэширование было включено в другой части
++конфигурации.
++
++
++the "If-Modified-Since", "If-Range", etc. client request header lines
++might be passed to backend while caching; or not passed without caching
++if caching was enabled in another part of the configuration.
++
++
++
++
++
++модуль ngx_http_mp4_module выдавал неверную строку "Content-Length"
++в заголовке ответа, использовался аргумент start.
++Спасибо Piotr Sikora.
++
++
++the module ngx_http_mp4_module sent incorrect "Content-Length" response
++header line if the "start" argument was used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++
++
++
++
++
++поддержка нескольких DNS серверов в директиве "resolver".
++Спасибо Кириллу Коринскому.
++
++
++support of several DNS servers in the "resolver" directive.
++Thanks to Kirill A. Korinskiy.
++
++
++
++
++
++на старте или во время переконфигурации происходил segmentation fault,
++если директива ssl использовалась на уровне http и не был указан
++ssl_certificate.
++
++
++a segmentation fault occurred on start or during reconfiguration
++if the "ssl" directive was used at http level and there was
++no "ssl_certificate" defined.
++
++
++
++
++
++уменьшено потребление памяти при проксировании больших файлов,
++если они буферизировались на диск.
++
++
++reduced memory consumption while proxying big files
++if they were buffered to disk.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовалась директива "proxy_http_version 1.1".
++
++
++a segmentation fault might occur in a worker process
++if "proxy_http_version 1.1" directive was used.
++
++
++
++
++
++в директиве "expires @time".
++
++
++in the "expires @time" directive.
++
++
++
++
++
++
++
++
++
++
++Изменение во внутреннем API: теперь при внутреннем редиректе
++в именованный location контексты модулей очищаются.
++По запросу Yichun Zhang.
++
++
++Change in internal API: now module context data are cleared
++while internal redirect to named location.
++Requested by Yichun Zhang.
++
++
++
++
++
++теперь если сервер, описанный в блоке upstream, был признан неработающим,
++то после истечения fail_timeout на него будет отправлен только один запрос;
++сервер будет считаться работающим, если успешно ответит на этот запрос.
++
++
++if a server in an upstream failed, only one request will be sent to it
++after fail_timeout; the server will be considered alive if it will
++successfully respond to the request.
++
++
++
++
++
++теперь символы 0x7F-0xFF в access_log записываются в виде \xXX.
++
++
++now the 0x7F-0xFF characters are escaped as \xXX in an access_log.
++
++
++
++
++
++директивы "proxy/fastcgi/scgi/uwsgi_ignore_headers" теперь поддерживают
++значения X-Accel-Limit-Rate, X-Accel-Buffering и X-Accel-Charset.
++
++
++"proxy/fastcgi/scgi/uwsgi_ignore_headers" directives support the following
++additional values: X-Accel-Limit-Rate, X-Accel-Buffering, X-Accel-Charset.
++
++
++
++
++
++уменьшение потребления памяти при использовании SSL.
++
++
++decrease of memory consumption if SSL is used.
++
++
++
++
++
++некоторые UTF-8 символы обрабатывались неправильно.
++Спасибо Алексею Куцу.
++
++
++some UTF-8 characters were processed incorrectly.
++Thanks to Alexey Kuts.
++
++
++
++
++
++директивы модуля ngx_http_rewrite_module, заданные на уровне server,
++применялись повторно, если для запроса не находилось ни одного location'а.
++
++
++the ngx_http_rewrite_module directives specified at "server" level were
++executed twice if no matching locations were defined.
++
++
++
++
++
++при использовании "aio sendfile" могла происходить утечка сокетов.
++
++
++a socket leak might occurred if "aio sendfile" was used.
++
++
++
++
++
++при использовании файлового AIO соединения с быстрыми клиентами
++могли быть закрыты по истечению send_timeout.
++
++
++connections with fast clients might be closed after send_timeout
++if file AIO was used.
++
++
++
++
++
++в модуле ngx_http_autoindex_module.
++
++
++in the ngx_http_autoindex_module.
++
++
++
++
++
++модуль ngx_http_mp4_module не поддерживал перемотку на 32-битных платформах.
++
++
++the module ngx_http_mp4_module did not support seeking on 32-bit platforms.
++
++
++
++
++
++
++
++
++
++
++директивы uwsgi_buffering и scgi_buffering.
++Спасибо Peter Smit.
++
++
++the "uwsgi_buffering" and "scgi_buffering" directives.
++Thanks to Peter Smit.
++
++
++
++
++
++при использовании proxy_cache_bypass могли быть закэшированы
++некэшируемые ответы.
++Спасибо John Ferlito.
++
++
++non-cacheable responses might be cached if "proxy_cache_bypass" directive
++was used.
++Thanks to John Ferlito.
++
++
++
++
++
++в модуле ngx_http_proxy_module при работе с бэкендами по HTTP/1.1.
++
++
++in HTTP/1.1 support in the ngx_http_proxy_module.
++
++
++
++
++
++закэшированные ответы с пустым телом возвращались некорректно;
++ошибка появилась в 0.8.31.
++
++
++cached responses with an empty body were returned incorrectly;
++the bug had appeared in 0.8.31.
++
++
++
++
++
++ответы с кодом 201 модуля ngx_http_dav_module были некорректны;
++ошибка появилась в 0.8.32.
++
++
++201 responses of the ngx_http_dav_module were incorrect;
++the bug had appeared in 0.8.32.
++
++
++
++
++
++в директиве return.
++
++
++in the "return" directive.
++
++
++
++
++
++при использовании директивы "ssl_session_cache builtin" происходил
++segmentation fault;
++ошибка появилась в 1.1.1.
++
++
++the "ssl_session_cache builtin" directive caused segmentation fault;
++the bug had appeared in 1.1.1.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_upstream_keepalive.
++
++
++the ngx_http_upstream_keepalive module.
++
++
++
++
++
++директива proxy_http_version.
++
++
++the "proxy_http_version" directive.
++
++
++
++
++
++директива fastcgi_keep_conn.
++
++
++the "fastcgi_keep_conn" directive.
++
++
++
++
++
++директива worker_aio_requests.
++
++
++the "worker_aio_requests" directive.
++
++
++
++
++
++если nginx был собран с файловым AIO,
++он не мог запускаться на Linux без поддержки AIO.
++
++
++if nginx was built --with-file-aio it could not be run on Linux
++kernel which did not support AIO.
++
++
++
++
++
++в обработке ошибок при работе с Linux AIO.
++
++Спасибо Hagai Avrahami.
++
++
++in Linux AIO error processing.
++
++Thanks to Hagai Avrahami.
++
++
++
++
++
++уменьшено потребление памяти для долгоживущих запросов.
++
++
++reduced memory consumption for long-lived requests.
++
++
++
++
++
++модуль ngx_http_mp4_module не поддерживал 64-битный MP4-атом co64.
++
++
++the module ngx_http_mp4_module did not support 64-bit MP4 "co64" atom.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_mp4_module.
++
++
++the module ngx_http_mp4_module.
++
++
++
++
++
++в Linux AIO, используемым совместно с open_file_cache.
++
++
++in Linux AIO combined with open_file_cache.
++
++
++
++
++
++open_file_cache не обновлял информацию о файле,
++если файл был изменён не атомарно.
++
++
++open_file_cache did not update file info on retest
++if file was not atomically changed.
++
++
++
++
++
++nginx не собирался на MacOSX 10.7.
++
++
++nginx could not be built on MacOSX 10.7.
++
++
++
++
++
++
++
++
++
++
++теперь, если суммарный размер всех диапазонов больше размера исходного ответа,
++то nginx возвращает только исходный ответ, не обрабатывая диапазоны.
++
++
++now if total size of all ranges is greater than source response size,
++then nginx disables ranges and returns just the source response.
++
++
++
++
++
++директива max_ranges.
++
++
++the "max_ranges" directive.
++
++
++
++
++
++директивы ssl_verify_client, ssl_verify_depth и ssl_prefer_server_cipher
++могли работать некорректно, если использовался SNI.
++
++
++the "ssl_verify_client", "ssl_verify_depth", and "ssl_prefer_server_ciphers"
++directives might work incorrectly if SNI was used.
++
++
++
++
++
++в директивах proxy/fastcgi/scgi/ uwsgi_ignore_client_abort.
++
++
++in the "proxy/fastcgi/scgi/uwsgi_ignore_client_abort" directives.
++
++
++
++
++
++
++
++
++
++
++теперь загрузчик кэша за каждую итерацию либо обрабатывает число файлов,
++указанное в параметре load_files, либо работает не дольше времени,
++указанного в параметре loader_threshold.
++
++
++now cache loader processes either as many files as specified by "loader_files"
++parameter or works no longer than time specified by the "loader_threshold"
++parameter during each iteration.
++
++
++
++
++
++SIGWINCH сигнал теперь работает только в режиме демона.
++
++
++now SIGWINCH signal works only in daemon mode.
++
++
++
++
++
++теперь разделяемые зоны и кэши используют семафоры POSIX на Solaris.
++Спасибо Денису Иванову.
++
++
++now shared zones and caches use POSIX semaphores on Solaris.
++Thanks to Den Ivanov.
++
++
++
++
++
++теперь на NetBSD поддерживаются accept фильтры.
++
++
++accept filters are now supported on NetBSD.
++
++
++
++
++
++nginx не собирался на Linux 3.0.
++
++
++nginx could not be built on Linux 3.0.
++
++
++
++
++
++в некоторых случаях nginx не использовал сжатие;
++ошибка появилась в 1.1.0.
++
++
++nginx did not use gzipping in some cases;
++the bug had appeared in 1.1.0.
++
++
++
++
++
++обработка тела запроса могла быть неверной, если клиент использовал pipelining.
++
++
++request body might be processed incorrectly if client used pipelining.
++
++
++
++
++
++в директиве request_body_in_single_buf.
++
++
++in the "request_body_in_single_buf" directive.
++
++
++
++
++
++в директивах proxy_set_body и proxy_pass_request_body
++при использовании SSL-соединения с бэкендом.
++
++
++in "proxy_set_body" and "proxy_pass_request_body" directives
++if SSL connection to backend was used.
++
++
++
++
++
++nginx нагружал процессор, если все серверы в upstream'е были помечены
++флагом down.
++
++
++nginx hogged CPU if all servers in an upstream were marked as "down".
++
++
++
++
++
++при переконфигурации мог произойти segmentation fault,
++если в предыдущей конфигурации был определён, но не использовался
++ssl_session_cache.
++
++
++a segmentation fault might occur during reconfiguration
++if ssl_session_cache was defined but not used in previous configuration.
++
++
++
++
++
++при использовании большого количества backup-серверов
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in a worker process
++if many backup servers were used in an upstream.
++
++
++
++
++
++при использовании директив fastcgi/scgi/uwsgi_param
++со значениями, начинающимися со строки "HTTP_",
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.8.40.
++
++
++a segmentation fault might occur in a worker process
++if "fastcgi/scgi/uwsgi_param" directives were used
++with values starting with "HTTP_";
++the bug had appeared in 0.8.40.
++
++
++
++
++
++
++
++
++
++
++уменьшение времени работы загрузчика кэша.
++
++
++cache loader run time decrease.
++
++
++
++
++
++параметры loader_files, loader_sleep и loader_threshold
++директив proxy/fastcgi/scgi/uwsgi_cache_path.
++
++
++"loader_files", "loader_sleep", and "loader_threshold" options
++of the "proxy/fastcgi/scgi/uwsgi_cache_path" directives.
++
++
++
++
++
++уменьшение времени загрузки конфигураций с большим количеством HTTPS серверов.
++
++
++loading time decrease of configuration with large number of HTTPS sites.
++
++
++
++
++
++теперь nginx поддерживает шифры с обменом ECDHE-ключами.
++Спасибо Adrian Kotelba.
++
++
++now nginx supports ECDHE key exchange ciphers.
++Thanks to Adrian Kotelba.
++
++
++
++
++
++директива lingering_close.
++Спасибо Максиму Дунину.
++
++
++the "lingering_close" directive.
++Thanks to Maxim Dounin.
++
++
++
++
++
++закрытия соединения для pipelined-запросов.
++Спасибо Максиму Дунину.
++
++
++in closing connection for pipelined requests.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не запрещал сжатие при получении значения "gzip;q=0"
++в строке "Accept-Encoding" в заголовке запроса клиента.
++
++
++nginx did not disable gzipping if client sent "gzip;q=0" in
++"Accept-Encoding" request header line.
++
++
++
++
++
++таймаута при небуферизированном проксировании.
++Спасибо Максиму Дунину.
++
++
++in timeout in unbuffered proxied mode.
++Thanks to Maxim Dounin.
++
++
++
++
++
++утечки памяти при использовании переменных в директиве proxy_pass
++при работе с бэкендом по HTTPS.
++Спасибо Максиму Дунину.
++
++
++memory leaks when a "proxy_pass" directive contains variables and proxies
++to an HTTPS backend.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в проверке параметра директивы proxy_pass, заданного переменными.
++Спасибо Lanshun Zhou.
++
++
++in parameter validation of a "proxy_pass" directive with variables.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++SSL не работал на QNX.
++Спасибо Максиму Дунину.
++
++
++SSL did not work on QNX.
++Thanks to Maxim Dounin.
++
++
++
++
++
++SSL модули не собирались gcc 4.6 без параметра --with-debug.
++
++
++SSL modules could not be built by gcc 4.6 without --with-debug option.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию используются следующие шифры SSL: "HIGH:!aNULL:!MD5".
++Спасибо Rob Stradling.
++
++
++now default SSL ciphers are "HIGH:!aNULL:!MD5".
++Thanks to Rob Stradling.
++
++
++
++
++
++директивы referer_hash_max_size и referer_hash_bucket_size.
++Спасибо Witold Filipczyk.
++
++
++the "referer_hash_max_size" and "referer_hash_bucket_size"
++directives.
++Thanks to Witold Filipczyk.
++
++
++
++
++
++переменная $uid_reset.
++
++
++$uid_reset variable.
++
++
++
++
++
++при использовании кэширования
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Lanshun Zhou.
++
++
++a segmentation fault might occur in a worker process,
++if a caching was used.
++Thanks to Lanshun Zhou.
++
++
++
++
++
++при использовании кэширования рабочие процессы
++могли зациклиться во время переконфигурации;
++ошибка появилась в 0.8.48.
++Спасибо Максиму Дунину.
++
++
++worker processes may got caught in an endless loop during reconfiguration,
++if a caching was used;
++the bug had appeared in 0.8.48.
++Thanks to Maxim Dounin.
++
++
++
++
++
++сообщения "stalled cache updating".
++Спасибо Максиму Дунину.
++
++
++"stalled cache updating" alert.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++теперь в регулярных выражениях в директиве map можно задать
++чувствительность к регистру с помощью префиксов "~" и "~*".
++
++
++now regular expressions case sensitivity in the "map" directive
++is given by prefixes "~" or "~*".
++
++
++
++
++
++теперь разделяемые зоны и кэши используют семафоры POSIX на Linux.
++Спасибо Денису Латыпову.
++
++
++now shared zones and caches use POSIX semaphores on Linux.
++Thanks to Denis F. Latypoff.
++
++
++
++
++
++сообщения "stalled cache updating".
++
++
++"stalled cache updating" alert.
++
++
++
++
++
++nginx не собирался с параметром --without-http_auth_basic_module;
++ошибка появилась в 1.0.3.
++
++
++nginx could not be built --without-http_auth_basic_module;
++the bug had appeared in 1.0.3.
++
++
++
++
++
++
++
++
++
++
++директива auth_basic_user_file поддерживает шифрование пароля
++методами "$apr1", "{PLAIN}" и "{SSHA}".
++Спасибо Максиму Дунину.
++
++
++the "auth_basic_user_file" directive supports "$apr1", "{PLAIN}",
++and "{SSHA}" password encryption methods.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директива geoip_org и переменная $geoip_org.
++Спасибо Александру Ускову, Arnaud Granal и Денису Латыпову.
++
++
++the "geoip_org" directive and $geoip_org variable.
++Thanks to Alexander Uskov, Arnaud Granal, and Denis F. Latypoff.
++
++
++
++
++
++модули ngx_http_geo_module и ngx_http_geoip_module поддерживают
++адреса IPv4, отображённые на IPv6 адреса.
++
++
++ngx_http_geo_module and ngx_http_geoip_module support IPv4 addresses
++mapped to IPv6 addresses.
++
++
++
++
++
++при проверке адреса IPv4, отображённого на адрес IPv6,
++в рабочем процессе происходил segmentation fault,
++если директивы access или deny были определены только для адресов IPv6;
++ошибка появилась в 0.8.22.
++
++
++a segmentation fault occurred in a worker process
++during testing IPv4 address mapped to IPv6 address,
++if access or deny rules were defined only for IPv6;
++the bug had appeared in 0.8.22.
++
++
++
++
++
++закэшированный ответ мог быть испорчен, если значения директив
++proxy/fastcgi/scgi/uwsgi_cache_bypass и proxy/fastcgi/scgi/ uwsgi_no_cache
++были разными;
++ошибка появилась в 0.8.46.
++
++
++a cached response may be broken if "proxy/fastcgi/scgi/ uwsgi_cache_bypass"
++and "proxy/fastcgi/scgi/uwsgi_no_cache" directive values were different;
++the bug had appeared in 0.8.46.
++
++
++
++
++
++
++
++
++
++
++теперь разделяемые зоны и кэши используют семафоры POSIX.
++
++
++now shared zones and caches use POSIX semaphores.
++
++
++
++
++
++в работе параметра rotate директивы image_filter.
++Спасибо Adam Bocim.
++
++
++in the "rotate" parameter of the "image_filter" directive.
++Thanks to Adam Bocim.
++
++
++
++
++
++nginx не собирался на Solaris;
++ошибка появилась в 1.0.1.
++
++
++nginx could not be built on Solaris;
++the bug had appeared in 1.0.1.
++
++
++
++
++
++
++
++
++
++
++теперь директива split_clients использует алгоритм MurmurHash2 из-за
++лучшего распределения.
++Спасибо Олегу Мамонтову.
++
++
++now the "split_clients" directive uses MurmurHash2 algorithm because
++of better distribution.
++Thanks to Oleg Mamontov.
++
++
++
++
++
++теперь длинные строки, начинающиеся с нуля, не считаются ложными
++значениями.
++Спасибо Максиму Дунину.
++
++
++now long strings starting with zero are not considered as false values.
++Thanks to Maxim Dounin.
++
++
++
++
++
++теперь по умолчанию nginx использует значение 511 для listen backlog на Linux.
++
++
++now nginx uses a default listen backlog value 511 on Linux.
++
++
++
++
++
++переменные $upstream_... можно использовать в SSI и перловом модулях.
++
++
++the $upstream_... variables may be used in the SSI and perl modules.
++
++
++
++
++
++теперь nginx лучше ограничивает размер кэша на диске.
++Спасибо Олегу Мамонтову.
++
++
++now nginx limits better disk cache size.
++Thanks to Oleg Mamontov.
++
++
++
++
++
++при парсинге неправильного IPv4 адреса мог произойти segmentation fault;
++ошибка появилась в 0.8.22.
++Спасибо Максиму Дунину.
++
++
++a segmentation fault might occur while parsing incorrect IPv4 address;
++the bug had appeared in 0.9.3.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не собирался gcc 4.6 без параметра --with-debug.
++
++
++nginx could not be built by gcc 4.6 without --with-debug option.
++
++
++
++
++
++nginx не собирался на Solaris 9 и более ранних;
++ошибка появилась в 0.9.3.
++Спасибо Dagobert Michelsen.
++
++
++nginx could not be built on Solaris 9 and earlier;
++the bug had appeared in 0.9.3.
++Thanks to Dagobert Michelsen.
++
++
++
++
++
++переменная $request_time имела неверные значения, если использовались
++подзапросы;
++ошибка появилась в 0.8.47.
++Спасибо Игорю А. Валькову.
++
++
++$request_time variable had invalid values if subrequests were used;
++the bug had appeared in 0.8.47.
++Thanks to Igor A. Valcov.
++
++
++
++
++
++
++
++
++
++
++cache manager мог нагружать процессор после переконфигурации.
++Спасибо Максиму Дунину.
++
++
++a cache manager might hog CPU after reload.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директива "image_filter crop" неправильно работала в сочетании с
++"image_filter rotate 180".
++
++
++an "image_filter crop" directive worked incorrectly coupled with
++an "image_filter rotate 180" directive.
++
++
++
++
++
++директива "satisfy any" запрещала выдачу пользовательской страницы
++для 401 кода.
++
++
++a "satisfy any" directive disabled custom 401 error page.
++
++
++
++
++
++
++
++
++
++
++теперь соединения в состоянии keepalive могут быть закрыты преждевременно,
++если у воркера нет свободных соединений.
++Спасибо Максиму Дунину.
++
++
++now keepalive connections may be closed premature,
++if there are no free worker connections.
++Thanks to Maxim Dounin.
++
++
++
++
++
++параметр rotate директивы image_filter.
++Спасибо Adam Bocim.
++
++
++the "rotate" parameter of the "image_filter" directive.
++Thanks to Adam Bocim.
++
++
++
++
++
++ситуации, когда бэкенд в директивах fastcgi_pass, scgi_pass или uwsgi_pass
++задан выражением и ссылается на описанный upstream.
++
++
++a case when a backend in "fastcgi_pass", "scgi_pass", or "uwsgi_pass"
++directives is given by expression and refers to a defined upstream.
++
++
++
++
++
++
++
++
++
++
++директива map поддерживает регулярные выражения в качестве значения
++первого параметра.
++
++
++the "map" directive supports regular expressions as value of the first
++parameter.
++
++
++
++
++
++переменная $time_iso8601 для access_log.
++Спасибо Michael Lustfield.
++
++
++$time_iso8601 access_log variable.
++Thanks to Michael Lustfield.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию nginx использует значение -1 для listen backlog
++на Linux.
++Спасибо Андрею Нигматулину.
++
++
++now nginx uses a default listen backlog value -1 on Linux.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++параметр utf8 в директивах geoip_country и geoip_city.
++Спасибо Денису Латыпову.
++
++
++the "utf8" parameter of "geoip_country" and "geoip_city" directives.
++Thanks to Denis F. Latypoff.
++
++
++
++
++
++исправление в умолчательной директиве proxy_redirect, если в директиве
++proxy_pass не был описан URI.
++Спасибо Максиму Дунину.
++
++
++in a default "proxy_redirect" directive if "proxy_pass" directive has no
++URI part.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директива error_page не работала с нестандартными кодами ошибок;
++ошибка появилась в 0.8.53.
++Спасибо Максиму Дунину.
++
++
++an "error_page" directive did not work with nonstandard error codes;
++the bug had appeared in 0.8.53.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++директива server_name поддерживает переменную $hostname.
++
++
++the "server_name" directive supports the $hostname variable.
++
++
++
++
++
++494 код для ошибки "Request Header Too Large".
++
++
++494 code for "Request Header Too Large" error.
++
++
++
++
++
++
++
++
++
++
++если для пары IPv6-адрес:порт описан только один сервер, то выделения
++в регулярных выражениях в директиве server_name не работали.
++
++
++if there was a single server for given IPv6 address:port pair,
++then captures in regular expressions in a "server_name" directive did not work.
++
++
++
++
++
++nginx не собирался под Solaris;
++ошибка появилась в 0.9.0.
++
++
++nginx could not be built on Solaris;
++the bug had appeared in 0.9.0.
++
++
++
++
++
++
++
++
++
++
++поддержка строки "If-Unmodified-Since" в заголовке запроса клиента.
++
++
++the "If-Unmodified-Since" client request header line support.
++
++
++
++
++
++использование accept(), если accept4() не реализован;
++ошибка появилась в 0.9.0.
++
++
++fallback to accept() syscall if accept4() was not implemented;
++the issue had appeared in 0.9.0.
++
++
++
++
++
++nginx не собирался под Cygwin;
++ошибка появилась в 0.9.0.
++
++
++nginx could not be built on Cygwin;
++the bug had appeared in 0.9.0.
++
++
++
++
++
++уязвимости в OpenSSL CVE-2010-4180.
++Спасибо Максиму Дунину.
++
++
++for OpenSSL vulnerability CVE-2010-4180.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++директивы вида "return CODE message" не работали;
++ошибка появилась в 0.9.0.
++
++
++"return CODE message" directives did not work;
++the bug had appeared in 0.9.0.
++
++
++
++
++
++
++
++
++
++
++директива keepalive_disable.
++
++
++the "keepalive_disable" directive.
++
++
++
++
++
++директива map поддерживает переменные в качестве значения определяемой
++переменной.
++
++
++the "map" directive supports variables as value of a defined variable.
++
++
++
++
++
++директива map поддерживает пустые строки в качестве значения первого параметра.
++
++
++the "map" directive supports empty strings as value of the first parameter.
++
++
++
++
++
++директива map поддерживает выражения в первом параметре.
++
++
++the "map" directive supports expressions as the first parameter.
++
++
++
++
++
++страница руководства nginx(8).
++Спасибо Сергею Осокину.
++
++
++nginx(8) manual page.
++Thanks to Sergey Osokin.
++
++
++
++
++
++поддержка accept4() в Linux.
++Спасибо Simon Liu.
++
++
++Linux accept4() support.
++Thanks to Simon Liu.
++
++
++
++
++
++устранение предупреждения линкера о "sys_errlist" и "sys_nerr" под Linux;
++предупреждение появилось в 0.8.35.
++
++
++elimination of Linux linker warning about "sys_errlist" and "sys_nerr";
++the warning had appeared in 0.8.35.
++
++
++
++
++
++при использовании директивы auth_basic
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Михаилу Лалетину.
++
++
++a segmentation fault might occur in a worker process,
++if the "auth_basic" directive was used.
++Thanks to Michail Laletin.
++
++
++
++
++
++совместимость с модулем ngx_http_eval_module;
++ошибка появилась в 0.8.42.
++
++
++compatibility with ngx_http_eval_module;
++the bug had appeared in 0.8.42.
++
++
++
++
++
++
++
++
++
++
++теперь директива error_page позволяет менять код статуса у редиректа.
++
++
++now the "error_page" directive allows to change a status code in a redirect.
++
++
++
++
++
++директива gzip_disable поддерживает специальную маску degradation.
++
++
++the "gzip_disable" directive supports special "degradation" mask.
++
++
++
++
++
++при использовании файлового AIO могла происходить утечка сокетов.
++Спасибо Максиму Дунину.
++
++
++a socket leak might occurred if file AIO was used.
++Thanks to Maxim Dounin.
++
++
++
++
++
++если в первом сервере не была описана директива listen и нигде явно
++не описан сервер по умолчанию, то сервером по умолчанию становился
++следующий сервер с директивой listen;
++ошибка появилась в 0.8.21.
++
++
++if the first server had no "listen" directive and there was no explicit
++default server, then a next server with a "listen" directive became
++the default server;
++the bug had appeared in 0.8.21.
++
++
++
++
++
++
++
++
++
++
++nginx использовал режим SSL для listen сокета, если для него был
++установлен любой listen-параметр;
++ошибка появилась в 0.8.51.
++
++
++nginx used SSL mode for a listen socket if any listen option was set;
++the bug had appeared in 0.8.51.
++
++
++
++
++
++
++
++
++
++
++директива secure_link_expires упразднена.
++
++
++the "secure_link_expires" directive has been canceled.
++
++
++
++
++
++уровень логгирования ошибок resolver'а понижен с уровня alert на error.
++
++
++a logging level of resolver errors has been lowered from "alert" to "error".
++
++
++
++
++
++теперь параметр "ssl" listen-сокета можно устанавливать несколько раз.
++
++
++now a listen socket "ssl" parameter may be set several times.
++
++
++
++
++
++
++
++
++
++
++директивы secure_link, secure_link_md5 и secure_link_expires
++модуля ngx_http_secure_link_module.
++
++
++the "secure_link", "secure_link_md5", and "secure_link_expires" directives of
++the ngx_http_secure_link_module.
++
++
++
++
++
++ключ -q.
++Спасибо Геннадию Махомеду.
++
++
++the -q switch.
++Thanks to Gena Makhomed.
++
++
++
++
++
++при использовании кэширования рабочие процессы и могли зациклиться
++во время переконфигурации;
++ошибка появилась в 0.8.48.
++
++
++worker processes may got caught in an endless loop during reconfiguration,
++if a caching was used;
++the bug had appeared in 0.8.48.
++
++
++
++
++
++в директиве gzip_disable.
++Спасибо Derrick Petzold.
++
++
++in the "gzip_disable" directive.
++Thanks to Derrick Petzold.
++
++
++
++
++
++nginx/Windows не мог посылать сигналы stop, quit, reopen, reload процессу,
++запущенному в другой сессии.
++
++
++nginx/Windows could not send stop, quit, reopen, and reload signals
++to a process run in other session.
++
++
++
++
++
++
++
++
++
++
++директива image_filter_jpeg_quality поддерживает переменные.
++
++
++the "image_filter_jpeg_quality" directive supports variables.
++
++
++
++
++
++при использовании переменной $geoip_region_name
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.8.48.
++
++
++a segmentation fault might occur in a worker process,
++if the $geoip_region_name variables was used;
++the bug had appeared in 0.8.48.
++
++
++
++
++
++ошибки, перехваченные error_page, кэшировались только до следующего запроса;
++ошибка появилась в 0.8.48.
++
++
++errors intercepted by error_page were cached only for next request;
++the bug had appeared in 0.8.48.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию директива server_name имеет значение пустое имя "".
++Спасибо Геннадию Махомеду.
++
++
++now the "server_name" directive default value is an empty name "".
++Thanks to Gena Makhomed.
++
++
++
++
++
++теперь по умолчанию директива server_name_in_redirect имеет значение off.
++
++
++now the "server_name_in_redirect" directive default value is "off".
++
++
++
++
++
++переменные $geoip_dma_code, $geoip_area_code и $geoip_region_name.
++Спасибо Christine McGonagle.
++
++
++the $geoip_dma_code, $geoip_area_code, and $geoip_region_name variables.
++Thanks to Christine McGonagle.
++
++
++
++
++
++директивы proxy_pass, fastcgi_pass, uwsgi_pass и scgi_pass не наследовались
++в блоки limit_except.
++
++
++the "proxy_pass", "fastcgi_pass", "uwsgi_pass", and "scgi_pass" directives
++were not inherited inside "limit_except" blocks.
++
++
++
++
++
++директивы proxy_cache_min_uses, fastcgi_cache_min_uses
++uwsgi_cache_min_uses и scgi_cache_min_uses не работали;
++ошибка появилась в 0.8.46.
++
++
++the "proxy_cache_min_uses", "fastcgi_cache_min_uses"
++"uwsgi_cache_min_uses", and "scgi_cache_min_uses" directives did not work;
++the bug had appeared in 0.8.46.
++
++
++
++
++
++директива fastcgi_split_path_info неверно использовала выделения,
++если в выделения попадала только часть URI.
++Спасибо Юрию Тарадаю и Frank Enderle.
++
++
++the "fastcgi_split_path_info" directive used incorrectly captures,
++if only parts of an URI were captured.
++Thanks to Yuriy Taraday and Frank Enderle.
++
++
++
++
++
++директива rewrite не экранировала символ ";" при копировании из URI
++в аргументы.
++Спасибо Daisuke Murase.
++
++
++the "rewrite" directive did not escape a ";" character during copying
++from URI to query string.
++Thanks to Daisuke Murase.
++
++
++
++
++
++модуль ngx_http_image_filter_module закрывал соединение,
++если изображение было больше размера image_filter_buffer.
++
++
++the ngx_http_image_filter_module closed a connection,
++if an image was larger than "image_filter_buffer" size.
++
++
++
++
++
++
++
++
++
++
++переменная $request_time имела неверные значения для подзапросов.
++
++
++$request_time variable had invalid values for subrequests.
++
++
++
++
++
++ошибки, перехваченные error_page, не кэшировались.
++
++
++errors intercepted by error_page could not be cached.
++
++
++
++
++
++если использовался параметр max_size, то cache manager мог зациклиться;
++ошибка появилась в 0.8.46.
++
++
++a cache manager process may got caught in an endless loop,
++if max_size parameter was used;
++the bug had appeared in 0.8.46.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_no_cache, fastcgi_no_cache, uwsgi_no_cache
++и scgi_no_cache теперь влияют только на сохранение закэшированного ответа.
++
++
++now the "proxy_no_cache", "fastcgi_no_cache", "uwsgi_no_cache", and
++"scgi_no_cache" directives affect on a cached response saving only.
++
++
++
++
++
++директивы proxy_cache_bypass, fastcgi_cache_bypass, uwsgi_cache_bypass
++и scgi_cache_bypass.
++
++
++the "proxy_cache_bypass", "fastcgi_cache_bypass", "uwsgi_cache_bypass",
++and "scgi_cache_bypass" directives.
++
++
++
++
++
++nginx не освобождал память в keys_zone кэшей в случае ошибки работы с
++бэкендом: память освобождалась только по истечении времени неактивности
++или при недостатке памяти.
++
++
++nginx did not free memory in cache keys zones if there was an error
++during working with backend: the memory was freed only after inactivity
++time or on memory low condition.
++
++
++
++
++
++
++
++
++
++
++улучшения в модуле ngx_http_xslt_filter.
++Спасибо Laurence Rowe.
++
++
++ngx_http_xslt_filter improvements.
++Thanks to Laurence Rowe.
++
++
++
++
++
++ответ SSI модуля мог передаваться не полностью после команды include
++с параметром wait="yes";
++ошибка появилась в 0.7.25.
++Спасибо Максиму Дунину.
++
++
++SSI response might be truncated after include with wait="yes";
++the bug had appeared in 0.7.25.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директива listen не поддерживала параметр setfib=0.
++
++
++the "listen" directive did not support the "setfib=0" parameter.
++
++
++
++
++
++
++
++
++
++
++теперь nginx по умолчанию не кэширует ответы бэкендов,
++в заголовке которых есть строка "Set-Cookie".
++
++
++now nginx does not cache by default backend responses,
++if they have a "Set-Cookie" header line.
++
++
++
++
++
++директива listen поддерживает параметр setfib.
++Спасибо Андрею Филонову.
++
++
++the "listen" directive supports the "setfib" parameter.
++Thanks to Andrew Filonov.
++
++
++
++
++
++директива sub_filter могла изменять регистр букв при частичном совпадении.
++
++
++the "sub_filter" directive might change character case on partial match.
++
++
++
++
++
++совместимость с HP/UX.
++
++
++compatibility with HP/UX.
++
++
++
++
++
++совместимость с компилятором AIX xlC_r.
++
++
++compatibility with AIX xlC_r compiler.
++
++
++
++
++
++nginx считал большие пакеты SSLv2 как обычные текстовые запросы.
++Спасибо Miroslaw Jaworski.
++
++
++nginx treated large SSLv2 packets as plain requests.
++Thanks to Miroslaw Jaworski.
++
++
++
++
++
++
++
++
++
++
++ускорение загрузки больших баз geo-диапазонов.
++
++
++large geo ranges base loading speed-up.
++
++
++
++
++
++перенаправление ошибки в "location /zero {return 204;}" без изменения
++кода ответа оставляло тело ошибки;
++ошибка появилась в 0.8.42.
++
++
++an error_page redirection to "location /zero {return 204;}" without
++changing status code kept the error body;
++the bug had appeared in 0.8.42.
++
++
++
++
++
++nginx мог закрывать IPv6 listen сокет во время переконфигурации.
++Спасибо Максиму Дунину.
++
++
++nginx might close IPv6 listen socket during reconfiguration.
++Thanks to Maxim Dounin.
++
++
++
++
++
++переменную $uid_set можно использовать на любой стадии обработки запроса.
++
++
++the $uid_set variable may be used at any request processing stage.
++
++
++
++
++
++
++
++
++
++
++теперь nginx проверяет location'ы, заданные регулярными выражениями,
++если запрос полностью совпал с location'ом, заданным строкой префикса.
++Предыдущее поведение появилось в 0.7.1.
++
++
++now nginx tests locations given by regular expressions,
++if request was matched exactly by a location given by a prefix string.
++The previous behavior has been introduced in 0.7.1.
++
++
++
++
++
++модуль ngx_http_scgi_module.
++Спасибо Manlio Perillo.
++
++
++the ngx_http_scgi_module.
++Thanks to Manlio Perillo.
++
++
++
++
++
++в директиве return можно добавлять текст ответа.
++
++
++a text answer may be added to a "return" directive.
++
++
++
++
++
++
++
++
++
++
++рабочий процесс nginx/Windows мог завершаться аварийно при запросе файла
++с неверной кодировкой UTF-8.
++
++
++nginx/Windows worker might be terminated abnormally if a requested file name
++has invalid UTF-8 encoding.
++
++
++
++
++
++теперь nginx разрешает использовать пробелы в строке запроса.
++
++
++now nginx allows to use spaces in a request line.
++
++
++
++
++
++директива proxy_redirect неправильно изменяла строку "Refresh" в заголовке
++ответа бэкенда.
++Спасибо Андрею Андрееву и Максиму Согину.
++
++
++the "proxy_redirect" directive changed incorrectly a backend "Refresh"
++response header line.
++Thanks to Andrey Andreew and Max Sogin.
++
++
++
++
++
++nginx не поддерживал путь без имени хоста в
++строке "Destination" в заголовке запроса.
++
++
++nginx did not support path without host name
++in "Destination" request header line.
++
++
++
++
++
++
++
++
++
++
++теперь nginx/Windows игнорирует имя потока файла по умолчанию.
++Спасибо Jose Antonio Vazquez Gonzalez.
++
++
++now nginx/Windows ignores default file stream name.
++Thanks to Jose Antonio Vazquez Gonzalez.
++
++
++
++
++
++модуль ngx_http_uwsgi_module.
++Спасибо Roberto De Ioris.
++
++
++the ngx_http_uwsgi_module.
++Thanks to Roberto De Ioris.
++
++
++
++
++
++директива fastcgi_param со значением, начинающимся со строки "HTTP_",
++изменяет строку заголовка в запросе клиента.
++
++
++a "fastcgi_param" directive with value starting with "HTTP_" overrides
++a client request header line.
++
++
++
++
++
++строки "If-Modified-Since", "If-Range" и им подобные в заголовке запроса
++клиента передавались FastCGI-серверу при кэшировании.
++
++
++the "If-Modified-Since", "If-Range", etc. client request header lines
++were passed to FastCGI-server while caching.
++
++
++
++
++
++listen unix domain сокет нельзя было изменить во время переконфигурации.
++Спасибо Максиму Дунину.
++
++
++listen unix domain socket could not be changed during reconfiguration.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++наследуемая директива alias неправильно работала во вложенном location'е.
++
++
++an inherited "alias" directive worked incorrectly in inclusive location.
++
++
++
++
++
++в комбинации директив alias с переменными и try_files;
++
++
++in "alias" with variables and "try_files" directives combination.
++
++
++
++
++
++listen unix domain и IPv6 сокеты не наследовались во время обновления
++без перерыва.
++Спасибо Максиму Дунину.
++
++
++listen unix domain and IPv6 sockets did not inherit while online upgrade.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_no_cache и fastcgi_no_cache.
++
++
++the "proxy_no_cache" and "fastcgi_no_cache" directives.
++
++
++
++
++
++теперь при использовании переменной $scheme в директиве rewrite
++автоматически делается редирект.
++Спасибо Piotr Sikora.
++
++
++now the "rewrite" directive does a redirect automatically
++if the $scheme variable is used.
++Thanks to Piotr Sikora.
++
++
++
++
++
++теперь задержки в директиве limit_req соответствует описанному алгоритму.
++Спасибо Максиму Дунину.
++
++
++now "limit_req" delay directive conforms to the described algorithm.
++Thanks to Maxim Dounin.
++
++
++
++
++
++переменную $uid_got нельзя было использовать в SSI и перловом модулях.
++
++
++the $uid_got variable might not be used in the SSI and perl modules.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_split_clients_module.
++
++
++the ngx_http_split_clients_module.
++
++
++
++
++
++директива map поддерживает ключи больше 255 символов.
++
++
++the "map" directive supports keys more than 255 characters.
++
++
++
++
++
++nginx игнорировал значения "private" и "no-store" в строке "Cache-Control"
++в заголовке ответа бэкенда.
++
++
++nginx ignored the "private" and "no-store" values
++in the "Cache-Control" backend response header line.
++
++
++
++
++
++параметр stub в SSI-директиве include не использовался,
++если пустой ответ имел код 200.
++
++
++a "stub" parameter of an "include" SSI directive was not used,
++if empty response has 200 status code.
++
++
++
++
++
++если проксированный или FastCGI запрос внутренне перенаправлялся
++в другой проксированный или FastCGI location,
++то в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.8.33.
++Спасибо Yichun Zhang.
++
++
++if a proxied or FastCGI request was internally redirected
++to another proxied or FastCGI location,
++then a segmentation fault might occur in a worker process;
++the bug had appeared in 0.8.33.
++Thanks to Yichun Zhang.
++
++
++
++
++
++соединения IMAP к серверу Zimbra могло зависнуть до таймаута.
++Спасибо Alan Batie.
++
++
++IMAP connections may hang until they timed out
++while talking to Zimbra server.
++Thanks to Alan Batie.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_dav_module неправильно обрабатывал методы DELETE, COPY и MOVE
++для симлинков.
++
++
++the ngx_http_dav_module handled incorrectly the DELETE, COPY, and MOVE methods
++for symlinks.
++
++
++
++
++
++модуль SSI в подзапросах использовал закэшированные в основном запросе
++значения переменных $query_string, $arg_... и им подобных.
++
++
++values of the $query_string, $arg_..., etc. variables cached in main
++request were used by the SSI module in subrequests.
++
++
++
++
++
++значение переменной повторно экранировалось после каждого вывода
++SSI-команды echo;
++ошибка появилась в 0.6.14.
++
++
++a variable value was repeatedly encoded after each
++an "echo" SSI-command output;
++the bug had appeared in 0.6.14.
++
++
++
++
++
++рабочий процесс зависал при запросе файла FIFO.
++Спасибо Vicente Aguilar и Максиму Дунину.
++
++
++a worker process hung if a FIFO file was requested.
++Thanks to Vicente Aguilar and Maxim Dounin.
++
++
++
++
++
++совместимость с OpenSSL-1.0.0 на 64-битном Linux.
++Спасибо Максиму Дунину.
++
++
++OpenSSL-1.0.0 compatibility on 64-bit Linux.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не собирался с параметром --without-http-cache;
++ошибка появилась в 0.8.35.
++
++
++nginx could not be built --without-http-cache;
++the bug had appeared in 0.8.35.
++
++
++
++
++
++
++
++
++
++
++теперь charset-фильтр работает до SSI-фильтра.
++
++
++now the charset filter runs before the SSI filter.
++
++
++
++
++
++директива chunked_transfer_encoding.
++
++
++the "chunked_transfer_encoding" directive.
++
++
++
++
++
++символ "&" при копировании в аргументы в правилах rewrite не экранировался.
++
++
++an "&" character was not escaped when it was copied in arguments part
++in a rewrite rule.
++
++
++
++
++
++nginx мог завершаться аварийно во время обработки сигнала или
++при использовании директивы timer_resolution на платформах,
++не поддерживающих методы kqueue или eventport.
++Спасибо George Xie и Максиму Дунину.
++
++
++nginx might be terminated abnormally
++while a signal processing or if the directive "timer_resolution" was used
++on platforms which do not support kqueue or eventport notification methods.
++Thanks to George Xie and Maxim Dounin.
++
++
++
++
++
++если временные файлы и постоянное место хранения располагались на разных
++файловых системах, то у постоянных файлов время изменения было неверным.
++Спасибо Максиму Дунину.
++
++
++if temporary files and permanent storage area resided at different
++file systems, then permanent file modification times were incorrect.
++Thanks to Maxim Dounin.
++
++
++
++
++
++модуль ngx_http_memcached_module мог выдавать ошибку "memcached sent invalid
++trailer".
++Спасибо Максиму Дунину.
++
++
++ngx_http_memcached_module might issue the error message "memcached sent invalid
++trailer".
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не мог собрать библиотеку zlib-1.2.4 из исходных текстов.
++Спасибо Максиму Дунину.
++
++
++nginx could not built zlib-1.2.4 library using the library sources.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в рабочем процессе происходил segmentation fault,
++если перед ответом FastCGI-сервера было много вывода в stderr;
++ошибка появилась в 0.8.34.
++Спасибо Максиму Дунину.
++
++
++a segmentation fault occurred in a worker process,
++if there was large stderr output before FastCGI response;
++the bug had appeared in 0.8.34.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++nginx не поддерживал все шифры, используемые в клиентских сертификатах.
++Спасибо Иннокентию Еникееву.
++
++
++nginx did not support all ciphers and digests used in client certificates.
++Thanks to Innocenty Enikeew.
++
++
++
++
++
++nginx неправильно кэшировал FastCGI-ответы, если перед ответом было
++много вывода в stderr.
++
++
++nginx cached incorrectly FastCGI responses if there was large stderr output
++before response.
++
++
++
++
++
++nginx не поддерживал HTTPS-рефереры.
++
++
++nginx did not support HTTPS referrers.
++
++
++
++
++
++nginx/Windows мог не находить файлы, если путь в конфигурации был задан
++в другом регистре;
++ошибка появилась в 0.8.33.
++
++
++nginx/Windows might not find file if path in configuration was given
++in other character case;
++the bug had appeared in 0.8.33.
++
++
++
++
++
++переменная $date_local выдавала неверное время,
++если использовался формат "%s".
++Спасибо Максиму Дунину.
++
++
++the $date_local variable has an incorrect value,
++if the "%s" format was used.
++Thanks to Maxim Dounin.
++
++
++
++
++
++если ssl_session_cache не был установлен или установлен в none,
++то при проверке клиентского сертификаты могла происходить
++ошибка "session id context uninitialized";
++ошибка появилась в 0.7.1.
++
++
++if ssl_session_cache was not set or was set to "none",
++then during client certificate verify
++the error "session id context uninitialized" might occur;
++the bug had appeared in 0.7.1.
++
++
++
++
++
++geo-диапазон возвращал значение по умолчанию, если диапазон включал
++в себя одну и более сетей размером /16 и не начинался на границе сети
++размером /16.
++
++
++a geo range returned default value if the range included two or more
++/16 networks and did not begin at /16 network boundary.
++
++
++
++
++
++блок, используемый в параметре stub в SSI-директиве include,
++выводился с MIME-типом "text/plain".
++
++
++a block used in a "stub" parameter of an "include" SSI directive
++was output with "text/plain" MIME type.
++
++
++
++
++
++$r->sleep() не работал;
++ошибка появилась в 0.8.11.
++
++
++$r->sleep() did not work;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++теперь nginx/Windows игнорирует пробелы в конце URI.
++Спасибо Dan Crowley, Core Security Technologies.
++
++
++now nginx/Windows ignores trailing spaces in URI.
++Thanks to Dan Crowley, Core Security Technologies.
++
++
++
++
++
++теперь nginx/Windows игнорирует короткие имена файлов.
++Спасибо Dan Crowley, Core Security Technologies.
++
++
++now nginx/Windows ignores short files names.
++Thanks to Dan Crowley, Core Security Technologies.
++
++
++
++
++
++теперь keepalive соединения после запросов POST не запрещаются для
++MSIE 7.0+.
++Спасибо Adam Lounds.
++
++
++now keepalive connections after POST requests are not disabled for
++MSIE 7.0+.
++Thanks to Adam Lounds.
++
++
++
++
++
++теперь keepalive соединения запрещены для Safari.
++Спасибо Joshua Sierles.
++
++
++now keepalive connections are disabled for Safari.
++Thanks to Joshua Sierles.
++
++
++
++
++
++если проксированный или FastCGI запрос внутренне перенаправлялся
++в другой проксированный или FastCGI location, то переменная
++$upstream_response_time могла иметь ненормально большое значение;
++ошибка появилась в 0.8.7.
++
++
++if a proxied or FastCGI request was internally redirected
++to another proxied or FastCGI location,
++then $upstream_response_time variable may have abnormally large value;
++the bug had appeared in 0.8.7.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault
++при отбрасывания тела запроса;
++ошибка появилась в 0.8.11.
++
++
++a segmentation fault might occur in a worker process,
++while discarding a request body;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++ошибки при использовании кодировки UTF-8 в ngx_http_autoindex_module.
++Спасибо Максиму Дунину.
++
++
++UTF-8 encoding usage in the ngx_http_autoindex_module.
++Thanks to Maxim Dounin.
++
++
++
++
++
++именованные выделения в регулярных выражениях работали только для
++двух переменных.
++Спасибо Максиму Дунину.
++
++
++regular expression named captures worked for two names only.
++Thanks to Maxim Dounin.
++
++
++
++
++
++теперь в строке заголовка запроса "Host" используется имя "localhost",
++если в директиве auth_http указан unix domain сокет.
++Спасибо Максиму Дунину.
++
++
++now the "localhost" name is used in the "Host" request header line,
++if an unix domain socket is defined in the "auth_http" directive.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не поддерживал передачу chunk'ами для 201-ых ответов.
++Спасибо Julian Reich.
++
++
++nginx did not support chunked transfer encoding for 201 responses.
++Thanks to Julian Reich.
++
++
++
++
++
++если директива "expires modified" выставляла дату в прошлом, то в строке
++заголовка ответа "Cache-Control" выдавалось отрицательное число.
++Спасибо Алексею Капранову.
++
++
++if the "expires modified" set date in the past, then a negative number
++was set in the "Cache-Control" response header line.
++Thanks to Alex Kapranoff.
++
++
++
++
++
++
++
++
++
++
++теперь директива error_page может перенаправлять ответы со статусом 301 и 302.
++
++
++now the "error_page" directive may redirect the 301 and 302 responses.
++
++
++
++
++
++переменные $geoip_city_continent_code, $geoip_latitude и $geoip_longitude.
++Спасибо Arvind Sundararajan.
++
++
++the $geoip_city_continent_code, $geoip_latitude, and $geoip_longitude
++variables.
++Thanks to Arvind Sundararajan.
++
++
++
++
++
++модуль ngx_http_image_filter_module теперь всегда удаляет
++EXIF и другие данные, если они занимают больше 5% в JPEG-файле.
++
++
++now the ngx_http_image_filter_module deletes always EXIF and other
++application specific data if the data consume more than 5% of a JPEG file.
++
++
++
++
++
++nginx закрывал соединение при запросе закэшированного
++ответа с пустым телом.
++Спасибо Piotr Sikora.
++
++
++nginx closed a connection if a cached response had an empty body.
++Thanks to Piotr Sikora.
++
++
++
++
++
++nginx мог не собираться gcc 4.x при использовании оптимизации -O2 и выше.
++Спасибо Максиму Дунину и Денису Латыпову.
++
++
++nginx might not be built by gcc 4.x if the -O2 or higher optimization option
++was used.
++Thanks to Maxim Dounin and Denis F. Latypoff.
++
++
++
++
++
++регулярные выражения в location всегда тестировались с учётом регистра;
++ошибка появилась в 0.8.25.
++
++
++regular expressions in location were always tested in case-sensitive mode;
++the bug had appeared in 0.8.25.
++
++
++
++
++
++nginx кэшировал 304 ответ, если в заголовке проксируемого запроса
++была строка "If-None-Match".
++Спасибо Tim Dettrick и David Kostal.
++
++
++nginx cached a 304 response if there was the "If-None-Match" header line
++in a proxied request.
++Thanks to Tim Dettrick and David Kostal.
++
++
++
++
++
++nginx/Windows пытался дважды удалить временный файл
++при перезаписи уже существующего файла.
++
++
++nginx/Windows tried to delete a temporary file twice
++if the file should replace an already existent file.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию размер буфера директивы large_client_header_buffers
++равен 8K.
++Спасибо Andrew Cholakian.
++
++
++now the default buffer size of the "large_client_header_buffers"
++directive is 8K.
++Thanks to Andrew Cholakian.
++
++
++
++
++
++файл conf/fastcgi.conf для простых конфигураций FastCGI.
++
++
++the conf/fastcgi.conf for simple FastCGI configurations.
++
++
++
++
++
++nginx/Windows пытался дважды переименовать временный файл
++при перезаписи уже существующего файла.
++
++
++nginx/Windows tried to rename a temporary file twice if the file
++should replace an already existent file.
++
++
++
++
++
++ошибки double free or corruption, возникающей, если имя хоста не было найдено;
++ошибка появилась в 0.8.22.
++Спасибо Константину Свисту.
++
++
++of "double free or corruption" error issued if host could not be resolved;
++the bug had appeared in 0.8.22.
++Thanks to Konstantin Svist.
++
++
++
++
++
++в использовании libatomic на некоторых платформах.
++Спасибо W-Mark Kubacki.
++
++
++in libatomic usage on some platforms.
++Thanks to W-Mark Kubacki.
++
++
++
++
++
++
++
++
++
++
++теперь для проксируемых ответов HTTP/0.9 в лог пишется код ответа "009".
++
++
++now the "009" status code is written to an access log for proxied HTTP/0.9
++responses.
++
++
++
++
++
++директивы addition_types, charset_types, gzip_types, ssi_types,
++sub_filter_types и xslt_types поддерживают параметр "*".
++
++
++the "addition_types", "charset_types", "gzip_types", "ssi_types",
++"sub_filter_types", and "xslt_types" directives support an "*" parameter.
++
++
++
++
++
++использование встроенных атомарных операций GCC 4.1+.
++Спасибо W-Mark Kubacki.
++
++
++GCC 4.1+ built-in atomic operations usage.
++Thanks to W-Mark Kubacki.
++
++
++
++
++
++параметр --with-libatomic[=DIR] в configure.
++Спасибо W-Mark Kubacki.
++
++
++the --with-libatomic[=DIR] option in the configure.
++Thanks to W-Mark Kubacki.
++
++
++
++
++
++listen unix domain сокет имели ограниченные права доступа.
++
++
++listen unix domain socket had limited access rights.
++
++
++
++
++
++закэшированные ответы ответов HTTP/0.9 неправильно обрабатывались.
++
++
++cached HTTP/0.9 responses were handled incorrectly.
++
++
++
++
++
++именованные выделения в регулярных выражениях, заданные как "?P<...>",
++не работали в директиве server_name.
++Спасибо Максиму Дунину.
++
++
++regular expression named captures given by "?P<...>" did not work
++in a "server_name" directive.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с параметром --without-pcre;
++ошибка появилась в 0.8.25.
++
++
++nginx could not be built with the --without-pcre parameter;
++the bug had appeared in 0.8.25.
++
++
++
++
++
++
++
++
++
++
++регулярные выражения не работали в nginx/Windows;
++ошибка появилась в 0.8.25.
++
++
++regular expressions did not work in nginx/Windows;
++the bug had appeared in 0.8.25.
++
++
++
++
++
++
++
++
++
++
++ошибки при использовании выделений в директиве rewrite;
++ошибка появилась в 0.8.25.
++
++
++in captures usage in "rewrite" directive;
++the bug had appeared in 0.8.25.
++
++
++
++
++
++nginx не собирался без параметра --with-debug;
++ошибка появилась в 0.8.25.
++
++
++nginx could not be built without the --with-debug option;
++the bug had appeared in 0.8.25.
++
++
++
++
++
++
++
++
++
++
++теперь в лог ошибок не пишется сообщение, если переменная не найдена
++с помощью метода $r->variable().
++
++
++now no message is written in an error log if a variable is not found by
++$r->variable() method.
++
++
++
++
++
++модуль ngx_http_degradation_module.
++
++
++the ngx_http_degradation_module.
++
++
++
++
++
++именованные выделения в регулярных выражениях.
++
++
++regular expression named captures.
++
++
++
++
++
++теперь при использовании переменных в директиве proxy_pass не требуется
++задавать URI.
++
++
++now URI part is not required a "proxy_pass" directive if variables are used.
++
++
++
++
++
++теперь директива msie_padding работает и для Chrome.
++
++
++now the "msie_padding" directive works for Chrome too.
++
++
++
++
++
++в рабочем процессе происходил segmentation fault при недостатке памяти;
++ошибка появилась в 0.8.18.
++
++
++a segmentation fault occurred in a worker process on low memory condition;
++the bug had appeared in 0.8.18.
++
++
++
++
++
++nginx передавал сжатые ответы клиентам, не поддерживающим сжатие,
++при настройках gzip_static on и gzip_vary off;
++ошибка появилась в 0.8.16.
++
++
++nginx sent gzipped responses to clients those do not support gzip,
++if "gzip_static on" and "gzip_vary off";
++the bug had appeared in 0.8.16.
++
++
++
++
++
++
++
++
++
++
++nginx всегда добавлял строку "Content-Encoding: gzip" в заголовок
++304-ых ответов модуля ngx_http_gzip_static_module.
++
++
++nginx always added "Content-Encoding: gzip" response header line
++in 304 responses sent by ngx_http_gzip_static_module.
++
++
++
++
++
++nginx не собирался без параметра --with-debug;
++ошибка появилась в 0.8.23.
++
++
++nginx could not be built without the --with-debug option;
++the bug had appeared in 0.8.23.
++
++
++
++
++
++параметр "unix:" в директиве set_real_ip_from неправильно наследовался
++с предыдущего уровня.
++
++
++the "unix:" parameter of the "set_real_ip_from" directive inherited
++incorrectly from previous level.
++
++
++
++
++
++в resolver'е при определении пустого имени.
++
++
++in resolving empty name.
++
++
++
++
++
++
++
++
++
++
++теперь SSL/TLS renegotiation запрещён.
++Спасибо Максиму Дунину.
++
++
++now SSL/TLS renegotiation is disabled.
++Thanks to Maxim Dounin.
++
++
++
++
++
++listen unix domain сокет не наследовался во время обновления без перерыва.
++
++
++listen unix domain socket did not inherit while online upgrade.
++
++
++
++
++
++параметр "unix:" в директиве set_real_ip_from не работал без ещё
++одной директивы с любым IP-адресом.
++
++
++the "unix:" parameter of the "set_real_ip_from" directive did not without
++yet another directive with any IP address.
++
++
++
++
++
++segmentation fault и зацикливания в resolver'е.
++
++
++segmentation fault and infinite looping in resolver.
++
++
++
++
++
++в resolver'е.
++Спасибо Артёму Бохану.
++
++
++in resolver.
++Thanks to Artem Bokhan.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_bind, fastcgi_bind и memcached_bind.
++
++
++the "proxy_bind", "fastcgi_bind", and "memcached_bind" directives.
++
++
++
++
++
++директивы access и deny поддерживают IPv6.
++
++
++the "access" and the "deny" directives support IPv6.
++
++
++
++
++
++директива set_real_ip_from поддерживает IPv6 адреса в заголовках запроса.
++
++
++the "set_real_ip_from" directive supports IPv6 addresses in request headers.
++
++
++
++
++
++параметр "unix:" в директиве set_real_ip_from.
++
++
++the "unix:" parameter of the "set_real_ip_from" directive.
++
++
++
++
++
++nginx не удалял unix domain сокет после тестирования конфигурации.
++
++
++nginx did not delete unix domain socket after configuration testing.
++
++
++
++
++
++nginx удалял unix domain сокет во время обновления без перерыва.
++
++
++nginx deleted unix domain socket while online upgrade.
++
++
++
++
++
++оператор "!-x" не работал.
++Спасибо Максиму Дунину.
++
++
++the "!-x" operator did not work.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault
++при использовании limit_rate в HTTPS сервере.
++Спасибо Максиму Дунину.
++
++
++a segmentation fault might occur in a worker process,
++if limit_rate was used in HTTPS server.
++Thanks to Maxim Dounin.
++
++
++
++
++
++при записи в лог переменной $limit_rate
++в рабочем процессе происходил segmentation fault.
++Спасибо Максиму Дунину.
++
++
++a segmentation fault might occur in a worker process
++while $limit_rate logging.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если внутри блока server не было директивы listen;
++ошибка появилась в 0.8.21.
++
++
++a segmentation fault might occur in a worker process,
++if there was no "listen" directive in "server" block;
++the bug had appeared in 0.8.21.
++
++
++
++
++
++
++
++
++
++
++теперь ключ -V показывает статус поддержки TLS SNI.
++
++
++now the "-V" switch shows TLS SNI support.
++
++
++
++
++
++директива listen модуля HTTP поддерживает unix domain сокеты.
++Спасибо Hongli Lai.
++
++
++the "listen" directive of the HTTP module supports unix domain sockets.
++Thanks to Hongli Lai.
++
++
++
++
++
++параметр "default_server" в директиве listen.
++
++
++the "default_server" parameter of the "listen" directive.
++
++
++
++
++
++теперь параметр "default" не обязателен для установки параметров listen-сокета.
++
++
++now a "default" parameter is not required to set listen socket options.
++
++
++
++
++
++nginx не поддерживал даты в 2038 году на 32-битных платформах;
++
++
++nginx did not support dates in 2038 year on 32-bit platforms;
++
++
++
++
++
++утечки сокетов;
++ошибка появилась в 0.8.11.
++
++
++socket leak;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию используются следующие шифры SSL: "HIGH:!ADH:!MD5".
++
++
++now default SSL ciphers are "HIGH:!ADH:!MD5".
++
++
++
++
++
++модуль ngx_http_autoindex_module не показывал последний слэш для линков
++на каталоги;
++ошибка появилась в 0.7.15.
++
++
++the ngx_http_autoindex_module did not show the trailing slash in links to
++a directory;
++the bug had appeared in 0.7.15.
++
++
++
++
++
++nginx не закрывал лог, заданный параметром конфигурации --error-log-path;
++ошибка появилась в 0.7.53.
++
++
++nginx did not close a log file set by the --error-log-path configuration option;
++the bug had appeared in 0.7.53.
++
++
++
++
++
++nginx не считал запятую разделителем в строке "Cache-Control" в
++заголовке ответа бэкенда.
++
++
++nginx did not treat a comma as separator in the "Cache-Control" backend response
++header line.
++
++
++
++
++
++nginx/Windows мог не создать временный файл, файл в кэше или файл
++с помощью директив proxy/fastcgi_store, если рабочий процесс не имел
++достаточно прав для работы с каталогами верхнего уровня.
++
++
++nginx/Windows might not create temporary file, a cache file, or
++"proxy/fastcgi_store"d file if a worker had no enough access rights
++for top level directories.
++
++
++
++
++
++строки "Set-Cookie" и "P3P" в заголовке ответа FastCGI-сервера не скрывались
++при кэшировании, если не использовались директивы fastcgi_hide_header
++с любыми параметрами.
++
++
++the "Set-Cookie" and "P3P" FastCGI response header lines were not hidden
++while caching if no "fastcgi_hide_header" directives were used with
++any parameters.
++
++
++
++
++
++nginx неверно считал размер кэша на диске.
++
++
++nginx counted incorrectly disk cache size.
++
++
++
++
++
++
++
++
++
++
++теперь протокол SSLv2 по умолчанию запрещён.
++
++
++now SSLv2 protocol is disabled by default.
++
++
++
++
++
++теперь по умолчанию используются следующие шифры SSL:
++"ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM".
++
++
++now default SSL ciphers are "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM".
++
++
++
++
++
++директива limit_req не работала;
++ошибка появилась в 0.8.18.
++
++
++a "limit_req" directive did not work;
++the bug had appeared in 0.8.18.
++
++
++
++
++
++
++
++
++
++
++директива read_ahead.
++
++
++the "read_ahead" directive.
++
++
++
++
++
++теперь можно использовать несколько директив perl_modules.
++
++
++now several "perl_modules" directives may be used.
++
++
++
++
++
++директивы limit_req_log_level и limit_conn_log_level.
++
++
++the "limit_req_log_level" and "limit_conn_log_level" directives.
++
++
++
++
++
++теперь директива limit_req соответствует алгоритму leaky bucket.
++Спасибо Максиму Дунину.
++
++
++now "limit_req" directive conforms to the leaky bucket algorithm.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не работал на Linux/sparc.
++Спасибо Marcus Ramberg.
++
++
++nginx did not work on Linux/sparc.
++Thanks to Marcus Ramberg.
++
++
++
++
++
++nginx слал символ '\0' в строке "Location" в заголовке в ответе на запрос
++MKCOL.
++Спасибо Xie Zhenye.
++
++
++nginx sent '\0' in a "Location" response header line on MKCOL request.
++Thanks to Xie Zhenye.
++
++
++
++
++
++вместо кода ответа 499 в лог записывался код 0;
++ошибка появилась в 0.8.11.
++
++
++zero status code was logged instead of 499 status code;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++утечки сокетов;
++ошибка появилась в 0.8.11.
++
++
++socket leak;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++теперь символы "/../" запрещены в строке "Destination" в заголовке запроса.
++
++
++now "/../" are disabled in "Destination" request header line.
++
++
++
++
++
++теперь значение переменной $host всегда в нижнем регистре.
++
++
++now $host variable value is always low case.
++
++
++
++
++
++переменная $ssl_session_id.
++
++
++the $ssl_session_id variable.
++
++
++
++
++
++утечки сокетов;
++ошибка появилась в 0.8.11.
++
++
++socket leak;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++директива image_filter_transparency.
++
++
++the "image_filter_transparency" directive.
++
++
++
++
++
++директива "addition_types" была неверно названа "addtion_types".
++
++
++"addition_types" directive was incorrectly named "addtion_types".
++
++
++
++
++
++порчи кэша resolver'а.
++Спасибо Matthew Dempsky.
++
++
++resolver cache poisoning.
++Thanks to Matthew Dempsky.
++
++
++
++
++
++утечки памяти в resolver'е.
++Спасибо Matthew Dempsky.
++
++
++memory leak in resolver.
++Thanks to Matthew Dempsky.
++
++
++
++
++
++неверная строка запроса в переменной $request записывалась в access_log
++только при использовании error_log на уровне info или debug.
++
++
++invalid request line in $request variable was written in access_log
++only if error_log was set to "info" or "debug" level.
++
++
++
++
++
++в поддержке альфа-канала PNG в модуле ngx_http_image_filter_module.
++
++
++in PNG alpha-channel support in the ngx_http_image_filter_module.
++
++
++
++
++
++nginx всегда добавлял строку "Vary: Accept-Encoding" в заголовок ответа,
++если обе директивы gzip_static и gzip_vary были включены.
++
++
++nginx always added "Vary: Accept-Encoding" response header line,
++if both "gzip_static" and "gzip_vary" were on.
++
++
++
++
++
++в поддержке кодировки UTF-8 директивой try_files в nginx/Windows.
++
++
++in UTF-8 encoding support by "try_files" directive in nginx/Windows.
++
++
++
++
++
++ошибки при использовании post_action;
++ошибка появилась в 0.8.11.
++Спасибо Игорю Артемьеву.
++
++
++in "post_action" directive usage;
++the bug had appeared in 0.8.11.
++Thanks to Igor Artemiev.
++
++
++
++
++
++
++
++
++
++
++при обработке специально созданного запроса
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Chris Ries.
++
++
++a segmentation fault might occur in worker process
++while specially crafted request handling.
++Thanks to Chris Ries.
++
++
++
++
++
++если были описаны имена .domain.tld, .sub.domain.tld и .domain-some.tld,
++то имя .sub.domain.tld попадало под маску .domain.tld.
++
++
++if names .domain.tld, .sub.domain.tld, and .domain-some.tld were defined,
++then the name .sub.domain.tld was matched by .domain.tld.
++
++
++
++
++
++в поддержке прозрачности в модуле ngx_http_image_filter_module.
++
++
++in transparency support in the ngx_http_image_filter_module.
++
++
++
++
++
++в файловом AIO.
++
++
++in file AIO.
++
++
++
++
++
++ошибки при использовании X-Accel-Redirect;
++ошибка появилась в 0.8.11.
++
++
++in X-Accel-Redirect usage;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++ошибки при использовании встроенного перла;
++ошибка появилась в 0.8.11.
++
++
++in embedded perl module;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++
++устаревший закэшированный запрос мог залипнуть в состоянии "UPDATING".
++
++
++an expired cached response might stick in the "UPDATING" state.
++
++
++
++
++
++при использовании error_log на уровне info или debug
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Сергею Боченкову.
++
++
++a segmentation fault might occur in worker process,
++if error_log was set to info or debug level.
++Thanks to Sergey Bochenkov.
++
++
++
++
++
++ошибки при использовании встроенного перла;
++ошибка появилась в 0.8.11.
++
++
++in embedded perl module;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++директива error_page не перенаправляла ошибку 413;
++ошибка появилась в 0.6.10.
++
++
++an "error_page" directive did not redirect a 413 error;
++the bug had appeared in 0.6.10.
++
++
++
++
++
++
++
++
++
++
++в директиве "aio sendfile";
++ошибка появилась в 0.8.12.
++
++
++in the "aio sendfile" directive;
++the bug had appeared in 0.8.12.
++
++
++
++
++
++nginx не собирался без параметра --with-file-aio на FreeBSD;
++ошибка появилась в 0.8.12.
++
++
++nginx could not be built without the --with-file-aio option on FreeBSD;
++the bug had appeared in 0.8.12.
++
++
++
++
++
++
++
++
++
++
++параметр sendfile в директиве aio во FreeBSD.
++
++
++the "sendfile" parameter in the "aio" directive on FreeBSD.
++
++
++
++
++
++ошибки при использовании try_files;
++ошибка появилась в 0.8.11.
++
++
++in try_files;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++ошибки при использовании memcached;
++ошибка появилась в 0.8.11.
++
++
++in memcached;
++the bug had appeared in 0.8.11.
++
++
++
++
++
++
++
++
++
++теперь директива "gzip_disable msie6" не запрещает сжатие для
++MSIE 6.0 SV1.
++
++
++now directive "gzip_disable msie6" does not disable gzipping for
++MSIE 6.0 SV1.
++
++
++
++
++
++поддержка файлового AIO во FreeBSD и Linux.
++
++
++file AIO support on FreeBSD and Linux.
++
++
++
++
++
++директива directio_alignment.
++
++
++the "directio_alignment" directive.
++
++
++
++
++
++
++
++
++
++
++утечек памяти при использовании базы GeoIP City.
++
++
++memory leaks if GeoIP City database was used.
++
++
++
++
++
++ошибки при копировании временных файлов в постоянное место хранения;
++ошибка появилась в 0.8.9.
++
++
++in copying temporary files to permanent storage area;
++the bug had appeared in 0.8.9.
++
++
++
++
++
++
++
++
++
++
++теперь стартовый загрузчик кэша работает в отдельном процесс;
++это должно улучшить обработку больших кэшей.
++
++
++now the start cache loader runs in a separate process;
++this should improve large caches handling.
++
++
++
++
++
++теперь временные файлы и постоянное место хранения могут располагаться
++на разных файловых системах.
++
++
++now temporary files and permanent storage area may reside at
++different file systems.
++
++
++
++
++
++
++
++
++
++
++в обработке заголовков ответа, разделённых в FastCGI-записях.
++
++
++in handling FastCGI headers split in records.
++
++
++
++
++
++если запрос обрабатывался в двух проксированных или FastCGI location'ах
++и в первом из них использовалось кэширование,
++то в рабочем процессе происходил segmentation fault;
++ошибка появилась в 0.8.7.
++
++
++a segmentation fault occurred in worker process,
++if a request was handled in two proxied or FastCGIed locations
++and a caching was enabled in the first location;
++the bug had appeared in 0.8.7.
++
++
++
++
++
++
++
++
++
++
++минимальная поддерживаемая версия OpenSSL—0.9.7.
++
++
++minimum supported OpenSSL version is 0.9.7.
++
++
++
++
++
++параметр ask директивы ssl_verify_client изменён на параметр optional
++и теперь он проверяет клиентский сертификат, если он был предложен.
++Спасибо Brice Figureau.
++
++
++the "ask" parameter of the "ssl_verify_client" directive was changed
++to the "optional" parameter and now it checks a client certificate if it was
++offered.
++Thanks to Brice Figureau.
++
++
++
++
++
++переменная $ssl_client_verify.
++Спасибо Brice Figureau.
++
++
++the $ssl_client_verify variable.
++Thanks to Brice Figureau.
++
++
++
++
++
++директива ssl_crl.
++Спасибо Brice Figureau.
++
++
++the "ssl_crl" directive.
++Thanks to Brice Figureau.
++
++
++
++
++
++параметр proxy директивы geo.
++
++
++the "proxy" parameter of the "geo" directive.
++
++
++
++
++
++директива image_filter поддерживает переменные для задания размеров.
++
++
++the "image_filter" directive supports variables for setting size.
++
++
++
++
++
++использование переменной $ssl_client_cert портило память;
++ошибка появилась в 0.7.7.
++Спасибо Сергею Журавлёву.
++
++
++the $ssl_client_cert variable usage corrupted memory;
++the bug had appeared in 0.7.7.
++Thanks to Sergey Zhuravlev.
++
++
++
++
++
++директивы proxy_pass_header и fastcgi_pass_header" не передавали клиенту
++строки "X-Accel-Redirect", "X-Accel-Limit-Rate", "X-Accel-Buffering" и
++"X-Accel-Charset" из заголовка ответа бэкенда.
++Спасибо Максиму Дунину.
++
++
++"proxy_pass_header" and "fastcgi_pass_header" directives did not pass to
++a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", "X-Accel-Buffering",
++and "X-Accel-Charset" lines from backend response header.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в обработке строк "Last-Modified" и "Accept-Ranges" в заголовке ответа бэкенда;
++ошибка появилась в 0.7.44.
++Спасибо Максиму Дунину.
++
++
++in handling "Last-Modified" and "Accept-Ranges" backend response header lines;
++the bug had appeared in 0.7.44.
++Thanks to Maxim Dounin.
++
++
++
++
++
++ошибки "[alert] zero size buf" при получении пустых ответы в подзапросах;
++ошибка появилась в 0.8.5.
++
++
++the "[alert] zero size buf" error if subrequest returns an empty response;
++the bug had appeared in 0.8.5.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_geoip_module.
++
++
++the ngx_http_geoip_module.
++
++
++
++
++
++XSLT-фильтр мог выдавать ошибку "not well formed XML document" для
++правильного документа.
++Спасибо Kuramoto Eiji.
++
++
++XSLT filter may fail with message "not well formed XML document"
++for valid XML document.
++Thanks to Kuramoto Eiji.
++
++
++
++
++
++в MacOSX, Cygwin и nginx/Windows при проверке location'ов, заданных
++регулярным выражением, теперь всегда делается сравнение без учёта
++регистра символов.
++
++
++now in MacOSX, Cygwin, and nginx/Windows locations given by a regular
++expression are always tested in case insensitive mode.
++
++
++
++
++
++теперь nginx/Windows игнорирует точки в конце URI.
++Спасибо Hugo Leisink.
++
++
++now nginx/Windows ignores trailing dots in URI.
++Thanks to Hugo Leisink.
++
++
++
++
++
++имя файла указанного в --conf-path игнорировалось при установке;
++ошибка появилась в 0.6.6.
++Спасибо Максиму Дунину.
++
++
++name of file specified in --conf-path was not honored during installation;
++the bug had appeared in 0.6.6.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++теперь nginx разрешает подчёркивания в методе запроса.
++
++
++now nginx allows underscores in a request method.
++
++
++
++
++
++при использовании HTTP Basic-аутентификации на Windows
++для неверных имени/пароля возвращалась 500-ая ошибка.
++
++
++a 500 error code was returned for invalid login/password while HTTP
++Basic authentication on Windows.
++
++
++
++
++
++ответы модуля ngx_http_perl_module не работали в подзапросах.
++
++
++ngx_http_perl_module responses did not work in subrequests.
++
++
++
++
++
++в модуле ngx_http_limit_req_module.
++Спасибо Максиму Дунину.
++
++
++in ngx_http_limit_req_module.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с параметром --without-http-cache;
++ошибка появилась в 0.8.3.
++
++
++nginx could not be built --without-http-cache;
++the bug had appeared in 0.8.3.
++
++
++
++
++
++
++
++
++
++
++переменная $upstream_cache_status.
++
++
++the $upstream_cache_status variable.
++
++
++
++
++
++nginx не собирался на MacOSX 10.6.
++
++
++nginx could not be built on MacOSX 10.6.
++
++
++
++
++
++nginx не собирался с параметром --without-http-cache;
++ошибка появилась в 0.8.2.
++
++
++nginx could not be built --without-http-cache;
++the bug had appeared in 0.8.2.
++
++
++
++
++
++если использовался перехват 401 ошибки от бэкенда и бэкенд
++не возвращал строку "WWW-Authenticate" в заголовке ответа,
++то в рабочем процессе происходил segmentation fault.
++Спасибо Евгению Мычло.
++
++
++a segmentation fault occurred in worker process,
++if a backend 401 error was intercepted and the backend did not set
++the "WWW-Authenticate" response header line.
++Thanks to Eugene Mychlo.
++
++
++
++
++
++
++
++
++
++
++во взаимодействии open_file_cache и proxy/fastcgi кэша на старте.
++
++
++in open_file_cache and proxy/fastcgi cache interaction on start up.
++
++
++
++
++
++open_file_cache мог кэшировать открытые файлы очень долго;
++ошибка появилась в 0.7.4.
++
++
++open_file_cache might cache open file descriptors too long;
++the bug had appeared in 0.7.4.
++
++
++
++
++
++
++
++
++
++
++параметр updating в директивах proxy_cache_use_stale и fastcgi_cache_use_stale.
++
++
++the "updating" parameter in "proxy_cache_use_stale" and
++"fastcgi_cache_use_stale" directives.
++
++
++
++
++
++строки "If-Modified-Since", "If-Range" и им подобные в заголовке запроса
++клиента передавались бэкенду при кэшировании, если не использовалась
++директива proxy_set_header с любыми параметрами.
++
++
++the "If-Modified-Since", "If-Range", etc. client request header lines
++were passed to backend while caching if no "proxy_set_header" directive
++was used with any parameters.
++
++
++
++
++
++строки "Set-Cookie" и "P3P" в заголовке ответа бэкенда не скрывались
++при кэшировании, если не использовались директивы
++proxy_hide_header/fastcgi_hide_header с любыми параметрами.
++
++
++the "Set-Cookie" and "P3P" response header lines were not hidden while caching
++if no "proxy_hide_header/fastcgi_hide_header" directives were used with
++any parameters.
++
++
++
++
++
++модуль ngx_http_image_filter_module не понимал формат GIF87a.
++Спасибо Денису Ильиных.
++
++
++the ngx_http_image_filter_module did not support GIF87a format.
++Thanks to Denis Ilyinyh.
++
++
++
++
++
++nginx не собирался на Solaris 10 и более ранних;
++ошибка появилась в 0.7.56.
++
++
++nginx could not be built modules on Solaris 10 and early;
++the bug had appeared in 0.7.56.
++
++
++
++
++
++
++
++
++
++
++директива keepalive_requests.
++
++
++the "keepalive_requests" directive.
++
++
++
++
++
++директива limit_rate_after.
++Спасибо Ivan Debnar.
++
++
++the "limit_rate_after" directive.
++Thanks to Ivan Debnar.
++
++
++
++
++
++XSLT-фильтр не работал в подзапросах.
++
++
++XLST filter did not work in subrequests.
++
++
++
++
++
++обработке относительных путей в nginx/Windows.
++
++
++in relative paths handling in nginx/Windows.
++
++
++
++
++
++в proxy_store, fastcgi_store, proxy_cache и fastcgi_cache в nginx/Windows.
++
++
++in proxy_store, fastcgi_store, proxy_cache, and fastcgi_cache in nginx/Windows.
++
++
++
++
++
++в обработке ошибок выделения памяти.
++Спасибо Максиму Дунину и Кириллу Коринскому.
++
++
++in memory allocation error handling.
++Thanks to Maxim Dounin and Kirill A. Korinskiy.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_cache_methods и fastcgi_cache_methods.
++
++
++the "proxy_cache_methods" and "fastcgi_cache_methods" directives.
++
++
++
++
++
++утечки сокетов;
++ошибка появилась в 0.7.25.
++Спасибо Максиму Дунину.
++
++
++socket leak;
++the bug had appeared in 0.7.25.
++Thanks to Maxim Dounin.
++
++
++
++
++
++при использовании переменной $request_body
++в рабочем процессе происходил segmentation fault,
++если в запросе не было тела;
++ошибка появилась в 0.7.58.
++
++
++a segmentation fault occurred in worker process,
++if a request had no body and the $request_body
++variable was used;
++the bug had appeared in 0.7.58.
++
++
++
++
++
++SSL-модули могли не собираться на Solaris и Linux;
++ошибка появилась в 0.7.56.
++
++
++the SSL modules might not built on Solaris and Linux;
++the bug had appeared in 0.7.56.
++
++
++
++
++
++ответы модуля ngx_http_xslt_filter_module не обрабатывались
++SSI-, charset- и gzip-фильтрами.
++
++
++ngx_http_xslt_filter_module responses were not handled by SSI, charset,
++and gzip filters.
++
++
++
++
++
++директива charset не ставила кодировку для ответов модуля
++ngx_http_gzip_static_module.
++
++
++a "charset" directive did not set a charset to ngx_http_gzip_static_module
++responses.
++
++
++
++
++
++
++
++
++
++
++директива listen почтового прокси-сервера поддерживает IPv6.
++
++
++a "listen" directive of the mail proxy module supports IPv6.
++
++
++
++
++
++директива image_filter_jpeg_quality.
++
++
++the "image_filter_jpeg_quality" directive.
++
++
++
++
++
++директива client_body_in_single_buffer.
++
++
++the "client_body_in_single_buffer" directive.
++
++
++
++
++
++переменная $request_body.
++
++
++the $request_body variable.
++
++
++
++
++
++в модуле ngx_http_autoindex_module в ссылках на имена файлов,
++содержащих символ ":".
++
++
++in ngx_http_autoindex_module in file name links
++having a ":" symbol in the name.
++
++
++
++
++
++процедура "make upgrade" не работала;
++ошибка появилась в 0.7.53.
++Спасибо Денису Латыпову.
++
++
++"make upgrade" procedure did not work;
++the bug had appeared in 0.7.53.
++Thanks to Denis F. Latypoff.
++
++
++
++
++
++
++
++
++
++
++при перенаправлении ошибок модуля ngx_http_image_filter_module
++в именованный location в рабочем процессе происходил floating-point fault;
++ошибка появилась в 0.7.56.
++
++
++a floating-point fault occurred in worker process,
++if the ngx_http_image_filter_module errors were redirected to named location;
++the bug had appeared in 0.7.56.
++
++
++
++
++
++
++
++
++
++
++nginx/Windows поддерживает IPv6 в директиве listen модуля HTTP.
++
++
++nginx/Windows supports IPv6 in a "listen" directive of the HTTP module.
++
++
++
++
++
++в модуле ngx_http_image_filter_module.
++
++
++in ngx_http_image_filter_module.
++
++
++
++
++
++
++
++
++
++
++параметры http_XXX в директивах proxy_cache_use_stale
++и fastcgi_cache_use_stale не работали.
++
++
++the http_XXX parameters in "proxy_cache_use_stale" and
++"fastcgi_cache_use_stale" directives did not work.
++
++
++
++
++
++fastcgi кэш не кэшировал ответы, состоящие только из заголовка.
++
++
++fastcgi cache did not cache header only responses.
++
++
++
++
++
++ошибки "select() failed (9: Bad file descriptor)" в nginx/Unix
++и "select() failed (10038: ...)" в nginx/Windows.
++
++
++of "select() failed (9: Bad file descriptor)" error in nginx/Unix
++and "select() failed (10038: ...)" error in nginx/Windows.
++
++
++
++
++
++при использовании директивы debug_connection
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.7.54.
++
++
++a segmentation fault might occur in worker process,
++if an "debug_connection" directive was used;
++the bug had appeared in 0.7.54.
++
++
++
++
++
++в сборке модуля ngx_http_image_filter_module.
++
++
++fix ngx_http_image_filter_module building errors.
++
++
++
++
++
++файлы больше 2G не передавались с использованием $r->sendfile.
++Спасибо Максиму Дунину.
++
++
++the files bigger than 2G could not be transferred using $r->sendfile.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_image_filter_module.
++
++
++the ngx_http_image_filter_module.
++
++
++
++
++
++директивы proxy_ignore_headers и fastcgi_ignore_headers.
++
++
++the "proxy_ignore_headers" and "fastcgi_ignore_headers" directives.
++
++
++
++
++
++при использовании переменных "open_file_cache_errors on"
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.7.53.
++
++
++a segmentation fault might occur in worker process,
++if an "open_file_cache_errors off" directive was used;
++the bug had appeared in 0.7.53.
++
++
++
++
++
++директива "port_in_redirect off" не работала;
++ошибка появилась в 0.7.39.
++
++
++the "port_in_redirect off" directive did not work;
++the bug had appeared in 0.7.39.
++
++
++
++
++
++улучшение обработки ошибок метода select.
++
++
++improve handling of "select" method errors.
++
++
++
++
++
++ошибки "select() failed (10022: ...)" в nginx/Windows.
++
++
++of "select() failed (10022: ...)" error in nginx/Windows.
++
++
++
++
++
++в текстовых сообщениях об ошибках в nginx/Windows;
++ошибка появилась в 0.7.53.
++
++
++in error text descriptions in nginx/Windows;
++the bug had appeared in 0.7.53.
++
++
++
++
++
++
++
++
++
++
++теперь лог, указанный в --error-log-path, создаётся с самого начала работы.
++
++
++now a log set by --error-log-path is created from the very start-up.
++
++
++
++
++
++теперь ошибки и предупреждения при старте записываются в error_log
++и выводятся на stderr.
++
++
++now the start up errors and warnings are outputted to an error_log and stderr.
++
++
++
++
++
++при сборке с пустым параметром --prefix= nginx использует как префикс каталог,
++в котором он был запущен.
++
++
++the empty --prefix= configure parameter forces nginx to use a directory
++where it was run as prefix.
++
++
++
++
++
++ключ -p.
++
++
++the -p switch.
++
++
++
++
++
++ключ -s на Unix-платформах.
++
++
++the -s switch on Unix platforms.
++
++
++
++
++
++ключи -? и -h.
++Спасибо Jerome Loyet.
++
++
++the -? and -h switches.
++Thanks to Jerome Loyet.
++
++
++
++
++
++теперь ключи можно задавать в сжатой форме.
++
++
++now switches may be set in condensed form.
++
++
++
++
++
++nginx/Windows не работал, если файл конфигурации был задан ключом -c.
++
++
++nginx/Windows did not work if configuration file was given by the -c switch.
++
++
++
++
++
++при использовании директив proxy_store, fastcgi_store,
++proxy_cache или fastcgi_cache временные файлы могли не удаляться.
++Спасибо Максиму Дунину.
++
++
++temporary files might be not removed if the "proxy_store", "fastcgi_store",
++"proxy_cache", or "fastcgi_cache" were used.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в заголовке Auth-Method запроса серверу аутентификации почтового
++прокси-сервера передавалось неверное значение;
++ошибка появилась в 0.7.34.
++Спасибо Simon Lecaille.
++
++
++an incorrect value was passed to mail proxy authentication server
++in "Auth-Method" header line;
++the bug had appeared
++in 0.7.34.
++Thanks to Simon Lecaille.
++
++
++
++
++
++при логгировании на Linux не писались текстовые описания системных ошибок;
++ошибка появилась в 0.7.45.
++
++
++system error text descriptions were not logged on Linux;
++the bug had appeared in 0.7.45.
++
++
++
++
++
++директива fastcgi_cache_min_uses не работала.
++Спасибо Андрею Воробьёву.
++
++
++the "fastcgi_cache_min_uses" directive did not work.
++Thanks to Andrew Vorobyoff.
++
++
++
++
++
++
++
++
++
++
++первая бинарная версия под Windows.
++
++
++the first native Windows binary release.
++
++
++
++
++
++корректная обработка метода HEAD при кэшировании.
++
++
++in processing HEAD method while caching.
++
++
++
++
++
++корректная обработка строк "If-Modified-Since", "If-Range" и им подобных
++в заголовке запроса клиента при кэшировании.
++
++
++in processing the "If-Modified-Since", "If-Range", etc. client request
++header lines while caching.
++
++
++
++
++
++теперь строки "Set-Cookie" и "P3P" скрываются в заголовке ответа
++для закэшированных ответов.
++
++
++now the "Set-Cookie" and "P3P" header lines are hidden in cacheable responses.
++
++
++
++
++
++если nginx был собран с модулем ngx_http_perl_module и perl
++поддерживал потоки, то при выходе основного процесса
++могла выдаваться ошибка "panic: MUTEX_LOCK".
++
++
++if nginx was built with the ngx_http_perl_module and with a perl which
++supports threads, then during a master process exit
++the message "panic: MUTEX_LOCK" might be issued.
++
++
++
++
++
++nginx не собирался с параметром --without-http-cache;
++ошибка появилась в 0.7.48.
++
++
++nginx could not be built --without-http-cache;
++the bug had appeared in 0.7.48.
++
++
++
++
++
++nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
++ошибка появилась в 0.7.42.
++
++
++nginx could not be built on platforms different from i386, amd64, sparc,
++and ppc;
++the bug had appeared in 0.7.42.
++
++
++
++
++
++
++
++
++
++
++директива try_files поддерживает код ответа в последнем параметре.
++
++
++the "try_files" directive supports a response code in the fallback parameter.
++
++
++
++
++
++теперь в директиве return можно использовать любой код ответа.
++
++
++now any response code can be used in the "return" directive.
++
++
++
++
++
++директива error_page делала внешний редирект без строки запроса;
++ошибка появилась в 0.7.44.
++
++
++the "error_page" directive made an external redirect without query string;
++the bug had appeared in 0.7.44.
++
++
++
++
++
++если сервера слушали на нескольких явно описанных адресах,
++то виртуальные сервера могли не работать;
++ошибка появилась в 0.7.39.
++
++
++if servers listened on several defined explicitly addresses,
++then virtual servers might not work;
++the bug had appeared in 0.7.39.
++
++
++
++
++
++
++
++
++
++
++переменные $arg_... не работали;
++ошибка появилась в 0.7.49.
++
++
++the $arg_... variables did not work;
++the bug had appeared in 0.7.49.
++
++
++
++
++
++
++
++
++
++
++при использовании переменных $arg_...
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.7.48.
++
++
++a segmentation fault might occur in worker process,
++if the $arg_... variables were used;
++the bug had appeared in 0.7.48.
++
++
++
++
++
++
++
++
++
++
++директива proxy_cache_key.
++
++
++the "proxy_cache_key" directive.
++
++
++
++
++
++теперь nginx учитывает при кэшировании строки "X-Accel-Expires",
++"Expires" и "Cache-Control" в заголовке ответа бэкенда.
++
++
++now nginx takes into account the "X-Accel-Expires", "Expires", and
++"Cache-Control" header lines in a backend response.
++
++
++
++
++
++теперь nginx кэширует только ответы на запросы GET.
++
++
++now nginx caches responses for the GET requests only.
++
++
++
++
++
++директива fastcgi_cache_key не наследовалась.
++
++
++the "fastcgi_cache_key" directive was not inherited.
++
++
++
++
++
++переменные $arg_... не работали с SSI-подзапросами.
++Спасибо Максиму Дунину.
++
++
++the $arg_... variables did not work with SSI subrequests.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не собирался с библиотекой uclibc.
++Спасибо Timothy Redaelli.
++
++
++nginx could not be built with uclibc library.
++Thanks to Timothy Redaelli.
++
++
++
++
++
++nginx не собирался на OpenBSD;
++ошибка появилась в 0.7.46.
++
++
++nginx could not be built on OpenBSD;
++the bug had appeared in 0.7.46.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на FreeBSD 6 и более ранних версиях;
++ошибка появилась в 0.7.46.
++
++
++nginx could not be built on FreeBSD 6 and early versions;
++the bug had appeared in 0.7.46.
++
++
++
++
++
++nginx не собирался на MacOSX;
++ошибка появилась в 0.7.46.
++
++
++nginx could not be built on MacOSX;
++the bug had appeared in 0.7.46.
++
++
++
++
++
++если использовался параметр max_size, то cache manager мог удалить весь кэш;
++ошибка появилась в 0.7.46.
++
++
++if the "max_size" parameter was set, then the cache manager might purge
++a whole cache;
++the bug had appeared in 0.7.46.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если директивы proxy_cache/fastcgi_cache
++и proxy_cache_valid/ fastcgi_cache_valid не были заданы на одном уровне;
++ошибка появилась в 0.7.46.
++
++
++a segmentation fault might occur in worker process,
++if the "proxy_cache"/"fastcgi_cache" and
++the "proxy_cache_valid"/ "fastcgi_cache_valid" were set on different levels;
++the bug had appeared in 0.7.46.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault
++при перенаправлении запроса проксированному или FastCGI-серверу
++с помощью error_page или try_files;
++ошибка появилась в 0.7.44.
++
++
++a segmentation fault might occur in worker process,
++if a request was redirected to a proxied or FastCGI server via
++error_page or try_files;
++the bug had appeared in 0.7.44.
++
++
++
++
++
++
++
++
++
++
++архив предыдущего релиза был неверным.
++
++
++the previous release tarball was incorrect.
++
++
++
++
++
++
++
++
++
++
++теперь директивы proxy_cache и proxy_cache_valid можно задавать
++на разных уровнях.
++
++
++now the "proxy_cache" and the "proxy_cache_valid" directives can be set on
++different levels.
++
++
++
++
++
++параметр clean_time в директиве proxy_cache_path удалён.
++
++
++the "clean_time" parameter of the "proxy_cache_path" directive is canceled.
++
++
++
++
++
++параметр max_size в директиве proxy_cache_path.
++
++
++the "max_size" parameter of the "proxy_cache_path" directive.
++
++
++
++
++
++предварительная поддержка кэширования в модуле ngx_http_fastcgi_module.
++
++
++the ngx_http_fastcgi_module preliminary cache support.
++
++
++
++
++
++теперь при ошибках выделения в разделяемой памяти в логе указываются
++названия директивы и зоны.
++
++
++now on shared memory allocation errors directive and zone names are logged.
++
++
++
++
++
++директива "add_header last-modified ''" не удаляла в заголовке ответа
++строку "Last-Modified";
++ошибка появилась в 0.7.44.
++
++
++the directive "add_header last-modified ''" did not delete a "Last-Modified"
++response header line;
++the bug had appeared in 0.7.44.
++
++
++
++
++
++в директиве auth_basic_user_file не работал относительный путь,
++заданный строкой без переменных;
++ошибка появилась в 0.7.44.
++Спасибо Jerome Loyet.
++
++
++a relative path in the "auth_basic_user_file" directive given without variables
++did not work;
++the bug had appeared in 0.7.44.
++Thanks to Jerome Loyet.
++
++
++
++
++
++в директиве alias, заданной переменными
++без ссылок на выделения в регулярных выражениях;
++ошибка появилась в 0.7.42.
++
++
++in an "alias" directive given using variables
++without references to captures of regular expressions;
++the bug had appeared in 0.7.42.
++
++
++
++
++
++
++
++
++
++
++предварительная поддержка кэширования в модуле ngx_http_proxy_module.
++
++
++the ngx_http_proxy_module preliminary cache support.
++
++
++
++
++
++параметр --with-pcre в configure.
++
++
++the --with-pcre option in the configure.
++
++
++
++
++
++теперь директива try_files может быть использована на уровне server.
++
++
++the "try_files" directive is now allowed on the server block level.
++
++
++
++
++
++директива try_files неправильно обрабатывала строку запроса в последнем
++параметре.
++
++
++the "try_files" directive handled incorrectly a query string
++in a fallback parameter.
++
++
++
++
++
++директива try_files могла неверно тестировать каталоги.
++
++
++the "try_files" directive might test incorrectly directories.
++
++
++
++
++
++если для пары адрес:порт описан только один сервер, то выделения
++в регулярных выражениях в директиве server_name не работали.
++
++
++if there was a single server for given address:port pair,
++then captures in regular expressions in a "server_name" directive did not work.
++
++
++
++
++
++
++
++
++
++
++запрос обрабатывался неверно, если директива root использовала переменные;
++ошибка появилась в 0.7.42.
++
++
++a request was handled incorrectly, if a "root" directive used variables;
++the bug had appeared in 0.7.42.
++
++
++
++
++
++если сервер слушал на адресах типа "*", то значение переменной $server_addr
++было "0.0.0.0";
++ошибка появилась в 0.7.36.
++
++
++if a server listened on wildcard address, then the $server_addr variable
++value was "0.0.0.0";
++the bug had appeared in 0.7.36.
++
++
++
++
++
++
++
++
++
++
++ошибка "Invalid argument", возвращаемая setsockopt(TCP_NODELAY) на Solaris,
++теперь игнорируется.
++
++
++now the "Invalid argument" error returned by setsockopt(TCP_NODELAY) on Solaris,
++is ignored.
++
++
++
++
++
++при отсутствии файла, указанного в директиве auth_basic_user_file,
++теперь возвращается ошибка 403 вместо 500.
++
++
++now if a file specified in a "auth_basic_user_file" directive is absent,
++then the 403 error is returned instead of the 500 one.
++
++
++
++
++
++директива auth_basic_user_file поддерживает переменные.
++
++Спасибо Кириллу Коринскому.
++
++
++the "auth_basic_user_file" directive supports variables.
++Thanks to Kirill A. Korinskiy.
++
++
++
++
++
++директива listen поддерживает параметр ipv6only.
++Спасибо Zhang Hua.
++
++
++the "listen" directive supports the "ipv6only" parameter.
++
++Thanks to Zhang Hua.
++
++
++
++
++
++в директиве alias со ссылками на выделения в регулярных выражениях;
++ошибка появилась в 0.7.40.
++
++
++in an "alias" directive with references to captures of regular expressions;
++the bug had appeared in 0.7.40.
++
++
++
++
++
++совместимость с Tru64 UNIX.
++Спасибо Dustin Marquess.
++
++
++compatibility with Tru64 UNIX.
++Thanks to Dustin Marquess.
++
++
++
++
++
++nginx не собирался без библиотеки PCRE;
++ошибка появилась в 0.7.41.
++
++
++nginx could not be built without PCRE library;
++the bug had appeared in 0.7.41.
++
++
++
++
++
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если в server_name или location были выделения в регулярных выражениях;
++ошибка появилась в 0.7.40.
++Спасибо Владимиру Сопоту.
++
++
++a segmentation fault might occur in worker process,
++if a "server_name" or a "location" directives had captures
++in regular expressions;
++the issue had appeared in 0.7.40.
++Thanks to Vladimir Sopot.
++
++
++
++
++
++
++
++
++
++
++директива location поддерживает выделения в регулярных выражениях.
++
++
++the "location" directive supports captures in regular expressions.
++
++
++
++
++
++директиву alias с ссылками на выделения в регулярных выражениях
++можно использовать внутри location'а, заданного регулярным выражением
++с выделениями.
++
++
++an "alias" directive with capture references may be used inside
++a location given by a regular expression with captures.
++
++
++
++
++
++директива server_name поддерживает выделения в регулярных выражениях.
++
++
++the "server_name" directive supports captures in regular expressions.
++
++
++
++
++
++модуль ngx_http_autoindex_module не показывал последний слэш для каталогов
++на файловой системе XFS;
++ошибка появилась в 0.7.15.
++Спасибо Дмитрию Кузьменко.
++
++
++the ngx_http_autoindex_module did not show the trailing slash in directories
++on XFS filesystem;
++the issue had appeared in 0.7.15.
++Thanks to Dmitry Kuzmenko.
++
++
++
++
++
++
++
++
++
++
++при включённом сжатии большие ответы с использованием SSI могли зависать;
++ошибка появилась в 0.7.28.
++Спасибо Артёму Бохану.
++
++
++large response with SSI might hang, if gzipping was enabled;
++the bug had appeared in 0.7.28.
++Thanks to Artem Bokhan.
++
++
++
++
++
++при использовании коротких статических вариантов в директиве try_files
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process,
++if short static variants are used in a "try_files" directive.
++
++
++
++
++
++
++
++
++
++
++логгирование ошибок аутентификации.
++
++
++authentication failures logging.
++
++
++
++
++
++имя/пароль, заданные в auth_basic_user_file, игнорировались после нечётного
++числа пустых строк.
++Спасибо Александру Загребину.
++
++
++name/password in auth_basic_user_file were ignored after odd number
++of empty lines.
++Thanks to Alexander Zagrebin.
++
++
++
++
++
++при использовании длинного пути в unix domain сокете
++в главном процессе происходил segmentation fault;
++ошибка появилась в 0.7.36.
++
++
++a segmentation fault occurred in a master process,
++if long path was used in unix domain socket;
++the bug had appeared in 0.7.36.
++
++
++
++
++
++
++
++
++
++
++директивы, использующие upstream'ы, не работали;
++ошибка появилась в 0.7.36.
++
++
++directives using upstreams did not work;
++the bug had appeared in 0.7.36.
++
++
++
++
++
++
++
++
++
++
++предварительная поддержка IPv6;
++директива listen модуля HTTP поддерживает IPv6.
++
++
++a preliminary IPv6 support;
++the "listen" directive of the HTTP module supports IPv6.
++
++
++
++
++
++переменная $ancient_browser не работала для браузеров, заданных
++директивами modern_browser.
++
++
++the $ancient_browser variable did not work for browsers
++preset by a "modern_browser" directives.
++
++
++
++
++
++
++
++
++
++
++директива ssl_engine не использовала SSL-акселератор
++для асимметричных шифров.
++Спасибо Marcin Gozdalik.
++
++
++a "ssl_engine" directive did not use a SSL-accelerator
++for asymmetric ciphers.
++Thanks to Marcin Gozdalik.
++
++
++
++
++
++директива try_files выставляла MIME-type, исходя из расширения
++первоначального запроса.
++
++
++a "try_files" directive set MIME type depending on an
++original request extension.
++
++
++
++
++
++в директивах server_name, valid_referers и map
++неправильно обрабатывались имена вида "*domain.tld",
++если использовались маски вида ".domain.tld" и ".subdomain.domain.tld";
++ошибка появилась в 0.7.9.
++
++
++"*domain.tld" names were handled incorrectly in
++"server_name", "valid_referers", and "map" directives,
++if ".domain.tld" and ".subdomain.domain.tld" wildcards were used;
++the bug had appeared in 0.7.9.
++
++
++
++
++
++
++
++
++
++
++параметр off в директиве if_modified_since.
++
++
++the "off" parameter of the "if_modified_since" directive.
++
++
++
++
++
++теперь после команды XCLIENT nginx посылает команду HELO/EHLO.
++Спасибо Максиму Дунину.
++
++
++now nginx sends an HELO/EHLO command after a XCLIENT command.
++Thanks to Maxim Dounin.
++
++
++
++
++
++поддержка Microsoft-специфичного режима
++"AUTH LOGIN with User Name"
++в почтовом прокси-сервере.
++Спасибо Максиму Дунину.
++
++
++Microsoft specific "AUTH LOGIN with User Name" mode support
++in mail proxy server.
++Thanks to Maxim Dounin.
++
++
++
++
++
++в директиве rewrite, возвращающей редирект, старые аргументы присоединялись
++к новым через символ "?" вместо "&";
++ошибка появилась в 0.1.18.
++Спасибо Максиму Дунину.
++
++
++in a redirect rewrite directive original arguments were concatenated with
++new arguments by a "?" rather than an "&";
++the bug had appeared in 0.1.18.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не собирался на AIX.
++
++
++nginx could not be built on AIX.
++
++
++
++
++
++
++
++
++
++
++если на запрос с телом возвращался редирект, то ответ мог быть двойным
++при использовании методов epoll или rtsig.
++Спасибо Eden Li.
++
++
++a double response might be returned if the epoll or rtsig methods are used
++and a redirect was returned to a request with body.
++Thanks to Eden Li.
++
++
++
++
++
++для некоторых типов редиректов в переменной $sent_http_location
++было пустое значение.
++
++
++the $sent_http_location variable was empty for some redirects types.
++
++
++
++
++
++при использовании директивы resolver в SMTP прокси-сервере
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process
++if "resolver" directive was used in SMTP proxy.
++
++
++
++
++
++
++
++
++
++
++теперь в директиве try_files можно явно указать проверку каталога.
++
++
++now a directory existence testing can be set explicitly
++in the "try_files" directive.
++
++
++
++
++
++fastcgi_store не всегда сохранял файлы.
++
++
++fastcgi_store stored files not always.
++
++
++
++
++
++в гео-диапазонах.
++
++
++in geo ranges.
++
++
++
++
++
++ошибки выделения больших блоков в разделяемой памяти,
++если nginx был собран без отладки.
++Спасибо Андрею Квасову.
++
++
++in shared memory allocations if nginx was built without debugging.
++Thanks to Andrey Kvasov.
++
++
++
++
++
++
++
++
++
++
++теперь директива try_files проверяет только файлы, игнорируя каталоги.
++
++
++now the "try_files" directive tests files only and ignores directories.
++
++
++
++
++
++директива fastcgi_split_path_info.
++
++
++the "fastcgi_split_path_info" directive.
++
++
++
++
++
++Исправления в поддержке строки "Expect" в заголовке запроса.
++
++
++Bugfixes in an "Expect" request header line support.
++
++
++
++
++
++Исправления в гео-диапазонах.
++
++
++Bugfixes in geo ranges.
++
++
++
++
++
++при отсутствии ответа ngx_http_memcached_module возвращал
++в теле ответа строку "END" вместо 404-ой страницы по умолчанию;
++ошибка появилась в 0.7.18.
++Спасибо Максиму Дунину.
++
++
++in a miss case ngx_http_memcached_module returned the "END" line
++as response body instead of default 404 page body;
++the bug had appeared in 0.7.18.
++Thanks to Maxim Dounin.
++
++
++
++
++
++при проксировании SMTP nginx выдавал сообщение
++"250 2.0.0 OK" вместо "235 2.0.0 OK";
++ошибка появилась в 0.7.22.
++Спасибо Максиму Дунину.
++
++
++while SMTP proxying nginx issued message
++"250 2.0.0 OK" instead of "235 2.0.0 OK";
++the bug had appeared in 0.7.22.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++
++в рабочем процессе происходил segmentation fault,
++если в директивах fastcgi_pass или proxy_pass
++использовались переменные и имя хоста должно было резолвиться;
++ошибка появилась в 0.7.29.
++
++
++a segmentation fault occurred in worker process,
++if variables were used in the "fastcgi_pass" or "proxy_pass" directives
++and host name must be resolved;
++the bug had appeared in 0.7.29.
++
++
++
++
++
++
++
++
++
++
++директивы fastcgi_pass и proxy_pass не поддерживали переменные
++при использовании unix domain сокетов.
++
++
++the "fastcgi_pass" and "proxy_pass" directives did not support
++variables if unix domain sockets were used.
++
++
++
++
++
++Исправления в обработке подзапросов;
++ошибки появились в 0.7.25.
++
++
++Bugfixes in subrequest processing;
++the bugs had appeared in 0.7.25.
++
++
++
++
++
++ответ "100 Continue" выдавался для запросов версии HTTP/1.0;
++Спасибо Максиму Дунину.
++
++
++a "100 Continue" response was issued for HTTP/1.0 requests;
++Thanks to Maxim Dounin.
++
++
++
++
++
++в выделении памяти в модуле ngx_http_gzip_filter_module под Cygwin.
++
++
++in memory allocation in the ngx_http_gzip_filter_module on Cygwin.
++
++
++
++
++
++
++
++
++
++
++в выделении памяти в модуле ngx_http_gzip_filter_module.
++
++
++in memory allocation in the ngx_http_gzip_filter_module.
++
++
++
++
++
++значения по умолчанию для директивы gzip_buffers изменены с 4 4k/8k
++на 32 4k или 16 8k.
++
++
++the default "gzip_buffers" directive values have been changed
++to 32 4k or 16 8k from 4 4k/8k.
++
++
++
++
++
++
++
++
++
++
++директива try_files.
++
++
++the "try_files" directive.
++
++
++
++
++
++директива fastcgi_pass поддерживает переменные.
++
++
++variables support in the "fastcgi_pass" directive.
++
++
++
++
++
++теперь директива geo может брать адрес из переменной.
++Спасибо Андрею Нигматулину.
++
++
++now the $geo variable may get an address from a variable.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++теперь модификатор location'а можно указывать без пробела перед названием.
++
++
++now a location's modifier may be used without space before name.
++
++
++
++
++
++переменная $upstream_response_length.
++
++
++the $upstream_response_length variable.
++
++
++
++
++
++теперь директива add_header не добавляет пустое значение.
++
++
++now a "add_header" directive does not add an empty value.
++
++
++
++
++
++при запросе файла нулевой длины nginx закрывал соединение, ничего не передав;
++ошибка появилась в 0.7.25.
++
++
++if zero length static file was requested, then nginx just closed connection;
++the bug had appeared in 0.7.25.
++
++
++
++
++
++метод MOVE не мог перемещать файл в несуществующий каталог.
++
++
++a MOVE method could not move file in non-existent directory.
++
++
++
++
++
++если в сервере не был описан ни один именованный location,
++но такой location использовался в директиве error_page,
++то в рабочем процессе происходил segmentation fault.
++Спасибо Сергею Боченкову.
++
++
++a segmentation fault occurred in worker process,
++if no one named location was defined in server,
++but some one was used in an error_page directive.
++Thanks to Sergey Bochenkov.
++
++
++
++
++
++
++
++
++
++
++в обработке подзапросов;
++ошибка появилась в 0.7.25.
++
++
++in subrequest processing;
++the bug had appeared in 0.7.25.
++
++
++
++
++
++
++
++
++
++
++в обработке подзапросов.
++
++
++in subrequest processing.
++
++
++
++
++
++теперь разрешаются POST'ы без строки "Content-Length" в заголовке запроса.
++
++
++now POSTs without "Content-Length" header line are allowed.
++
++
++
++
++
++теперь директивы limit_req и limit_conn указывают причину запрета запроса.
++
++
++now the "limit_req" and "limit_conn" directives log a prohibition reason.
++
++
++
++
++
++в параметре delete директивы geo.
++
++
++in the "delete" parameter of the "geo" directive.
++
++
++
++
++
++
++
++
++
++
++директива if_modified_since.
++
++
++the "if_modified_since" directive.
++
++
++
++
++
++nginx не обрабатывал ответ FastCGI-сервера,
++если перед ответом сервер передавал много сообщений в stderr.
++
++
++nginx did not process a FastCGI server response,
++if the server send too many messages to stderr before response.
++
++
++
++
++
++переменные "$cookie_..." не работали в SSI and в перловом модуле.
++
++
++the "$cookie_..." variables did not work in the SSI and the perl module.
++
++
++
++
++
++
++
++
++
++
++параметры delete и ranges в директиве geo.
++
++
++the "delete" and "ranges" parameters in the "geo" directive.
++
++
++
++
++
++ускорение загрузки geo-базы с большим числом значений.
++
++
++speeding up loading of geo base with large number of values.
++
++
++
++
++
++уменьшение памяти, необходимой для загрузки geo-базы.
++
++
++decrease of memory required for geo base load.
++
++
++
++
++
++
++
++
++
++
++параметр none в директиве smtp_auth.
++Спасибо Максиму Дунину.
++
++
++the "none" parameter in the "smtp_auth" directive.
++Thanks to Maxim Dounin.
++
++
++
++
++
++переменные "$cookie_...".
++
++
++the "$cookie_..." variables.
++
++
++
++
++
++директива directio не работала с файловой системой XFS.
++
++
++the "directio" directive did not work in XFS filesystem.
++
++
++
++
++
++resolver не понимал большие DNS-ответы.
++Спасибо Zyb.
++
++
++the resolver did not understand big DNS responses.
++Thanks to Zyb.
++
++
++
++
++
++
++
++
++
++
++Изменения в модуле ngx_http_limit_req_module.
++
++
++Changes in the ngx_http_limit_req_module.
++
++
++
++
++
++поддержка EXSLT в модуле ngx_http_xslt_module.
++Спасибо Денису Латыпову.
++
++
++the EXSLT support in the ngx_http_xslt_module.
++Thanks to Denis F. Latypoff.
++
++
++
++
++
++совместимость с glibc 2.3.
++Спасибо Eric Benson и Максиму Дунину.
++
++
++compatibility with glibc 2.3.
++Thanks to Eric Benson and Maxim Dounin.
++
++
++
++
++
++nginx не запускался на MacOSX 10.4 и более ранних;
++ошибка появилась в 0.7.6.
++
++
++nginx could not run on MacOSX 10.4 and earlier;
++the bug had appeared in 0.7.6.
++
++
++
++
++
++
++
++
++
++
++Изменения в модуле ngx_http_gzip_filter_module.
++
++
++Changes in the ngx_http_gzip_filter_module.
++
++
++
++
++
++модуль ngx_http_limit_req_module.
++
++
++the ngx_http_limit_req_module.
++
++
++
++
++
++на платформах sparc и ppc рабочие процессы могли выходить по сигналу SIGBUS;
++ошибка появилась в 0.7.3.
++Спасибо Максиму Дунину.
++
++
++worker processes might exit on a SIGBUS signal on sparc and ppc platforms;
++the bug had appeared in 0.7.3.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директивы вида "proxy_pass http://host/some:uri" не работали;
++ошибка появилась в 0.7.12.
++
++
++the "proxy_pass http://host/some:uri" directives did not work;
++the bug had appeared in 0.7.12.
++
++
++
++
++
++при использовании HTTPS запросы могли завершаться с ошибкой "bad write retry".
++
++
++in HTTPS mode requests might fail with the "bad write retry" error.
++
++
++
++
++
++модуль ngx_http_secure_link_module не работал внутри location'ов
++с именами меньше 3 символов.
++
++
++the ngx_http_secure_link_module did not work inside locations,
++whose names are less than 3 characters.
++
++
++
++
++
++переменная $server_addr могла не иметь значения.
++
++
++$server_addr variable might have no value.
++
++
++
++
++
++
++
++
++
++
++обновление номера версии.
++
++
++version number update.
++
++
++
++
++
++
++
++
++
++
++директива underscores_in_headers;
++теперь nginx по умолчанию не разрешает подчёркивания в именах строк
++в заголовке запроса клиента.
++
++
++the "underscores_in_headers" directive;
++now nginx does not allows underscores in a client request header line names.
++
++
++
++
++
++модуль ngx_http_secure_link_module.
++
++
++the ngx_http_secure_link_module.
++
++
++
++
++
++директива real_ip_header поддерживает любой заголовок.
++
++
++the "real_ip_header" directive supports any header.
++
++
++
++
++
++директива log_subrequest.
++
++
++the "log_subrequest" directive.
++
++
++
++
++
++переменная $realpath_root.
++
++
++the $realpath_root variable.
++
++
++
++
++
++параметры http_502 и http_504 в директиве proxy_next_upstream.
++
++
++the "http_502" and "http_504" parameters of the "proxy_next_upstream" directive.
++
++
++
++
++
++параметр http_503 в директивах proxy_next_upstream или fastcgi_next_upstream
++не работал.
++
++
++the "http_503" parameter of the "proxy_next_upstream" or
++"fastcgi_next_upstream" directives did not work.
++
++
++
++
++
++nginx мог выдавать строку "Transfer-Encoding: chunked" для запросов HEAD.
++
++
++nginx might send a "Transfer-Encoding: chunked" header line for HEAD requests.
++
++
++
++
++
++теперь accept-лимит зависит от числа worker_connections.
++
++
++now accept threshold depends on worker_connections.
++
++
++
++
++
++
++
++
++
++
++директива directio теперь работает на Linux.
++
++
++now the "directio" directive works on Linux.
++
++
++
++
++
++переменная $pid.
++
++
++the $pid variable.
++
++
++
++
++
++оптимизация directio, появившаяся в 0.7.15, не работала при использовании
++open_file_cache.
++
++
++the "directio" optimization that had appeared in 0.7.15 did not work with
++open_file_cache.
++
++
++
++
++
++access_log с переменными не работал на Linux;
++ошибка появилась в 0.7.7.
++
++
++the "access_log" with variables did not work on Linux;
++the bug had appeared in 0.7.7.
++
++
++
++
++
++модуль ngx_http_charset_module не понимал название кодировки в кавычках,
++полученное от бэкенда.
++
++
++the ngx_http_charset_module did not understand quoted charset name
++received from backend.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на 64-битных платформах;
++ошибка появилась в 0.7.15.
++
++
++nginx could not be built on 64-bit platforms;
++the bug had appeared in 0.7.15.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_random_index_module.
++
++
++the ngx_http_random_index_module.
++
++
++
++
++
++директива directio оптимизирована для запросов файлов, начинающихся
++с произвольной позиции.
++
++
++the "directio" directive has been optimized for file requests starting
++from arbitrary position.
++
++
++
++
++
++директива directio при необходимости запрещает использование sendfile.
++
++
++the "directio" directive turns off sendfile if it is necessary.
++
++
++
++
++
++теперь nginx разрешает подчёркивания в именах строк в заголовке запроса клиента.
++
++
++now nginx allows underscores in a client request header line names.
++
++
++
++
++
++
++
++
++
++
++теперь директивы ssl_certificate и ssl_certificate_key не имеют
++значений по умолчанию.
++
++
++now the ssl_certificate and ssl_certificate_key directives have no
++default values.
++
++
++
++
++
++директива listen поддерживает параметр ssl.
++
++
++the "listen" directive supports the "ssl" parameter.
++
++
++
++
++
++теперь при переконфигурации nginx учитывает изменение временной зоны
++на FreeBSD и Linux.
++
++
++now nginx takes into account a time zone change while reconfiguration
++on FreeBSD and Linux.
++
++
++
++
++
++параметры директивы listen, такие как backlog, rcvbuf и прочие,
++не устанавливались, если сервером по умолчанию был не первый сервер.
++
++
++the "listen" directive parameters such as "backlog", "rcvbuf", etc.
++were not set, if a default server was not the first one.
++
++
++
++
++
++при использовании в качестве аргументов части URI, выделенного с помощью
++директивы rewrite, эти аргументы не экранировались.
++
++
++if URI part captured by a "rewrite" directive was used as a query string,
++then the query string was not escaped.
++
++
++
++
++
++улучшения тестирования правильности конфигурационного файла.
++
++
++configuration file validity test improvements.
++
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на Linux и Solaris;
++ошибка появилась в 0.7.12.
++
++
++nginx could not be built on Linux and Solaris;
++the bug had appeared in 0.7.12.
++
++
++
++
++
++
++
++
++
++
++директива server_name поддерживает пустое имя "".
++
++
++the "server_name" directive supports empty name "".
++
++
++
++
++
++директива gzip_disable поддерживает специальную маску msie6.
++
++
++the "gzip_disable" directive supports special "msie6" mask.
++
++
++
++
++
++при использовании параметра max_fails=0 в upstream'е с несколькими
++серверами рабочий процесс выходил по сигналу SIGFPE.
++Спасибо Максиму Дунину.
++
++
++if the "max_fails=0" parameter was used in upstream with several servers,
++then a worker process exited on a SIGFPE signal.
++Thanks to Maxim Dounin.
++
++
++
++
++
++при перенаправлении запроса с помощью директивы error_page
++терялось тело запроса.
++
++
++a request body was dropped while redirection via an "error_page" directive.
++
++
++
++
++
++при перенаправлении запроса с методом HEAD с помощью директивы error_page
++возвращался полный ответ.
++
++
++a full response was returned for request method HEAD
++while redirection via an "error_page" directive.
++
++
++
++
++
++метод $r->header_in() не возвращал значения строк "Host", "User-Agent",
++и "Connection" из заголовка запроса;
++ошибка появилась в 0.7.0.
++
++
++the $r->header_in() method did not return value of the "Host",
++"User-Agent", and "Connection" request header lines;
++the bug had appeared in 0.7.0.
++
++
++
++
++
++
++
++
++
++
++теперь ngx_http_charset_module по умолчанию не работает MIME-типом text/css.
++
++
++now ngx_http_charset_module does not work by default with text/css MIME type.
++
++
++
++
++
++теперь nginx возвращает код 405 для метода POST при запросе статического
++файла, только если файл существует.
++
++
++now nginx returns the 405 status code for POST method requesting a static file
++only if the file exists.
++
++
++
++
++
++директива proxy_ssl_session_reuse.
++
++
++the "proxy_ssl_session_reuse" directive.
++
++
++
++
++
++после перенаправления запроса с помощью "X-Accel-Redirect"
++директива proxy_pass без URI могла использовать оригинальный запрос.
++
++
++a "proxy_pass" directive without URI part might use original request
++after the "X-Accel-Redirect" redirection was used.
++
++
++
++
++
++если у каталога были права доступа только на поиск файлов
++и первый индексный файл отсутствовал, то nginx возвращал ошибку 500.
++
++
++if a directory has search only rights and the first index file was absent,
++then nginx returned the 500 status code.
++
++
++
++
++
++ошибок во вложенных location'ах;
++ошибки появились в 0.7.1.
++
++
++in inclusive locations;
++the bugs had appeared in 0.7.1.
++
++
++
++
++
++
++
++
++
++
++ошибок в директивах addition_types, charset_types,
++gzip_types, ssi_types, sub_filter_types и xslt_types;
++ошибки появились в 0.7.9.
++
++
++in the "addition_types", "charset_types",
++"gzip_types", "ssi_types", "sub_filter_types", and "xslt_types" directives;
++the bugs had appeared in 0.7.9.
++
++
++
++
++
++рекурсивной error_page для 500 ошибки.
++
++
++of recursive error_page for 500 status code.
++
++
++
++
++
++теперь модуль ngx_http_realip_module устанавливает адрес не для
++всего keepalive соединения, а для каждого запроса по этому соединению.
++
++
++now the ngx_http_realip_module sets address not for whole keepalive connection,
++but for each request passed via the connection.
++
++
++
++
++
++
++
++
++
++
++теперь ngx_http_charset_module по умолчанию работает со следующими MIME-типами:
++text/html, text/css, text/xml, text/plain, text/vnd.wap.wml,
++application/x-javascript и application/rss+xml.
++
++
++now ngx_http_charset_module works by default with following MIME types:
++text/html, text/css, text/xml, text/plain, text/vnd.wap.wml,
++application/x-javascript, and application/rss+xml.
++
++
++
++
++
++директивы charset_types и addition_types.
++
++
++the "charset_types" and "addition_types" directives.
++
++
++
++
++
++теперь директивы gzip_types, ssi_types и sub_filter_types используют хэш.
++
++
++now the "gzip_types", "ssi_types", and "sub_filter_types" directives use hash.
++
++
++
++
++
++модуль ngx_cpp_test_module.
++
++
++the ngx_cpp_test_module.
++
++
++
++
++
++директива expires поддерживает суточное время.
++
++
++the "expires" directive supports daily time.
++
++
++
++
++
++улучшения и исправления в модуле ngx_http_xslt_module.
++Спасибо Денису Латыпову и Максиму Дунину.
++
++
++the ngx_http_xslt_module improvements and bug fixing.
++Thanks to Denis F. Latypoff and Maxim Dounin.
++
++
++
++
++
++директива log_not_found не работала при поиске индексных файлов.
++
++
++the "log_not_found" directive did not work for index files tests.
++
++
++
++
++
++HTTPS-соединения могли зависнуть,
++если использовались методы kqueue, epoll, rtsig или eventport;
++ошибка появилась в 0.7.7.
++
++
++HTTPS connections might hang,
++if kqueue, epoll, rtsig, or eventport methods were used;
++the bug had appeared in 0.7.7.
++
++
++
++
++
++если в директивах server_name, valid_referers и map
++использовалась маска вида "*.domain.tld" и при этом полное имя
++вида "domain.tld" не было описано, то это имя попадало под маску;
++ошибка появилась в 0.3.18.
++
++
++if the "server_name", "valid_referers", and "map" directives used
++an "*.domain.tld" wildcard and exact name "domain.tld" was not set,
++then the exact name was matched by the wildcard;
++the bug had appeared in 0.3.18.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_xslt_module.
++
++
++the ngx_http_xslt_module.
++
++
++
++
++
++переменные "$arg_...".
++
++
++the "$arg_..." variables.
++
++
++
++
++
++поддержка directio в Solaris.
++Спасибо Ivan Debnar.
++
++
++Solaris directio support.
++Thanks to Ivan Debnar.
++
++
++
++
++
++теперь, если FastCGI-сервер присылает строку "Location" в заголовке ответа
++без строки статуса, то nginx использует код статуса 302.
++Спасибо Максиму Дунину.
++
++
++now if FastCGI server sends a "Location" header line without status line,
++then nginx uses 302 status code.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++теперь ошибка EAGAIN при вызове connect() не считается временной.
++
++
++now the EAGAIN error returned by connect() is not considered as temporary error.
++
++
++
++
++
++значением переменной $ssl_client_cert теперь является сертификат,
++перед каждой строкой которого, кроме первой, вставляется символ табуляции;
++неизменённый сертификат доступен через переменную $ssl_client_raw_cert.
++
++
++now the $ssl_client_cert variable value is a certificate with TAB character
++intended before each line except first one;
++an unchanged certificate is available in the $ssl_client_raw_cert variable.
++
++
++
++
++
++параметр ask директивы ssl_verify_client.
++
++
++the "ask" parameter in the "ssl_verify_client" directive.
++
++
++
++
++
++улучшения в обработке byte-range.
++Спасибо Максиму Дунину.
++
++
++byte-range processing improvements.
++Thanks to Maxim Dounin.
++
++
++
++
++
++директива directio.
++Спасибо Jiang Hong.
++
++
++the "directio" directive.
++Thanks to Jiang Hong.
++
++
++
++
++
++поддержка sendfile() в MacOSX 10.5.
++
++
++MacOSX 10.5 sendfile() support.
++
++
++
++
++
++в MacOSX и Cygwin при проверке location'ов теперь делается сравнение
++без учёта регистра символов;
++однако, сравнение ограничено только однобайтными locale'ями.
++
++
++now in MacOSX and Cygwin locations are tested in case insensitive mode;
++however, the compare is provided by single-byte locales only.
++
++
++
++
++
++соединения почтового прокси-сервера зависали в режиме SSL,
++если использовались методы select, poll или /dev/poll.
++
++
++mail proxy SSL connections hanged,
++if select, poll, or /dev/poll methods were used.
++
++
++
++
++
++ошибки при использовании кодировки UTF-8 в ngx_http_autoindex_module.
++
++
++UTF-8 encoding usage in the ngx_http_autoindex_module.
++
++
++
++
++
++
++
++
++
++
++теперь при использовании переменных в директиве access_log
++всегда проверяется существовании root'а для запроса.
++
++
++now if variables are used in the "access_log" directive
++a request root existence is always tested.
++
++
++
++
++
++модуль ngx_http_flv_module не поддерживал несколько значений в
++аргументах запроса.
++
++
++the ngx_http_flv_module did not support several values in a query string.
++
++
++
++
++
++
++
++
++
++
++Исправления в поддержке переменных в директиве access_log;
++ошибки появились в 0.7.4.
++
++
++Bugfixes in variables support in the "access_log" directive;
++the bugs had appeared in 0.7.4.
++
++
++
++
++
++nginx не собирался с параметром --without-http_gzip_module;
++ошибка появилась в 0.7.3.
++Спасибо Кириллу Коринскому.
++
++
++nginx could not be built --without-http_gzip_module;
++the bug had appeared in 0.7.3.
++Thanks to Kirill A. Korinskiy.
++
++
++
++
++
++при совместном использовании sub_filter и SSI
++ответы могли передаваться неверно.
++
++
++if sub_filter and SSI were used together, then responses might
++were transferred incorrectly.
++
++
++
++
++
++
++
++
++
++
++директива access_log поддерживает переменные.
++
++
++variables support in the "access_log" directive.
++
++
++
++
++
++директива open_log_file_cache.
++
++
++the "open_log_file_cache" directive.
++
++
++
++
++
++ключ -g.
++
++
++the -g switch.
++
++
++
++
++
++поддержка строки "Expect" в заголовке запроса.
++
++
++the "Expect" request header line support.
++
++
++
++
++
++большие включения в SSI могли передавались не полностью.
++
++
++large SSI inclusions might be truncated.
++
++
++
++
++
++
++
++
++
++
++MIME-тип для расширения rss изменён на "application/rss+xml".
++
++
++the "rss" extension MIME type has been changed to "application/rss+xml".
++
++
++
++
++
++теперь директива "gzip_vary on" выдаёт строку
++"Vary: Accept-Encoding"
++в заголовке ответа и для несжатых ответов.
++
++
++now the "gzip_vary" directive turned on issues
++a "Vary: Accept-Encoding"
++header line for uncompressed responses too.
++
++
++
++
++
++теперь при использовании протокола "https://" в директиве rewrite
++автоматически делается редирект.
++
++
++now the "rewrite" directive does a redirect automatically
++if the "https://" protocol is used.
++
++
++
++
++
++директива proxy_pass не работала с протоколом HTTPS;
++ошибка появилась в 0.6.9.
++
++
++the "proxy_pass" directive did not work with the HTTPS protocol;
++the bug had appeared in 0.6.9.
++
++
++
++
++
++
++
++
++
++
++теперь nginx поддерживает шифры с обменом EDH-ключами.
++
++
++now nginx supports EDH key exchange ciphers.
++
++
++
++
++
++директива ssl_dhparam.
++
++
++the "ssl_dhparam" directive.
++
++
++
++
++
++переменная $ssl_client_cert.
++Спасибо Manlio Perillo.
++
++
++the $ssl_client_cert variable.
++Thanks to Manlio Perillo.
++
++
++
++
++
++после изменения URI с помощью директивы rewrite nginx не искал новый location;
++ошибка появилась в 0.7.1.
++Спасибо Максиму Дунину.
++
++
++after changing URI via a "rewrite" directive nginx did not search
++a new location;
++the bug had appeared in 0.7.1.
++Thanks to Maxim Dounin.
++
++
++
++
++
++nginx не собирался без библиотеки PCRE;
++ошибка появилась в 0.7.1.
++
++
++nginx could not be built without PCRE library;
++the bug had appeared in 0.7.1.
++
++
++
++
++
++при редиректе запроса к каталогу с добавлением слэша nginx
++не добавлял аргументы из оригинального запроса.
++
++
++when a request to a directory was redirected with the slash added,
++nginx dropped a query string from the original request.
++
++
++
++
++
++
++
++
++
++
++теперь поиск location'а делается с помощью дерева.
++
++
++now locations are searched in a tree.
++
++
++
++
++
++директива optimize_server_names упразднена в связи с появлением
++директивы server_name_in_redirect.
++
++
++the "optimize_server_names" directive was canceled
++due to the "server_name_in_redirect" directive introduction.
++
++
++
++
++
++некоторые давно устаревшие директивы больше не поддерживаются.
++
++
++some long deprecated directives are not supported anymore.
++
++
++
++
++
++параметр "none" в директиве ssl_session_cache;
++теперь этот параметр используется по умолчанию.
++Спасибо Rob Mueller.
++
++
++the "none" parameter in the "ssl_session_cache" directive;
++now this is default parameter.
++Thanks to Rob Mueller.
++
++
++
++
++
++рабочие процессы могли не реагировать на сигналы переконфигурации
++и ротации логов.
++
++
++worker processes might not catch reconfiguration and log rotation signals.
++
++
++
++
++
++nginx не собирался на последних Fedora 9 Linux.
++Спасибо Roxis.
++
++
++nginx could not be built on latest Fedora 9 Linux.
++Thanks to Roxis.
++
++
++
++
++
++
++
++
++
++
++теперь символы 0x00-0x1F, '"' и '\' в access_log записываются в виде \xXX.
++Спасибо Максиму Дунину.
++
++
++now the 0x00-0x1F, '"' and '\' characters are escaped as \xXX in an
++access_log.
++Thanks to Maxim Dounin.
++
++
++
++
++
++теперь nginx разрешает несколько строк "Host" в заголовке запроса.
++
++
++now nginx allows several "Host" request header line.
++
++
++
++
++
++директива expires поддерживает флаг modified.
++
++
++the "modified" flag in the "expires" directive.
++
++
++
++
++
++переменные $uid_got и $uid_set можно использовать на любой стадии обработки
++запроса.
++
++
++the $uid_got and $uid_set variables may be used at any request processing stage.
++
++
++
++
++
++переменная $hostname.
++Спасибо Андрею Нигматулину.
++
++
++the $hostname variable.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++поддержка DESTDIR.
++Спасибо Todd A. Fisher и Andras Voroskoi.
++
++
++DESTDIR support.
++Thanks to Todd A. Fisher and Andras Voroskoi.
++
++
++
++
++
++при использовании keepalive на Linux
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process on Linux,
++if keepalive was enabled.
++
++
++
++
++
++
++
++
++
++
++nginx не обрабатывал ответ FastCGI-сервера, если строка заголовка ответа была
++в конце записи FastCGI;
++ошибка появилась в 0.6.2.
++Спасибо Сергею Серову.
++
++
++nginx did not process FastCGI response
++if header was at the end of FastCGI record;
++the bug had appeared in 0.6.2.
++Thanks to Sergey Serov.
++
++
++
++
++
++при удалении файла и использовании директивы open_file_cache_errors off
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process if a file was deleted
++and the "open_file_cache_errors" directive was off.
++
++
++
++
++
++
++
++
++
++
++теперь, если маске, заданной в директиве include, не соответствует
++ни один файл, то nginx не выдаёт ошибку.
++
++
++now if an "include" directive pattern does not match any file,
++then nginx does not issue an error.
++
++
++
++
++
++теперь время в директивах можно задавать без пробела, например, "1h50m".
++
++
++now the time in directives may be specified without spaces,
++for example, "1h50m".
++
++
++
++
++
++утечек памяти, если директива ssl_verify_client имела значение on.
++Спасибо Chavelle Vincent.
++
++
++memory leaks if the "ssl_verify_client" directive was on.
++Thanks to Chavelle Vincent.
++
++
++
++
++
++директива sub_filter могла вставлять заменяемый текст в вывод.
++
++
++the "sub_filter" directive might set text to change into output.
++
++
++
++
++
++директива error_page не воспринимала параметры в перенаправляемом URI.
++
++
++the "error_page" directive did not take into account arguments in
++redirected URI.
++
++
++
++
++
++теперь при сборке с Cygwin nginx всегда открывает файлы в бинарном режиме.
++
++
++now nginx always opens files in binary mode under Cygwin.
++
++
++
++
++
++nginx не собирался под OpenBSD;
++ошибка появилась в 0.6.15.
++
++
++nginx could not be built on OpenBSD;
++the bug had appeared in 0.6.15.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_google_perftools_module.
++
++
++the ngx_google_perftools_module.
++
++
++
++
++
++модуль ngx_http_perl_module не собирался на 64-битных платформах;
++ошибка появилась в 0.6.27.
++
++
++the ngx_http_perl_module could not be built on 64-bit platforms;
++the bug had appeared in 0.6.27.
++
++
++
++
++
++
++
++
++
++
++метод rtsig не собирался;
++ошибка появилась в 0.6.27.
++
++
++the rtsig method could not be built;
++the bug had appeared in 0.6.27.
++
++
++
++
++
++
++
++
++
++
++теперь на Linux 2.6.18+ по умолчанию не собирается метод rtsig.
++
++
++now by default the rtsig method is not built on Linux 2.6.18+.
++
++
++
++
++
++теперь при перенаправлении запроса в именованный location с помощью
++директивы error_page метод запроса не изменяется.
++
++
++now a request method is not changed while redirection to a named location
++via an "error_page" directive.
++
++
++
++
++
++директивы resolver и resolver_timeout в SMTP прокси-сервере.
++
++
++the "resolver" and "resolver_timeout" directives in SMTP proxy.
++
++
++
++
++
++директива post_action поддерживает именованные location'ы.
++
++
++the "post_action" directive supports named locations.
++
++
++
++
++
++при перенаправлении запроса из location'а c обработчиком proxy, FastCGI
++или memcached в именованный location со статическим обработчиком
++в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process,
++if a request was redirected from proxy, FastCGI, or memcached location
++to static named locations.
++
++
++
++
++
++браузеры не повторяли SSL handshake, если при первом handshake
++не оказалось правильного клиентского сертификата.
++
++Спасибо Александру Инюхину.
++
++
++browsers did not repeat SSL handshake if there is no valid client certificate
++in first handshake.
++
++Thanks to Alexander V. Inyukhin.
++
++
++
++
++
++при перенаправлении ошибок 495-497 с помощью директивы error_page
++без изменения кода ошибки nginx пытался выделить очень много памяти.
++
++
++if response code 495-497 was redirected via an "error_page" directive
++without code change, then nginx tried to allocate too many memory.
++
++
++
++
++
++утечки памяти в долгоживущих небуфферизированных соединениях.
++
++
++memory leak in long-lived non buffered connections.
++
++
++
++
++
++утечки памяти в resolver'е.
++
++
++memory leak in resolver.
++
++
++
++
++
++при перенаправлении запроса из location'а c обработчиком proxy
++в другой location с обработчиком proxy
++в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process,
++if a request was redirected from proxy, FastCGI, or memcached location
++to static named locations.
++
++
++
++
++
++ошибки в кэшировании переменных $proxy_host и $proxy_port.
++Спасибо Сергею Боченкову.
++
++
++in the $proxy_host and $proxy_port variables caching.
++Thanks to Sergey Bochenkov.
++
++
++
++
++
++директива proxy_pass с переменными использовала порт, описанной в другой
++директиве proxy_pass без переменных, но с таким же именем хоста.
++Спасибо Сергею Боченкову.
++
++
++a "proxy_pass" directive with variables used incorrectly the same port
++as in another "proxy_pass" directive with the same host name
++and without variables.
++Thanks to Sergey Bochenkov.
++
++
++
++
++
++во время переконфигурации на некоторых 64-битном платформах в лог
++записывался alert "sendmsg() failed (9: Bad file descriptor)".
++
++
++an alert "sendmsg() failed (9: Bad file descriptor)" on some 64-bit platforms
++while reconfiguration.
++
++
++
++
++
++при повторном использовании в SSI пустого block'а в качестве заглушки
++в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process,
++if empty stub block was used second time in SSI.
++
++
++
++
++
++ошибки при копировании части URI, содержащего экранированные символы,
++в аргументы.
++
++
++in copying URI part contained escaped symbols into arguments.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_store и fastcgi_store не проверяли длину ответа.
++
++
++the "proxy_store" and "fastcgi_store" directives did not check
++a response length.
++
++
++
++
++
++при использовании большого значения в директиве expires
++в рабочем процессе происходил segmentation fault.
++Спасибо Joaquin Cuenca Abela.
++
++
++a segmentation fault occurred in worker process,
++if big value was used in a "expires" directive.
++Thanks to Joaquin Cuenca Abela.
++
++
++
++
++
++nginx неверно определял длину строки кэша на Pentium 4.
++Спасибо Геннадию Махомеду.
++
++
++nginx incorrectly detected cache line size on Pentium 4.
++Thanks to Gena Makhomed.
++
++
++
++
++
++в проксированных подзапросах и подзапросах к FastCGI-серверу
++вместо метода GET использовался оригинальный метод клиента.
++
++
++in proxied or FastCGI subrequests a client original method was used
++instead of the GET method.
++
++
++
++
++
++утечки сокетов в режиме HTTPS при использовании отложенного accept'а.
++Спасибо Ben Maurer.
++
++
++socket leak in HTTPS mode if deferred accept was used.
++Thanks to Ben Maurer.
++
++
++
++
++
++nginx выдавал ошибочное сообщение "SSL_shutdown() failed (SSL: )";
++ошибка появилась в 0.6.23.
++
++
++nginx issued the bogus error message "SSL_shutdown() failed (SSL: )";
++the bug had appeared in 0.6.23.
++
++
++
++
++
++при использовании HTTPS запросы могли завершаться с ошибкой "bad write retry";
++ошибка появилась в 0.6.23.
++
++
++in HTTPS mode requests might fail with the "bad write retry" error;
++the bug had appeared in 0.6.23.
++
++
++
++
++
++
++
++
++
++
++вместо специального параметра "*" в директиве server_name теперь
++используется директива server_name_in_redirect.
++
++
++now the "server_name_in_redirect" directive is used instead of
++the "server_name" directive's special "*" parameter.
++
++
++
++
++
++в качестве основного имени в директиве server_name теперь
++можно использовать имена с масками и регулярными выражениями.
++
++
++now wildcard and regex names can be used as main name in
++a "server_name" directive.
++
++
++
++
++
++директива satisfy_any заменена директивой satisfy.
++
++
++the "satisfy_any" directive was replaced by the "satisfy" directive.
++
++
++
++
++
++после переконфигурации старые рабочие процесс могли сильно нагружать процессор
++при запуске под Linux OpenVZ.
++
++
++old worker processes might hog CPU after reconfiguration if they was run
++under Linux OpenVZ.
++
++
++
++
++
++директива min_delete_depth.
++
++
++the "min_delete_depth" directive.
++
++
++
++
++
++методы COPY и MOVE не работали с одиночными файлами.
++
++
++the COPY and MOVE methods did not work with single files.
++
++
++
++
++
++модуль ngx_http_gzip_static_module не позволял работать модулю
++ngx_http_dav_module;
++ошибка появилась в 0.6.23.
++
++
++the ngx_http_gzip_static_module did not allow the ngx_http_dav_module to work;
++the bug had appeared in 0.6.23.
++
++
++
++
++
++утечки сокетов в режиме HTTPS при использовании отложенного accept'а.
++Спасибо Ben Maurer.
++
++
++socket leak in HTTPS mode if deferred accept was used.
++Thanks to Ben Maurer.
++
++
++
++
++
++nginx не собирался без библиотеки PCRE;
++ошибка появилась в 0.6.23.
++
++
++nginx could not be built without PCRE library;
++the bug had appeared in 0.6.23.
++
++
++
++
++
++
++
++
++
++при использовании HTTPS в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.6.23.
++
++
++a segmentation fault might occur in worker process if HTTPS was used;
++the bug had appeared in 0.6.23.
++
++
++
++
++
++
++
++
++
++
++параметр "off" в директиве ssl_session_cache;
++теперь этот параметр используется по умолчанию.
++
++
++the "off" parameter in the "ssl_session_cache" directive;
++now this is default parameter.
++
++
++
++
++
++директива open_file_cache_retest переименована в open_file_cache_valid.
++
++
++the "open_file_cache_retest" directive was renamed
++to the "open_file_cache_valid".
++
++
++
++
++
++директива open_file_cache_min_uses.
++
++
++the "open_file_cache_min_uses" directive.
++
++
++
++
++
++модуль ngx_http_gzip_static_module.
++
++
++the ngx_http_gzip_static_module.
++
++
++
++
++
++директива gzip_disable.
++
++
++the "gzip_disable" directive.
++
++
++
++
++
++директиву memcached_pass можно использовать внутри блока if.
++
++
++the "memcached_pass" directive may be used inside the "if" block.
++
++
++
++
++
++если внутри одного location'а использовались директивы "memcached_pass" и "if",
++то в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process,
++if the "memcached_pass" and "if" directives were used in the same location.
++
++
++
++
++
++если при использовании директивы satisfy_any on" были заданы директивы
++не всех модулей доступа, то заданные директивы не проверялись.
++
++
++if a "satisfy_any on" directive was used and not all access and auth modules
++directives were set, then other given access and auth directives
++were not tested;
++
++
++
++
++
++параметры, заданные регулярным выражением в директиве valid_referers,
++не наследовалась с предыдущего уровня.
++
++
++regex parameters in a "valid_referers" directive were not inherited
++from previous level.
++
++
++
++
++
++директива post_action не работала, если запрос завершался с кодом 499.
++
++
++a "post_action" directive did run if a request was completed
++with 499 status code.
++
++
++
++
++
++оптимизация использования 16K буфера для SSL-соединения.
++Спасибо Ben Maurer.
++
++
++optimization of 16K buffer usage in a SSL connection.
++Thanks to Ben Maurer.
++
++
++
++
++
++STARTTLS в режиме SMTP не работал.
++Спасибо Олегу Мотиенко.
++
++
++the STARTTLS in SMTP mode did not work.
++Thanks to Oleg Motienko.
++
++
++
++
++
++при использовании HTTPS запросы могли завершаться с ошибкой "bad write retry";
++ошибка появилась в 0.5.13.
++
++
++in HTTPS mode requests might fail with the "bad write retry" error;
++the bug had appeared in 0.5.13.
++
++
++
++
++
++
++
++
++
++
++теперь все методы модуля ngx_http_perl_module
++возвращают значения, скопированные в память, выделенную perl'ом.
++
++
++now all ngx_http_perl_module methods return values copied to perl's
++allocated memory.
++
++
++
++
++
++если nginx был собран с модулем ngx_http_perl_module,
++использовался perl до версии 5.8.6 и perl поддерживал потоки,
++то во время переконфигурации основной процесс аварийно выходил;
++ошибка появилась в 0.5.9.
++Спасибо Борису Жмурову.
++
++
++if nginx was built with ngx_http_perl_module,
++the perl before 5.8.6 was used, and perl supported threads,
++then during reconfiguration the master process aborted;
++the bug had appeared in 0.5.9.
++Thanks to Boris Zhmurov.
++
++
++
++
++
++в методы модуля ngx_http_perl_module
++могли передаваться неверные результаты выделения в регулярных выражениях.
++
++
++the ngx_http_perl_module methods may get invalid values of the regex captures.
++
++
++
++
++
++если метод $r->has_request_body() вызывался для запроса,
++у которого небольшое тело запроса было уже полностью получено,
++то в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process,
++if the $r->has_request_body() method was called for a request
++whose small request body was already received.
++
++
++
++
++
++large_client_header_buffers не освобождались перед переходом в состояние
++keep-alive.
++Спасибо Олександру Штепе.
++
++
++large_client_header_buffers did not freed before going to keep-alive state.
++Thanks to Olexander Shtepa.
++
++
++
++
++
++в переменной $upstream_addr не записывался последний адрес;
++ошибка появилась в 0.6.18.
++
++
++the last address was missed in the $upstream_addr variable;
++the bug had appeared in 0.6.18.
++
++
++
++
++
++директива fastcgi_catch_stderr не возвращала ошибку;
++теперь она возвращает ошибку 502, которую можно направить на следующий сервер
++с помощью "fastcgi_next_upstream invalid_header".
++
++
++the "fastcgi_catch_stderr" directive did return error code;
++now it returns 502 code, that can be rerouted to a next server using
++the "fastcgi_next_upstream invalid_header" directive.
++
++
++
++
++
++при использовании директивы fastcgi_catch_stderr
++в основном процессе происходил segmentation fault;
++ошибка появилась в 0.6.10.
++Спасибо Manlio Perillo.
++
++
++a segmentation fault occurred in master process
++if the "fastcgi_catch_stderr" directive was used;
++the bug had appeared in 0.6.10.
++Thanks to Manlio Perillo.
++
++
++
++
++
++
++
++
++
++
++если в значениях переменных директивы proxy_pass используются
++только IP-адреса, то указывать resolver не нужно.
++
++
++if variable values used in a "proxy_pass" directive contain IP-addresses only,
++then a "resolver" directive is not mandatory.
++
++
++
++
++
++при использовании директивы proxy_pass c URI-частью
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.6.19.
++
++
++a segmentation fault might occur in worker process
++if a "proxy_pass" directive with URI-part was used;
++the bug had appeared in 0.6.19.
++
++
++
++
++
++если resolver использовался на платформах, не поддерживающих метод kqueue,
++то nginx выдавал alert "name is out of response".
++Спасибо Андрею Нигматулину.
++
++
++if resolver was used on platform that does not support kqueue,
++then nginx issued an alert "name is out of response".
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++При использовании переменной $server_protocol в FastCGI-параметрах
++и запросе, длина которого была близка к значению директивы
++client_header_buffer_size,
++nginx выдавал alert "fastcgi: the request record is too big".
++
++
++if the $server_protocol was used in FastCGI parameters
++and a request line length was near to the "client_header_buffer_size"
++directive value,
++then nginx issued an alert "fastcgi: the request record is too big".
++
++
++
++
++
++при обычном запросе версии HTTP/0.9 к HTTPS серверу nginx возвращал
++обычный ответ.
++
++
++if a plain text HTTP/0.9 version request was made to HTTPS server,
++then nginx returned usual response.
++
++
++
++
++
++
++
++
++
++
++при использовании директивы proxy_pass c URI-частью
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.6.19.
++
++
++a segmentation fault might occur in worker process
++if a "proxy_pass" directive with URI-part was used;
++the bug had appeared in 0.6.19.
++
++
++
++
++
++
++
++
++
++
++версия 0.6.18 не собиралась.
++
++
++the 0.6.18 version could not be built.
++
++
++
++
++
++
++
++
++
++теперь модуль ngx_http_userid_module в поле куки с номером процесса
++добавляет микросекунды на время старта.
++
++
++now the ngx_http_userid_module adds start time microseconds
++to the cookie field contains a pid value.
++
++
++
++
++
++в error_log теперь записывается полная строка запроса вместо только URI.
++
++
++now the full request line instead of URI only is written to error_log.
++
++
++
++
++
++директива proxy_pass поддерживает переменные.
++
++
++variables support in the "proxy_pass" directive.
++
++
++
++
++
++директивы resolver и resolver_timeout.
++
++
++the "resolver" and "resolver_timeout" directives.
++
++
++
++
++
++теперь директива "add_header last-modified ''" удаляет в заголовке ответа
++строку "Last-Modified".
++
++
++now the directive "add_header last-modified ''" deletes a "Last-Modified"
++response header line.
++
++
++
++
++
++директива limit_rate не позволяла передавать на полной скорости,
++даже если был указан очень большой лимит.
++
++
++the "limit_rate" directive did not allow to use full throughput,
++even if limit value was very high.
++
++
++
++
++
++
++
++
++
++
++поддержка строки "If-Range" в заголовке запроса.
++Спасибо Александру Инюхину.
++
++
++the "If-Range" request header line support.
++Thanks to Alexander V. Inyukhin.
++
++
++
++
++
++при использовании директивы msie_refresh повторно экранировались
++уже экранированные символы;
++ошибка появилась в 0.6.4.
++
++
++URL double escaping in a redirect of the "msie_refresh" directive;
++the bug had appeared in 0.6.4.
++
++
++
++
++
++директива autoindex не работала при использовании "alias /".
++
++
++the "autoindex" directive did not work with the "alias /" directive.
++
++
++
++
++
++при использовании подзапросов
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process if subrequests were used.
++
++
++
++
++
++при использовании SSL и gzip большие ответы могли передаваться не полностью.
++
++
++the big responses may be transferred truncated if SSL and gzip were used.
++
++
++
++
++
++если ответ проксированного сервера был версии HTTP/0.9,
++то переменная $status была равна 0.
++
++
++the $status variable was equal to 0 if a proxied server returned response
++in HTTP/0.9 version.
++
++
++
++
++
++
++
++
++
++
++теперь на Linux используется uname(2) вместо procfs.
++Спасибо Илье Новикову.
++
++
++now the uname(2) is used on Linux instead of procfs.
++Thanks to Ilya Novikov.
++
++
++
++
++
++если в директиве error_page использовался символ "?", то он экранировался
++при проксировании запроса;
++ошибка появилась в 0.6.11.
++
++
++if the "?" character was in a "error_page" directive, then it was escaped
++in a proxied request;
++the bug had appeared in 0.6.11.
++
++
++
++
++
++совместимость с mget.
++
++
++compatibility with mget.
++
++
++
++
++
++
++
++
++
++
++совместимость с Cygwin.
++Спасибо Владимиру Кутакову.
++
++
++Cygwin compatibility.
++Thanks to Vladimir Kutakov.
++
++
++
++
++
++директива merge_slashes.
++
++
++the "merge_slashes" directive.
++
++
++
++
++
++директива gzip_vary.
++
++
++the "gzip_vary" directive.
++
++
++
++
++
++директива server_tokens.
++
++
++the "server_tokens" directive.
++
++
++
++
++
++nginx не раскодировал URI в команде SSI include.
++
++
++nginx did not unescape URI in the "include" SSI command.
++
++
++
++
++
++при использовании переменной в директивах charset или source_charset
++на старте или во время переконфигурации происходил segmentation fault,
++
++
++the segmentation fault was occurred on start or while reconfiguration
++if variable was used in the "charset" or "source_charset" directives.
++
++
++
++
++
++nginx возвращал ошибку 400 на запросы вида
++"GET http://www.domain.com HTTP/1.0".
++Спасибо James Oakley.
++
++
++nginx returned the 400 response on requests like
++"GET http://www.domain.com HTTP/1.0".
++Thanks to James Oakley.
++
++
++
++
++
++после перенаправления запроса с телом запроса с помощью директивы
++error_page nginx пытался снова прочитать тело запроса;
++ошибка появилась в 0.6.7.
++
++
++if request with request body was redirected using the "error_page" directive,
++then nginx tried to read the request body again;
++the bug had appeared in 0.6.7.
++
++
++
++
++
++в рабочем процессе происходил segmentation fault, если у сервера,
++обрабатывающему запрос, не был явно определён server_name;
++ошибка появилась в 0.6.7.
++
++
++a segmentation fault occurred in worker process
++if no server_name was explicitly defined for server processing request;
++the bug had appeared in 0.6.7.
++
++
++
++
++
++
++
++
++
++
++теперь по умолчанию команда SSI echo использует кодирование entity.
++
++
++now by default the "echo" SSI command uses entity encoding.
++
++
++
++
++
++параметр encoding в команде SSI echo.
++
++
++the "encoding" parameter in the "echo" SSI command.
++
++
++
++
++
++директиву access_log можно использовать внутри блока limit_except.
++
++
++the "access_log" directive may be used inside the "limit_except" block.
++
++
++
++
++
++если все сервера апстрима оказывались недоступными,
++то до восстановления работоспособности
++у всех серверов вес становился равным одному;
++ошибка появилась в 0.6.6.
++
++
++if all upstream servers were failed, then all servers had got weight
++the was equal one until servers became alive;
++the bug had appeared in 0.6.6.
++
++
++
++
++
++при использовании переменных $date_local и $date_gmt вне модуля
++ngx_http_ssi_filter_module в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process
++if $date_local and $date_gmt were used outside the ngx_http_ssi_filter_module.
++
++
++
++
++
++при использовании включённом отладочном логе
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Андрею Нигматулину.
++
++
++a segmentation fault might occur in worker process
++if debug log was enabled.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++ngx_http_memcached_module не устанавливал $upstream_response_time.
++Спасибо Максиму Дунину.
++
++
++ngx_http_memcached_module did not set $upstream_response_time.
++Thanks to Maxim Dounin.
++
++
++
++
++
++рабочий процесс мог зациклиться при использовании memcached.
++
++
++a worker process may got caught in an endless loop, if the memcached was used.
++
++
++
++
++
++nginx распознавал параметры "close" и "keep-alive" в строке "Connection"
++в заголовке запроса только, если они были в нижнем регистре;
++ошибка появилась в 0.6.11.
++
++
++nginx supported low case only "close" and "keep-alive" values
++in the "Connection" request header line;
++the bug had appeared in 0.6.11.
++
++
++
++
++
++sub_filter не работал с пустой строкой замены.
++
++
++sub_filter did not work with empty substitution.
++
++
++
++
++
++в парсинге sub_filter.
++
++
++in sub_filter parsing.
++
++
++
++
++
++
++
++
++
++
++nginx не закрывал файл каталога для запроса HEAD,
++если использовался autoindex
++Спасибо Arkadiusz Patyk.
++
++
++nginx did not close directory file on HEAD request if autoindex was used.
++Thanks to Arkadiusz Patyk.
++
++
++
++
++
++
++
++
++
++
++почтовый прокси-сервер разделён на три модуля: pop3, imap и smtp.
++
++
++mail proxy was split on three modules: pop3, imap and smtp.
++
++
++
++
++
++параметры конфигурации --without-mail_pop3_module,
++--without-mail_imap_module и --without-mail_smtp_module.
++
++
++the --without-mail_pop3_module, --without-mail_imap_module,
++and --without-mail_smtp_module configuration parameters.
++
++
++
++
++
++директивы smtp_greeting_delay и smtp_client_buffer модуля ngx_mail_smtp_module.
++
++
++the "smtp_greeting_delay" and "smtp_client_buffer" directives
++of the ngx_mail_smtp_module.
++
++
++
++
++
++wildcard в конце имени сервера не работали;
++ошибка появилась в 0.6.9.
++
++
++the trailing wildcards did not work;
++the bug had appeared in 0.6.9.
++
++
++
++
++
++при использовании разделяемой библиотеки PCRE,
++расположенной в нестандартном месте, nginx не запускался на Solaris.
++
++
++nginx could not start on Solaris if the shared PCRE library located
++in non-standard place was used.
++
++
++
++
++
++директивы proxy_hide_header и fastcgi_hide_header не скрывали
++строки заголовка ответа с именем больше 32 символов.
++Спасибо Manlio Perillo.
++
++
++the "proxy_hide_header" and "fastcgi_hide_header" directives did not
++hide response header lines whose name was longer than 32 characters.
++Thanks to Manlio Perillo.
++
++
++
++
++
++
++
++
++
++
++счётчик активных соединений всегда рос при использовании почтового
++прокси-сервера.
++
++
++active connection counter always increased if mail proxy was used.
++
++
++
++
++
++если бэкенд возвращал только заголовок ответа при небуферизированном
++проксировании, то nginx закрывал соединение с бэкендом по таймауту.
++
++
++if backend returned response header only using non-buffered proxy,
++then nginx closed backend connection on timeout.
++
++
++
++
++
++nginx не поддерживал несколько строк "Connection" в заголовке запроса.
++
++
++nginx did not support several "Connection" request header lines.
++
++
++
++
++
++если в сервере апстрима был задан max_fails, то после первой же неудачной
++попытки вес сервера навсегда становился равным одному;
++ошибка появилась в 0.6.6.
++
++
++if the "max_fails" was set for upstream server, then after first
++failure server weight was always one;
++the bug had appeared in 0.6.6.
++
++
++
++
++
++
++
++
++
++
++директивы open_file_cache, open_file_cache_retest и open_file_cache_errors.
++
++
++the "open_file_cache", "open_file_cache_retest", and "open_file_cache_errors"
++directives.
++
++
++
++
++
++утечки сокетов;
++ошибка появилась в 0.6.7.
++
++
++socket leak;
++the bug had appeared in 0.6.7.
++
++
++
++
++
++В строку заголовка ответа "Content-Type", указанную в методе
++$r->send_http_header(), не добавлялась кодировка, указанная в директиве charset.
++
++
++a charset set by the "charset" directive was not appended
++to the "Content-Type" header set by $r->send_http_header().
++
++
++
++
++
++при использовании метода /dev/poll
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process
++if /dev/poll method was used.
++
++
++
++
++
++
++
++
++
++
++рабочий процесс мог зациклиться при использовании протокола HTTPS;
++ошибка появилась в 0.6.7.
++
++
++a worker process may got caught in an endless loop,
++if the HTTPS protocol was used;
++the bug had appeared in 0.6.7.
++
++
++
++
++
++если сервер слушал на двух адресах или портах, то nginx не запускался
++при использовании wildcard в конце имени сервера.
++
++
++if server listened on two addresses or ports and trailing wildcard was used,
++then nginx did not run.
++
++
++
++
++
++директива ip_hash могла неверно помечать сервера как нерабочие.
++
++
++the "ip_hash" directive might incorrectly mark servers as down.
++
++
++
++
++
++nginx не собирался на amd64;
++ошибка появилась в 0.6.8.
++
++
++nginx could not be built on amd64;
++the bug had appeared in 0.6.8.
++
++
++
++
++
++
++
++
++
++
++теперь nginx пытается установить директивы worker_priority,
++worker_rlimit_nofile, worker_rlimit_core, worker_rlimit_sigpending
++без привилегий root'а.
++
++
++now nginx tries to set the "worker_priority", "worker_rlimit_nofile",
++"worker_rlimit_core", and "worker_rlimit_sigpending" without super-user
++privileges.
++
++
++
++
++
++теперь nginx экранирует символы пробела и "%" при передаче запроса
++серверу аутентификации почтового прокси-сервера.
++
++
++now nginx escapes space and "%" in request to a mail proxy authentication
++server.
++
++
++
++
++
++теперь nginx экранирует символ "%" в переменной $memcached_key.
++
++
++now nginx escapes "%" in $memcached_key variable.
++
++
++
++
++
++при указании относительного пути к конфигурационному файлу в качестве
++параметра ключа -c nginx определял путь относительно конфигурационного префикса;
++ошибка появилась в 0.6.6.
++
++
++nginx used path relative to configuration prefix for non-absolute
++configuration file path specified in the "-c" key;
++the bug had appeared in 0.6.6.
++
++
++
++
++
++nginx не работал на FreeBSD/sparc64.
++
++
++nginx did not work on FreeBSD/sparc64.
++
++
++
++
++
++
++
++
++
++
++теперь пути, указанные в директивах include, auth_basic_user_file,
++perl_modules, ssl_certificate, ssl_certificate_key и
++ssl_client_certificate, определяются относительно каталога конфигурационного
++файла nginx.conf, а не относительно префикса.
++
++
++now the paths specified in the "include", "auth_basic_user_file",
++"perl_modules", "ssl_certificate", "ssl_certificate_key", and
++"ssl_client_certificate" directives are relative to directory of
++nginx configuration file nginx.conf, but not to nginx prefix directory.
++
++
++
++
++
++параметр --sysconfdir=PATH в configure упразднён.
++
++
++the --sysconfdir=PATH option in configure was canceled.
++
++
++
++
++
++для обновления на лету версий 0.1.x создан специальный сценарий
++make upgrade1.
++
++
++the special make target "upgrade1" was defined for online upgrade of
++0.1.x versions.
++
++
++
++
++
++директивы server_name и valid_referers поддерживают регулярные выражения.
++
++
++the "server_name" and "valid_referers" directives support regular expressions.
++
++
++
++
++
++директива server в блоке upstream поддерживает параметр backup.
++
++
++the "server" directive in the "upstream" context supports
++the "backup" parameter.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает метод $r->discard_request_body.
++
++
++the ngx_http_perl_module supports the $r->discard_request_body.
++
++
++
++
++
++директива "add_header Last-Modified ..." меняет строку "Last-Modified"
++в заголовке ответа.
++
++
++the "add_header Last-Modified ..." directive changes the "Last-Modified"
++response header line.
++
++
++
++
++
++если на запрос с телом возвращался ответ с кодом HTTP отличным от 200,
++и после этого запроса соединение переходило в состояние keep-alive,
++то на следующий запрос nginx возвращал 400.
++
++
++if a response different than 200 was returned to a request with body
++and connection went to the keep-alive state after the request, then
++nginx returned 400 for the next request.
++
++
++
++
++
++если в директиве auth_http был задан неправильный адрес, то
++в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process
++if invalid address was set in the "auth_http" directive.
++
++
++
++
++
++теперь по умолчанию nginx использует значение 511 для listen backlog
++на всех платформах, кроме FreeBSD.
++Спасибо Jiang Hong.
++
++
++now nginx uses default listen backlog value 511 on all platforms
++except FreeBSD.
++Thanks to Jiang Hong.
++
++
++
++
++
++рабочий процесс мог зациклиться, если server в блоке upstream был помечен
++как down;
++ошибка появилась в 0.6.6.
++
++
++a worker process may got caught in an endless loop, if a "server" inside
++"upstream" block was marked as "down";
++the bug had appeared in 0.6.6.
++
++
++
++
++
++sendfilev() в Solaris теперь не используется при передаче тела запроса
++FastCGI-серверу через unix domain сокет.
++
++
++now Solaris sendfilev() is not used to transfer the client request body
++to FastCGI-server via the unix domain socket.
++
++
++
++
++
++
++
++
++
++
++параметр --sysconfdir=PATH в configure.
++
++
++the --sysconfdir=PATH option in configure.
++
++
++
++
++
++именованные location'ы.
++
++
++named locations.
++
++
++
++
++
++переменную $args можно устанавливать с помощью set.
++
++
++the $args variable can be set with the "set" directive.
++
++
++
++
++
++переменная $is_args.
++
++
++the $is_args variable.
++
++
++
++
++
++равномерное распределение запросов к апстримам с большими весами.
++
++
++fair big weight upstream balancer.
++
++
++
++
++
++если клиент в почтовом прокси-сервере закрывал соединение,
++то nginx мог не закрывать соединение с бэкендом.
++
++
++if a client has closed connection to mail proxy
++ then nginx might not close connection to backend.
++
++
++
++
++
++при использовании одного хоста в качестве бэкендов для протоколов HTTP и HTTPS
++без явного указания портов, nginx использовал только один порт—80 или 443.
++
++
++if the same host without specified port was used as backend for HTTP and HTTPS,
++then nginx used only one port—80 or 443.
++
++
++
++
++
++nginx не собирался на Solaris/amd64 Sun Studio 11 и более ранними версиями;
++ошибка появилась в 0.6.4.
++
++
++fix building on Solaris/amd64 by Sun Studio 11 and early versions;
++the bug had appeared in 0.6.4.
++
++
++
++
++
++
++
++
++
++
++переменная $nginx_version.
++Спасибо Николаю Гречуху.
++
++
++$nginx_version variable.
++Thanks to Nick S. Grechukh.
++
++
++
++
++
++почтовый прокси-сервер поддерживает AUTHENTICATE в режиме IMAP.
++Спасибо Максиму Дунину.
++
++
++the mail proxy supports AUTHENTICATE in IMAP mode.
++Thanks to Maxim Dounin.
++
++
++
++
++
++почтовый прокси-сервер поддерживает STARTTLS в режиме SMTP.
++Спасибо Максиму Дунину.
++
++
++the mail proxy supports STARTTLS in SMTP mode.
++Thanks to Maxim Dounin.
++
++
++
++
++
++теперь nginx экранирует пробел в переменной $memcached_key.
++
++
++now nginx escapes space in $memcached_key variable.
++
++
++
++
++
++nginx неправильно собирался Sun Studio на Solaris/amd64.
++Спасибо Jiang Hong.
++
++
++nginx was incorrectly built by Sun Studio on Solaris/amd64.
++Thanks to Jiang Hong.
++
++
++
++
++
++незначительных потенциальных ошибок.
++Спасибо Coverity's Scan.
++
++
++of minor potential bugs.
++Thanks to Coverity's Scan.
++
++
++
++
++
++
++
++
++
++
++при использовании директивы msie_refresh был возможен XSS.
++Спасибо Максиму Богуку.
++
++
++the "msie_refresh" directive allowed XSS.
++Thanks to Maxim Boguk.
++
++
++
++
++
++директивы proxy_store и fastcgi_store изменены.
++
++
++the "proxy_store" and "fastcgi_store" directives were changed.
++
++
++
++
++
++директивы proxy_store_access и fastcgi_store_access.
++
++
++the "proxy_store_access" and "fastcgi_store_access" directives.
++
++
++
++
++
++nginx не работал на Solaris/sparc64, если был собран Sun Studio.
++Спасибо Андрею Нигматулину.
++
++
++nginx did not work on Solaris/sparc64 if it was built by Sun Studio.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++обход ошибки в Sun Studio 12.
++Спасибо Jiang Hong.
++
++
++for Sun Studio 12.
++Thanks to Jiang Hong.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_store и fastcgi_store.
++
++
++the "proxy_store" and "fastcgi_store" directives.
++
++
++
++
++
++при использовании директивы auth_http_header
++в рабочем процессе мог произойти segmentation fault.
++Спасибо Максиму Дунину.
++
++
++a segmentation fault might occur in worker process
++if the "auth_http_header" directive was used.
++Thanks to Maxim Dounin.
++
++
++
++
++
++если использовался метод аутентификации CRAM-MD5, но он не был разрешён,
++то в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process
++if the CRAM-MD5 authentication method was used, but it was not enabled.
++
++
++
++
++
++при использовании протокола HTTPS в директиве proxy_pass
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process when
++the HTTPS protocol was used in the "proxy_pass" directive.
++
++
++
++
++
++в рабочем процессе мог произойти segmentation fault,
++если использовался метод eventport.
++
++
++a segmentation fault might occur in worker process
++if the eventport method was used.
++
++
++
++
++
++директивы proxy_ignore_client_abort и fastcgi_ignore_client_abort не работали;
++ошибка появилась в 0.5.13.
++
++
++the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives
++did not work;
++the bug had appeared in 0.5.13.
++
++
++
++
++
++
++
++
++
++
++если заголовок ответа был разделён в FastCGI-записях, то nginx передавал
++клиенту мусор в таких заголовках.
++
++
++if the FastCGI header was split in records,
++then nginx passed garbage in the header to a client.
++
++
++
++
++
++
++
++
++
++
++в парсинге SSI.
++
++
++in SSI parsing.
++
++
++
++
++
++при использовании удалённого подзапроса в SSI последующий
++подзапрос локального файла мог отдаваться клиенту в неверном порядке.
++
++
++if remote SSI subrequest was used, then posterior local file subrequest
++might transferred to client in wrong order.
++
++
++
++
++
++большие включения в SSI, сохранённые во временные файлы,
++передавались не полностью.
++
++
++large SSI inclusions buffered in temporary files were truncated.
++
++
++
++
++
++значение perl'овой переменной $$ модуля ngx_http_perl_module было равно
++номеру главного процесса.
++
++
++the perl $$ variable value in ngx_http_perl_module was equal to the master
++process identification number.
++
++
++
++
++
++
++
++
++
++
++директивы "server_name", "map", and "valid_referers" поддерживают
++маски вида "www.example.*".
++
++
++the "server_name", "map", and "valid_referers" directives support
++the "www.example.*" wildcards.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с параметром --without-http_rewrite_module;
++ошибка появилась в 0.5.24.
++
++
++nginx could not be built with the --without-http_rewrite_module parameter;
++the bug had appeared in 0.5.24.
++
++
++
++
++
++
++
++
++
++
++директива ssl_verify_client не работала, если запрос выполнялся
++по протоколу HTTP/0.9.
++
++
++the "ssl_verify_client" directive did not work if request was made
++using HTTP/0.9.
++
++
++
++
++
++при использовании сжатия часть ответа могла передаваться несжатой;
++ошибка появилась в 0.5.23.
++
++
++a part of response body might be passed uncompressed if gzip was used;
++the bug had appeared in 0.5.23.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_ssl_module поддерживает расширение TLS Server Name Indication.
++
++
++the ngx_http_ssl_module supports Server Name Indication TLS extension.
++
++
++
++
++
++директива fastcgi_catch_stderr.
++Спасибо Николаю Гречуху, проект OWOX.
++
++
++the "fastcgi_catch_stderr" directive.
++Thanks to Nick S. Grechukh, OWOX project.
++
++
++
++
++
++на Линуксе в основном процессе происходил segmentation fault,
++если два виртуальных сервера должны bind()ится к пересекающимся портам.
++
++
++a segmentation fault occurred in master process if
++two virtual servers should bind() to the overlapping ports.
++
++
++
++
++
++если nginx был собран с модулем ngx_http_perl_module и perl
++поддерживал потоки, то во время второй переконфигурации
++выдавались ошибки "panic: MUTEX_LOCK" и "perl_parse() failed".
++
++
++if nginx was built with ngx_http_perl_module and perl supported threads,
++then during second reconfiguration the error messages
++"panic: MUTEX_LOCK" and "perl_parse() failed" were issued.
++
++
++
++
++
++в использовании протокола HTTPS в директиве proxy_pass.
++
++
++in the HTTPS protocol in the "proxy_pass" directive.
++
++
++
++
++
++
++
++
++
++
++большое тело запроса могло не передаваться бэкенду;
++ошибка появилась в 0.5.21.
++
++
++a big request body might not be passed to backend;
++the bug had appeared in 0.5.21.
++
++
++
++
++
++
++
++
++
++
++если внутри сервера описано больше примерно десяти location'ов,
++то location'ы, заданные с помощью регулярного выражения,
++могли выполняться не в том, порядке, в каком они описаны.
++
++
++if server has more than about ten locations, then regex locations
++might be chosen not in that order as they were specified.
++
++
++
++
++
++на 64-битной платформе рабочий процесс мог зациклиться, если 33-тий
++по счёту или последующий бэкенд упал.
++Спасибо Антону Поварову.
++
++
++a worker process may got caught in an endless loop on 64-bit platform,
++if the 33-rd or next in succession backend has failed.
++Thanks to Anton Povarov.
++
++
++
++
++
++при использовании библиотеки PCRE на Solaris/sparc64
++мог произойти bus error.
++Спасибо Андрею Нигматулину.
++
++
++a bus error might occur on Solaris/sparc64 if the PCRE library was used.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++в использовании протокола HTTPS в директиве proxy_pass.
++
++
++in the HTTPS protocol in the "proxy_pass" directive.
++
++
++
++
++
++
++
++
++
++
++директива sendfile_max_chunk.
++
++
++the "sendfile_max_chunk" directive.
++
++
++
++
++
++переменные "$http_...", "$sent_http_..." и "$upstream_http_..."
++можно менять директивой set.
++
++
++the "$http_...", "$sent_http_...", and "$upstream_http_..." variables
++may be changed using the "set" directive.
++
++
++
++
++
++при использовании SSI-команды 'if expr="$var = /"'
++в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process
++if the SSI command 'if expr="$var = /"' was used.
++
++
++
++
++
++завершающая строка multipart range ответа передавалась неверно.
++Спасибо Evan Miller.
++
++
++trailing boundary of multipart range response was transferred incorrectly.
++Thanks to Evan Miller.
++
++
++
++
++
++nginx не работал на Solaris/sparc64, если был собран Sun Studio.
++Спасибо Андрею Нигматулину.
++
++
++nginx did not work on Solaris/sparc64 if it was built by Sun Studio.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++модуль ngx_http_perl_module не собирался make в Solaris.
++Спасибо Андрею Нигматулину.
++
++
++the ngx_http_perl_module could not be built by Solaris make.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++
++
++
++
++
++значение переменной $request_time теперь записывается с точностью
++до миллисекунд.
++
++
++now the $request_time variable has millisecond precision.
++
++
++
++
++
++метод $r->rflush в модуле ngx_http_perl_module переименован в $r->flush.
++
++
++the method $r->rflush of ngx_http_perl_module was renamed to the $r->flush.
++
++
++
++
++
++переменная $upstream_addr.
++
++
++the $upstream_addr variable.
++
++
++
++
++
++директивы proxy_headers_hash_max_size и proxy_headers_hash_bucket_size.
++Спасибо Володымыру Костырко.
++
++
++the "proxy_headers_hash_max_size" and "proxy_headers_hash_bucket_size"
++directives.
++Thanks to Volodymyr Kostyrko.
++
++
++
++
++
++при использовании sendfile и limit_rate на 64-битных платформах
++нельзя было передавать файлы больше 2G.
++
++
++the files more than 2G could not be transferred using sendfile and limit_rate
++on 64-bit platforms.
++
++
++
++
++
++при использовании sendfile на 64-битном Linux нельзя было передавать файлы
++больше 2G.
++
++
++the files more than 2G could not be transferred using sendfile on 64-bit Linux.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_sub_filter_module.
++
++
++the ngx_http_sub_filter_module.
++
++
++
++
++
++переменные "$upstream_http_...".
++
++
++the "$upstream_http_..." variables.
++
++
++
++
++
++теперь переменные $upstream_status и $upstream_response_time
++содержат данные о всех обращениях к апстримам, сделанным до X-Accel-Redirect.
++
++
++now the $upstream_status and $upstream_response_time variables
++keep data about all upstreams before X-Accel-Redirect.
++
++
++
++
++
++если nginx был собран с модулем ngx_http_perl_module и perl
++не поддерживал multiplicity, то после первой переконфигурации
++и после получения любого сигнала
++в основном процессе происходил segmentation fault;
++ошибка появилась в 0.5.9.
++
++
++a segmentation fault occurred in master process
++after first reconfiguration and receiving any signal
++if nginx was built with ngx_http_perl_module and perl
++did not support multiplicity;
++the bug had appeared in 0.5.9.
++
++
++
++
++
++если perl не поддерживал multiplicity, то после переконфигурации
++перловый код не работал;
++ошибка появилась в 0.3.38.
++
++
++if perl did not support multiplicity, then after reconfiguration
++perl code did not work;
++the bug had appeared in 0.3.38.
++
++
++
++
++
++
++
++
++
++
++теперь nginx для метода TRACE всегда возвращает код 405.
++
++
++now nginx always returns the 405 status for the TRACE method.
++
++
++
++
++
++теперь nginx поддерживает директиву include внутри блока types.
++
++
++now nginx supports the "include" directive inside the "types" block.
++
++
++
++
++
++использование переменной $document_root в директиве root и alias
++запрещено: оно вызывало рекурсивное переполнение стека.
++
++
++the $document_root variable usage in the "root" and "alias" directives
++is disabled: this caused recursive stack overflow.
++
++
++
++
++
++в использовании протокола HTTPS в директиве proxy_pass.
++
++
++in the HTTPS protocol in the "proxy_pass" directive.
++
++
++
++
++
++в некоторых случаях некэшируемые переменные (такие, как $uri)
++возвращали старое закэшированное значение.
++
++
++in some cases non-cacheable variables (such as $uri variable)
++returned old cached value.
++
++
++
++
++
++
++
++
++
++
++в качестве ключа для хэша в директиве ip_hash не использовалась сеть
++класса С.
++Спасибо Павлу Ярковому.
++
++
++the C-class network was not used as hash key in the "ip_hash" directive.
++Thanks to Pavel Yarkovoy.
++
++
++
++
++
++если в строке "Content-Type" в заголовке ответа бэкенда был указан charset
++и строка завершалась символом ";",
++то в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.3.50.
++
++
++a segmentation fault might occur in worker process
++if a charset was set in the "Content-Type" header line and the line
++has trailing ";";
++the bug had appeared in 0.3.50.
++
++
++
++
++
++ошибки "[alert] zero size buf" при работе с FastCGI-сервером, если
++тело запроса, записанное во временный файл, было кратно 32K.
++
++
++the "[alert] zero size buf" error when FastCGI server was used and
++a request body written in a temporary file was multiple of 32K.
++
++
++
++
++
++nginx не собирался на Solaris без параметра --with-debug;
++ошибка появилась в 0.5.15.
++
++
++nginx could not be built on Solaris without the --with-debug option;
++the bug had appeared in 0.5.15.
++
++
++
++
++
++
++
++
++
++
++почтовый прокси-сервер поддерживает аутентифицированное SMTP-проксирование и
++директивы smtp_auth, smtp_capabilities и xclient.
++Спасибо Антону Южанинову и Максиму Дунину.
++
++
++the mail proxy supports authenticated SMTP proxying and
++the "smtp_auth", "smtp_capabilities", and "xclient" directives.
++Thanks to Anton Yuzhaninov and Maxim Dounin.
++
++
++
++
++
++теперь keep-alive соединения закрываются сразу же по получении сигнала
++переконфигурации.
++
++
++now the keep-alive connections are closed just after receiving
++the reconfiguration signal.
++
++
++
++
++
++директивы imap и auth переименованы соответственно в mail и pop3_auth.
++
++
++the "imap" and "auth" directives were renamed
++to the "mail" and "pop3_auth" directives.
++
++
++
++
++
++если использовался метод аутентификации CRAM-MD5 и не был разрешён метод APOP,
++то в рабочем процессе происходил segmentation fault.
++
++
++a segmentation fault occurred in worker process
++if the CRAM-MD5 authentication method was used
++and the APOP method was disabled.
++
++
++
++
++
++при использовании директивы starttls only в протоколе POP3 nginx
++разрешал аутентификацию без перехода в режим SSL.
++
++
++if the "starttls only" directive was used in POP3 protocol,
++then nginx allowed authentication without switching to the SSL mode.
++
++
++
++
++
++рабочие процессы не выходили после переконфигурации и не переоткрывали логи,
++если использовался метод eventport.
++
++
++worker processes did not exit after reconfiguration and
++did not rotate logs if the eventport method was used.
++
++
++
++
++
++при использовании директивы ip_hash рабочий процесс мог зациклиться.
++
++
++a worker process may got caught in an endless loop,
++if the "ip_hash" directive was used.
++
++
++
++
++
++теперь nginx не пишет в лог некоторые alert'ы,
++если используются методы eventport или /dev/poll.
++
++
++now nginx does not log some alerts if eventport or /dev/poll methods are used.
++
++
++
++
++
++
++
++
++
++
++nginx игнорировал лишние закрывающие скобки "}" в конце
++конфигурационного файла.
++
++
++nginx ignored superfluous closing "}" in the end of configuration file.
++
++
++
++
++
++
++
++
++
++
++методы COPY и MOVE.
++
++
++the COPY and MOVE methods.
++
++
++
++
++
++модуль ngx_http_realip_module устанавливал мусор для запросов,
++переданных по keep-alive соединению.
++
++
++the ngx_http_realip_module set garbage for requests passed via
++keep-alive connection.
++
++
++
++
++
++nginx не работал на 64-битном big-endian Linux.
++Спасибо Андрею Нигматулину.
++
++
++nginx did not work on big-endian 64-bit Linux.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++при получении слишком длинной команды IMAP/POP3-прокси теперь сразу
++закрывает соединение, а не по таймауту.
++
++
++now when IMAP/POP3 proxy receives too long command it closes the connection
++right away, but not after timeout.
++
++
++
++
++
++если при использовании метода epoll клиент закрывал преждевременно
++соединение со своей стороны, то nginx закрывал это соединение только
++по истечении таймаута на передачу.
++
++
++if the "epoll" method was used and a client closed a connection prematurely,
++then nginx closed the connection after a send timeout only.
++
++
++
++
++
++nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
++ошибка появилась в 0.5.8.
++
++
++nginx could not be built on platforms different from i386, amd64, sparc,
++and ppc;
++the bug had appeared in 0.5.8.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
++ошибка появилась в 0.5.8.
++
++
++nginx could not be built on platforms different from i386, amd64, sparc,
++and ppc;
++the bug had appeared in 0.5.8.
++
++
++
++
++
++при использовании временных файлов в время работы с FastCGI-сервером
++в рабочем процессе мог произойти segmentation fault;
++ошибка появилась в 0.5.8.
++
++
++a segmentation fault might occur in worker process
++if the temporary files were used while working with FastCGI server;
++the bug had appeared in 0.5.8.
++
++
++
++
++
++если переменная $fastcgi_script_name записывалась в лог,
++то в рабочем процессе мог произойти segmentation fault.
++
++
++a segmentation fault might occur in worker process
++if the $fastcgi_script_name variable was logged.
++
++
++
++
++
++ngx_http_perl_module не собирался на Solaris.
++
++
++ngx_http_perl_module could not be built on Solaris.
++
++
++
++
++
++
++
++
++
++
++теперь configure определяет библиотеку PCRE в MacPorts.
++Спасибо Chris McGrath.
++
++
++now configure detects system PCRE library in MacPorts.
++Thanks to Chris McGrath.
++
++
++
++
++
++ответ был неверным, если запрашивалось несколько диапазонов;
++ошибка появилась в 0.5.6.
++
++
++the response was incorrect if several ranges were requested;
++the bug had appeared in 0.5.6.
++
++
++
++
++
++директива create_full_put_path не могла создавать промежуточные каталоги,
++если не была установлена директива dav_access.
++Спасибо Evan Miller.
++
++
++the "create_full_put_path" directive could not create the intermediate
++directories if no "dav_access" directive was set.
++Thanks to Evan Miller.
++
++
++
++
++
++вместо кодов ошибок "400" и "408" в access_log мог записываться код "0".
++
++
++the "0" response code might be logged in the access_log instead of
++the "400" and "408" error codes.
++
++
++
++
++
++при сборке с оптимизацией -O2 в рабочем процессе мог произойти
++segmentation fault.
++
++
++a segmentation fault might occur in worker process
++if nginx was built with -O2 optimization.
++
++
++
++
++
++
++
++
++
++
++во время обновления исполняемого файла новый процесс не наследовал
++слушающие сокеты;
++ошибка появилась в 0.5.9.
++
++
++while online executable file upgrade the new master process did not
++inherit the listening sockets;
++the bug had appeared in 0.5.9.
++
++
++
++
++
++при сборке с оптимизацией -O2 в рабочем процессе мог произойти
++segmentation fault;
++ошибка появилась в 0.5.1.
++
++
++a segmentation fault might occur in worker process
++if nginx was built with -O2 optimization;
++the bug had appeared in 0.5.1.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_memcached_module теперь в качестве ключа использует
++значение переменной $memcached_key.
++
++
++now the ngx_http_memcached_module uses the $memcached_key variable value
++as a key.
++
++
++
++
++
++переменная $memcached_key.
++
++
++the $memcached_key variable.
++
++
++
++
++
++параметр clean в директиве client_body_in_file_only.
++
++
++the "clean" parameter in the "client_body_in_file_only" directive.
++
++
++
++
++
++директива env.
++
++
++the "env" directive.
++
++
++
++
++
++директива sendfile работает внутри блока if.
++
++
++the "sendfile" directive is available inside the "if" block.
++
++
++
++
++
++теперь при ошибке записи в access_log nginx записывает сообщение в error_log,
++но не чаще одного раза в минуту.
++
++
++now on failure of the writing to access nginx logs a message to error_log,
++but not more often than once a minute.
++
++
++
++
++
++директива "access_log off" не всегда запрещала запись в лог.
++
++
++the "access_log off" directive did not always turn off the logging.
++
++
++
++
++
++
++
++
++
++
++если использовалась директива "client_body_in_file_only on"
++и тело запроса было небольшое, то мог произойти segmentation fault.
++
++
++a segmentation fault might occur if
++"client_body_in_file_only on" was used
++and a request body was small.
++
++
++
++
++
++происходил segmentation fault, если использовались директивы
++"client_body_in_file_only on"
++и "proxy_pass_request_body off"
++или "fastcgi_pass_request_body off",
++и делался переход к следующему бэкенду.
++
++
++a segmentation fault occurred if "client_body_in_file_only on"
++and "proxy_pass_request_body off"
++or "fastcgi_pass_request_body off"
++directives were used, and nginx switched to a next upstream.
++
++
++
++
++
++если при использовании директивы "proxy_buffering off" соединение с клиентом
++было неактивно, то оно закрывалось по таймауту, заданному директивой
++send_timeout;
++ошибка появилась в 0.4.7.
++
++
++if the "proxy_buffering off" directive was used and a client connection
++was non-active, then the connection was closed after send timeout;
++the bug had appeared in 0.4.7.
++
++
++
++
++
++если при использовании метода epoll клиент закрывал преждевременно
++соединение со своей стороны, то nginx закрывал это соединение только
++по истечении таймаута на передачу.
++
++
++if the "epoll" method was used and a client closed a connection prematurely,
++then nginx closed the connection after a send timeout only.
++
++
++
++
++
++ошибки "[alert] zero size buf" при работе с FastCGI-сервером.
++
++
++the "[alert] zero size buf" error when FastCGI server was used.
++
++
++
++
++
++Исправление ошибок в директиве limit_zone.
++
++
++Bugfixes in the "limit_zone" directive.
++
++
++
++
++
++
++
++
++
++
++оптимизация использования памяти в ssl_session_cache.
++
++
++the ssl_session_cache storage optimization.
++
++
++
++
++
++Исправление ошибок в директивах ssl_session_cache и limit_zone.
++
++
++Bugfixes in the "ssl_session_cache" and "limit_zone" directives.
++
++
++
++
++
++на старте или во время переконфигурации происходил segmentation fault,
++если директивы ssl_session_cache или limit_zone использовались
++на 64-битных платформах.
++
++
++the segmentation fault was occurred on start or while reconfiguration
++if the "ssl_session_cache" or "limit_zone" directives were used
++on 64-bit platforms.
++
++
++
++
++
++при использовании директив add_before_body или add_after_body происходил
++segmentation fault, если в заголовке ответа нет строки "Content-Type".
++
++
++a segmentation fault occurred if the "add_before_body" or "add_after_body"
++directives were used and there was no "Content-Type" header line in response.
++
++
++
++
++
++библиотека OpenSSL всегда собиралась с поддержкой потоков.
++Спасибо Дену Иванову.
++
++
++the OpenSSL library was always built with the threads support.
++Thanks to Den Ivanov.
++
++
++
++
++
++совместимость библиотеки PCRE-6.5+ и компилятора icc.
++
++
++the PCRE-6.5+ library and the icc compiler compatibility.
++
++
++
++
++
++
++
++
++
++
++теперь модуль ngx_http_index_module игнорирует все методы,
++кроме GET, HEAD и POST.
++
++
++now the ngx_http_index_module ignores all methods except the GET, HEAD, and
++POST methods.
++
++
++
++
++
++модуль ngx_http_limit_zone_module.
++
++
++the ngx_http_limit_zone_module.
++
++
++
++
++
++переменная $binary_remote_addr.
++
++
++the $binary_remote_addr variable.
++
++
++
++
++
++директивы ssl_session_cache модулей ngx_http_ssl_module и ngx_imap_ssl_module.
++
++
++the "ssl_session_cache" directives
++of the ngx_http_ssl_module and ngx_imap_ssl_module.
++
++
++
++
++
++метод DELETE поддерживает рекурсивное удаление.
++
++
++the DELETE method supports recursive removal.
++
++
++
++
++
++при использовании $r->sendfile() byte-ranges передавались неверно.
++
++
++the byte-ranges were transferred incorrectly if the $r->sendfile() was used.
++
++
++
++
++
++
++
++
++
++
++ключ -v больше не выводит информацию о компиляторе.
++
++
++the -v switch does not show compiler information any more.
++
++
++
++
++
++ключ -V.
++
++
++the -V switch.
++
++
++
++
++
++директива worker_rlimit_core поддерживает указание размера в K, M и G.
++
++
++the "worker_rlimit_core" directive supports size in K, M, and G.
++
++
++
++
++
++модуль nginx.pm теперь может устанавливаться непривилегированным пользователем.
++
++
++the nginx.pm module now could be installed by an unprivileged user.
++
++
++
++
++
++при использовании методов $r->request_body или $r->request_body_file мог
++произойти segmentation fault.
++
++
++a segmentation fault might occur if the $r->request_body or
++$r->request_body_file methods were used.
++
++
++
++
++
++ошибок, специфичных для платформы ppc.
++
++
++the ppc platform specific bugs.
++
++
++
++
++
++
++
++
++
++
++директиву perl можно использовать внутри блока limit_except.
++
++
++the "perl" directive may be used inside the "limit_except" block.
++
++
++
++
++
++модуль ngx_http_dav_module требовал строку "Date" в заголовке запроса
++для метода DELETE.
++
++
++the ngx_http_dav_module required the "Date" request header line
++for the DELETE method.
++
++
++
++
++
++при использовании одного параметра в директиве dav_access nginx мог
++сообщить об ошибке в конфигурации.
++
++
++if one only parameter was used in the "dav_access" directive, then
++nginx might report about configuration error.
++
++
++
++
++
++при использовании переменной $host мог произойти segmentation fault;
++ошибка появилась в 0.4.14.
++
++
++a segmentation fault might occur if the $host variable was used;
++the bug had appeared in 0.4.14.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает методы $r->status, $r->log_error
++и $r->sleep.
++
++
++the ngx_http_perl_module supports the $r->status, $r->log_error,
++and $r->sleep methods.
++
++
++
++
++
++метод $r->variable поддерживает переменные, неописанные в конфигурации nginx'а.
++
++
++the $r->variable method supports variables that do not exist in nginx
++configuration.
++
++
++
++
++
++метод $r->has_request_body не работал.
++
++
++the $r->has_request_body method did not work.
++
++
++
++
++
++
++
++
++
++
++если в директивах proxy_pass использовалось имя, указанное в upstream,
++то nginx пытался найти IP-адрес этого имени;
++ошибка появилась в 0.5.1.
++
++
++if the "proxy_pass" directive used the name of the "upstream" block,
++then nginx tried to resolve the name;
++the bug had appeared in 0.5.1.
++
++
++
++
++
++
++
++
++
++
++директива post_action могла не работать после неудачного завершения запроса.
++
++
++the "post_action" directive might not run after a unsuccessful completion
++of a request.
++
++
++
++
++
++обход ошибки в Eudora для Mac;
++ошибка появилась в 0.4.11.
++Спасибо Bron Gondwana.
++
++
++for Eudora for Mac;
++the bug had appeared in 0.4.11.
++Thanks to Bron Gondwana.
++
++
++
++
++
++при указании в директиве fastcgi_pass имени описанного upstream'а выдавалось
++сообщение "no port in upstream";
++ошибка появилась в 0.5.0.
++
++
++if the "upstream" name was used in the "fastcgi_pass", then the message
++"no port in upstream" was issued;
++the bug had appeared in 0.5.0.
++
++
++
++
++
++если в директивах proxy_pass и fastcgi_pass использовались одинаковых имена
++серверов, но с разными портами, то эти директивы использовали первый
++описанный порт;
++ошибка появилась в 0.5.0.
++
++
++if the "proxy_pass" and "fastcgi_pass" directives used the same servers but
++different ports, then these directives uses the first described port;
++the bug had appeared in 0.5.0.
++
++
++
++
++
++если в директивах proxy_pass и fastcgi_pass использовались unix domain сокеты,
++то эти директивы использовали первый описанный сокет;
++ошибка появилась в 0.5.0.
++
++
++if the "proxy_pass" and "fastcgi_pass" directives used the unix domain sockets,
++then these directives used first described socket;
++the bug had appeared in 0.5.0.
++
++
++
++
++
++ngx_http_auth_basic_module игнорировал пользователя, если он был указан
++в последней строке файла паролей и после пароля не было перевода строки,
++возврата каретки или символа ":".
++
++
++ngx_http_auth_basic_module ignored the user if it was in the last line in
++the password file and there was no the carriage return, the line feed,
++or the ":" symbol after the password.
++
++
++
++
++
++переменная $upstream_response_time могла быть равна "0.000", хотя время
++обработки было больше 1 миллисекунды.
++
++
++the $upstream_response_time variable might be equal to "0.000", although
++response time was more than 1 millisecond.
++
++
++
++
++
++
++
++
++
++
++параметры в виде "%name" в директиве log_format больше не поддерживаются.
++
++
++the parameters in the "%name" form in the "log_format" directive
++are not supported anymore.
++
++
++
++
++
++директивы proxy_upstream_max_fails, proxy_upstream_fail_timeout,
++fastcgi_upstream_max_fails, и fastcgi_upstream_fail_timeout,
++memcached_upstream_max_fails и memcached_upstream_fail_timeout
++больше не поддерживаются.
++
++
++the "proxy_upstream_max_fails", "proxy_upstream_fail_timeout",
++"fastcgi_upstream_max_fails", "fastcgi_upstream_fail_timeout",
++"memcached_upstream_max_fails", and "memcached_upstream_fail_timeout"
++directives are not supported anymore.
++
++
++
++
++
++директива server в блоке upstream поддерживает параметры
++max_fails, fail_timeout и down.
++
++
++the "server" directive in the "upstream" context supports
++the "max_fails", "fail_timeout", and "down" parameters.
++
++
++
++
++
++директива ip_hash в блоке upstream.
++
++
++the "ip_hash" directive inside the "upstream" block.
++
++
++
++
++
++статус WAIT в строке "Auth-Status" в заголовке ответа сервера аутентификации
++IMAP/POP3 прокси.
++
++
++the WAIT status in the "Auth-Status" header line of the IMAP/POP3 proxy
++authentication server response.
++
++
++
++
++
++nginx не собирался на 64-битных платформах;
++ошибка появилась в 0.4.14.
++
++
++nginx could not be built on 64-bit platforms;
++the bug had appeared in 0.4.14.
++
++
++
++
++
++
++
++
++
++
++директива proxy_pass_error_message в IMAP/POP3 прокси.
++
++
++the "proxy_pass_error_message" directive in IMAP/POP3 proxy.
++
++
++
++
++
++теперь configure определяет библиотеку PCRE на FreeBSD, Linux и NetBSD.
++
++
++now configure detects system PCRE library on FreeBSD, Linux, and NetBSD.
++
++
++
++
++
++ngx_http_perl_module не работал с перлом, собранным с поддержкой потоков;
++ошибка появилась в 0.3.38.
++
++
++ngx_http_perl_module did not work with perl built with the threads support;
++the bug had appeared in 0.3.38.
++
++
++
++
++
++ngx_http_perl_module не работал корректно, если перл вызывался рекурсивно.
++
++
++ngx_http_perl_module did not work if perl was called recursively.
++
++
++
++
++
++nginx игнорировал имя сервера в строке запроса.
++
++
++nginx ignored a host name in a request line.
++
++
++
++
++
++если FastCGI сервер передавал много в stderr,
++то рабочий процесс мог зациклиться.
++
++
++a worker process may got caught in an endless loop,
++if a FastCGI server sent too many data to the stderr.
++
++
++
++
++
++при изменении системного времени переменная $upstream_response_time
++могла быть отрицательной.
++
++
++the $upstream_response_time variable may be negative if the system time
++was changed backward.
++
++
++
++
++
++при использовании POP3 серверу аутентификации IMAP/POP3 прокси
++не передавался параметр Auth-Login-Attempt.
++
++
++the "Auth-Login-Attempt" parameter was not sent to
++IMAP/POP3 proxy authentication server when POP3 was used.
++
++
++
++
++
++при ошибке соединения с сервером аутентификации IMAP/POP3 прокси
++мог произойти segmentation fault.
++
++
++a segmentation fault might occur if connect to IMAP/POP3 proxy
++authentication server failed.
++
++
++
++
++
++
++
++
++
++
++директиву proxy_pass можно использовать внутри блока limit_except.
++
++
++the "proxy_pass" directive may be used inside the "limit_except" block.
++
++
++
++
++
++директива limit_except поддерживает все WebDAV методы.
++
++
++the "limit_except" directive supports all WebDAV methods.
++
++
++
++
++
++при использовании директивы add_before_body без директивы add_after_body
++ответ передавался не полностью.
++
++
++if the "add_before_body" directive was used without
++the "add_after_body" directive, then a response did not transferred complete.
++
++
++
++
++
++большое тело запроса не принималось, если использовались метод epoll
++и deferred accept().
++
++
++a large request body did not receive if the epoll method
++and the deferred accept() were used.
++
++
++
++
++
++для ответов модуля ngx_http_autoindex_module не выставлялась кодировка;
++ошибка появилась в 0.3.50.
++
++
++a charset could not be set for ngx_http_autoindex_module responses;
++the bug had appeared in 0.3.50.
++
++
++
++
++
++ошибки "[alert] zero size buf" при работе с FastCGI-сервером;
++
++
++the "[alert] zero size buf" error when FastCGI server was used;
++
++
++
++
++
++параметр конфигурации --group= игнорировался.
++Спасибо Thomas Moschny.
++
++
++the --group= configuration parameter was ignored.
++Thanks to Thomas Moschny.
++
++
++
++
++
++50-й подзапрос в SSI ответе не работал;
++ошибка появилась в 0.3.50.
++
++
++the 50th subrequest in SSI response did not work;
++the bug had appeared in 0.3.50.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает метод $r->variable.
++
++
++the ngx_http_perl_module supports the $r->variable method.
++
++
++
++
++
++при включении в ответ большого статического файла с помощью SSI
++ответ мог передаваться не полностью.
++
++
++if a big static file was included using SSI in a response,
++then the response may be transferred incomplete.
++
++
++
++
++
++nginx не убирал "#fragment" в URI.
++
++
++nginx did not omit the "#fragment" part in URI.
++
++
++
++
++
++
++
++
++
++
++POP3 прокси поддерживает AUTH LOGIN PLAIN и CRAM-MD5.
++
++
++the POP3 proxy supports the AUTH LOGIN PLAIN and CRAM-MD5.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает метод $r->allow_ranges.
++
++
++the ngx_http_perl_module supports the $r->allow_ranges method.
++
++
++
++
++
++при включённой поддержке команды APOP в POP3 прокси могли
++не работать команды USER/PASS;
++ошибка появилась в 0.4.10.
++
++
++if the APOP was enabled in the POP3 proxy, then the USER/PASS commands
++might not work;
++the bug had appeared in 0.4.10.
++
++
++
++
++
++
++
++
++
++
++POP3 прокси поддерживает APOP.
++
++
++the POP3 proxy supports the APOP command.
++
++
++
++
++
++при использовании методов select, poll и /dev/poll во время ожидания
++ответа от сервера аутентификации IMAP/POP3 прокси нагружал процессор.
++
++
++if the select, poll or /dev/poll methods were used, then while
++waiting authentication server response the IMAP/POP3 proxy hogged CPU.
++
++
++
++
++
++при использовании переменной $server_addr в директиве map мог
++произойти segmentation fault.
++
++
++a segmentation fault might occur if the $server_addr variable was used
++in the "map" directive.
++
++
++
++
++
++модуль ngx_http_flv_module не поддерживал byte ranges для полных ответов;
++ошибка появилась в 0.4.7.
++
++
++the ngx_http_flv_module did not support the byte ranges for full responses;
++the bug had appeared in 0.4.7.
++
++
++
++
++
++nginx не собирался на Debian amd64;
++ошибка появилась в 0.4.9.
++
++
++nginx could not be built on Debian amd64;
++the bug had appeared in 0.4.9.
++
++
++
++
++
++
++
++
++
++
++параметр set в команде SSI include.
++
++
++the "set" parameter in the "include" SSI command.
++
++
++
++
++
++модуль ngx_http_perl_module теперь проверяет версию модуля nginx.pm.
++
++
++the ngx_http_perl_module now tests the nginx.pm module version.
++
++
++
++
++
++
++
++
++
++
++если до команды SSI include с параметром wait выполнялась ещё
++одна команда SSI include, то параметр wait мог не работать.
++
++
++if an "include" SSI command were before another "include" SSI command
++with a "wait" parameter, then the "wait" parameter might not work.
++
++
++
++
++
++модуль ngx_http_flv_module добавлял FLV-заголовок для полных ответов.
++Спасибо Алексею Ковырину.
++
++
++the ngx_http_flv_module added the FLV header to the full responses.
++Thanks to Alexey Kovyrin.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_flv_module.
++
++
++the ngx_http_flv_module.
++
++
++
++
++
++переменная $request_body_file.
++
++
++the $request_body_file variable.
++
++
++
++
++
++директивы charset и source_charset поддерживают переменные.
++
++
++the "charset" and "source_charset" directives support the variables.
++
++
++
++
++
++если до команды SSI include с параметром wait выполнялась ещё
++одна команда SSI include, то параметр wait мог не работать.
++
++
++if an "include" SSI command were before another "include" SSI command
++with a "wait" parameter, then the "wait" parameter might not work.
++
++
++
++
++
++при использовании директивы "proxy_buffering off" или при работе
++с memcached соединения могли не закрываться по таймауту.
++
++
++if the "proxy_buffering off" directive was used or while working with
++memcached the connections might not be closed on timeout.
++
++
++
++
++
++nginx не запускался на 64-битных платформах, отличных от amd64, sparc64 и ppc64.
++
++
++nginx did not run on 64-bit platforms except amd64, sparc64, and ppc64.
++
++
++
++
++
++
++
++
++
++
++nginx не запускался на 64-битных платформах, отличных от amd64, sparc64 и ppc64.
++
++
++nginx did not run on 64-bit platforms except amd64, sparc64, and ppc64.
++
++
++
++
++
++при запросе версии HTTP/1.1 nginx передавал ответ chunk'ами,
++если длина ответа в методе $r->headers_out("Content-Length", ...)
++была задана текстовой строкой.
++
++
++nginx sent the chunked response for HTTP/1.1 request,
++if its length was set by text string in
++the $r->headers_out("Content-Length", ...) method.
++
++
++
++
++
++после перенаправления ошибки с помощью директивы error_page любая директива
++модуля ngx_http_rewrite_module возвращала эту ошибку;
++ошибка появилась в 0.4.4.
++
++
++after redirecting error by an "error_page" directive
++any ngx_http_rewrite_module directive returned this error code;
++the bug had appeared in 0.4.4.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на Linux и Solaris;
++ошибка появилась в 0.4.4.
++
++
++nginx could not be built on Linux and Solaris;
++the bug had appeared in 0.4.4.
++
++
++
++
++
++
++
++
++
++
++переменная $scheme.
++
++
++the $scheme variable.
++
++
++
++
++
++директива expires поддерживает параметр max.
++
++
++the "expires" directive supports the "max" parameter.
++
++
++
++
++
++директива include поддерживает маску "*".
++Спасибо Jonathan Dance.
++
++
++the "include" directive supports the "*" mask.
++Thanks to Jonathan Dance.
++
++
++
++
++
++директива return всегда изменяла код ответа, перенаправленного
++директивой error_page.
++
++
++the "return" directive always overrode the "error_page" response code
++redirected by the "error_page" directive.
++
++
++
++
++
++происходил segmentation fault, если в методе PUT передавалось
++тело нулевой длины.
++
++
++a segmentation fault occurred if zero-length body was in PUT method.
++
++
++
++
++
++при использовании переменных в директиве proxy_redirect редирект
++изменялся неверно.
++
++
++the redirect was changed incorrectly if the variables were used
++in the "proxy_redirect" directive.
++
++
++
++
++
++
++
++
++
++
++ошибку 499 теперь нельзя перенаправить с помощью директивы error_page.
++
++
++now the 499 error could not be redirected using an "error_page" directive.
++
++
++
++
++
++поддержка Solaris 10 event ports.
++
++
++the Solaris 10 event ports support.
++
++
++
++
++
++модуль ngx_http_browser_module.
++
++
++the ngx_http_browser_module.
++
++
++
++
++
++при перенаправлении ошибки 400 проксированному серверу
++помощью директивы error_page мог произойти segmentation fault.
++
++
++a segmentation fault may occur while redirecting the 400 error
++to the proxied server using a "proxy_pass" directive.
++
++
++
++
++
++происходил segmentation fault, если в директиве proxy_pass использовался
++unix domain сокет;
++ошибка появилась в 0.3.47.
++
++
++a segmentation fault occurred if an unix domain socket was used in
++a "proxy_pass" directive;
++the bug had appeared in 0.3.47.
++
++
++
++
++
++SSI не работал с ответами memcached и небуферизированными проксированными
++ответами.
++
++
++SSI did work with memcached and nonbuffered responses.
++
++
++
++
++
++обход ошибки PAUSE hardware capability в Sun Studio.
++
++
++of the Sun Studio PAUSE hardware capability bug.
++
++
++
++
++
++
++
++
++
++
++убрана поддержка флага O_NOATIME на Linux;
++ошибка появилась в 0.4.1.
++
++
++the O_NOATIME flag support on Linux was canceled;
++the bug had appeared in 0.4.1.
++
++
++
++
++
++
++
++
++
++
++совместимость с DragonFlyBSD.
++Спасибо Павлу Назарову.
++
++
++the DragonFlyBSD compatibility.
++Thanks to Pavel Nazarov.
++
++
++
++
++
++обход ошибки в sendfile() в 64-битном Linux при передаче файлов больше 2G.
++
++
++of bug in 64-bit Linux sendfile(), when file is more than 2G.
++
++
++
++
++
++теперь на Linux nginx для статических запросов использует флаг O_NOATIME.
++Спасибо Yusuf Goolamabbas.
++
++
++now on Linux nginx uses O_NOATIME flag for static requests.
++Thanks to Yusuf Goolamabbas.
++
++
++
++
++
++
++
++
++
++
++Изменение во внутреннем API: инициализация модулей HTTP перенесена из фазы
++init module в фазу HTTP postconfiguration.
++
++
++Change in internal API: the HTTP modules initialization was moved
++from the init module phase to the HTTP postconfiguration phase.
++
++
++
++
++
++теперь тело запроса в модуле ngx_http_perl_module не считывается
++заранее: нужно явно инициировать чтение с помощью метода $r->has_request_body.
++
++
++now the request body is not read beforehand for the ngx_http_perl_module:
++it's required to start the reading using the $r->has_request_body method.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает код возврата DECLINED.
++
++
++the ngx_http_perl_module supports the DECLINED return code.
++
++
++
++
++
++модуль ngx_http_dav_module поддерживает входящую строку заголовка "Date"
++для метода PUT.
++
++
++the ngx_http_dav_module supports the incoming "Date" header line
++for the PUT method.
++
++
++
++
++
++директива ssi работает внутри блока if.
++
++
++the "ssi" directive is available inside the "if" block.
++
++
++
++
++
++происходил segmentation fault, если в директиве index использовалась
++переменные и при этом первое имя индексного файла было без переменных;
++ошибка появилась в 0.1.29.
++
++
++a segmentation fault occurred if there was an "index" directive with
++variables and the first index name was without variables;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++
++
++
++
++
++директива tcp_nodelay теперь по умолчанию включена.
++
++
++now the "tcp_nodelay" directive is turned on by default.
++
++
++
++
++
++директива msie_refresh.
++
++
++the "msie_refresh" directive.
++
++
++
++
++
++директива recursive_error_pages.
++
++
++the "recursive_error_pages" directive.
++
++
++
++
++
++директива rewrite возвращала неправильный редирект, если редирект
++включал в себя выделенные закодированные символы из оригинального URI.
++
++
++the "rewrite" directive returned incorrect redirect, if the redirect
++had the captured escaped symbols from original URI.
++
++
++
++
++
++
++
++
++
++
++во время перенаправления ошибки рабочий процесс мог зациклиться;
++ошибка появилась в 0.3.59.
++
++
++a worker process may got caught in an endless loop
++while an error redirection;
++the bug had appeared in 0.3.59.
++
++
++
++
++
++
++
++
++
++
++теперь можно делать несколько перенаправлений через директиву error_page.
++
++
++now is possible to do several redirection using the "error_page" directive.
++
++
++
++
++
++директива dav_access не поддерживала три параметра.
++
++
++the "dav_access" directive did not support three parameters.
++
++
++
++
++
++директива error_page не изменяла строку "Content-Type"
++после перенаправления с помощью "X-Accel-Redirect";
++ошибка появилась в 0.3.58.
++
++
++the "error_page" directive did not changes the "Content-Type" header line
++after the "X-Accel-Redirect" was used;
++the bug had appeared in 0.3.58.
++
++
++
++
++
++
++
++
++
++
++директива error_page поддерживает переменные.
++
++
++the "error_page" directive supports the variables.
++
++
++
++
++
++теперь на Linux используется интерфейс procfs вместо sysctl.
++
++
++now the procfs interface instead of sysctl is used on Linux.
++
++
++
++
++
++теперь при использовании "X-Accel-Redirect" строка "Content-Type" наследуется
++из первоначального ответа.
++
++
++now the "Content-Type" header line is inherited from first response
++when the "X-Accel-Redirect" was used.
++
++
++
++
++
++директива error_page не перенаправляла ошибку 413.
++
++
++the "error_page" directive did not redirect the 413 error.
++
++
++
++
++
++завершающий "?" не удалял старые аргументы, если в переписанном URI
++не было новых аргументов.
++
++
++the trailing "?" did not remove old arguments if no new arguments
++were added to a rewritten URI.
++
++
++
++
++
++nginx не запускался на 64-битной FreeBSD 7.0-CURRENT.
++
++
++nginx could not run on 64-bit FreeBSD 7.0-CURRENT.
++
++
++
++
++
++
++
++
++
++
++переменная $ssl_client_serial.
++
++
++the $ssl_client_serial variable.
++
++
++
++
++
++в операторе "!-e" в директиве if.
++Спасибо Андриану Буданцову.
++
++
++in the "!-e" operator of the "if" directive.
++Thanks to Andrian Budanstov.
++
++
++
++
++
++при проверке клиентского сертификата nginx не передавал клиенту
++информацию о требуемых сертификатах.
++
++
++while a client certificate verification nginx did not send to a client
++the required certificates information.
++
++
++
++
++
++переменная $document_root не поддерживала переменные в директиве root.
++
++
++the $document_root variable did not support the variables in the "root"
++directive.
++
++
++
++
++
++
++
++
++
++
++директива dav_access.
++
++
++the "dav_access" directive.
++
++
++
++
++
++директива if поддерживает операторы "-d", "!-d", "-e", "!-e", "-x" и "!-x".
++
++
++the "if" directive supports the "-d", "!-d", "-e", "!-e", "-x", and "!-x"
++operators.
++
++
++
++
++
++при записи в access_log некоторых передаваемых клиенту строк заголовков
++происходил segmentation fault, если запрос возвращал редирект.
++
++
++a segmentation fault occurred if a request returned a redirect and
++some sent to client header lines were logged in the access log.
++
++
++
++
++
++
++
++
++
++
++параметр stub в команде SSI include.
++
++
++the "stub" parameter in the "include" SSI command.
++
++
++
++
++
++команда SSI block.
++
++
++the "block" SSI command.
++
++
++
++
++
++скрипт unicode2nginx добавлен в contrib.
++
++
++the unicode2nginx script was added to contrib.
++
++
++
++
++
++если root был задан только переменной, то корень задавался
++относительно префикса сервера.
++
++
++if a "root" was specified by variable only, then the root was relative
++to a server prefix.
++
++
++
++
++
++если в запросе был "//" или "/.", и после этого закодированные
++символы в виде "%XX", то проксируемый запрос передавался незакодированным.
++
++
++if the request contained "//" or "/./" and escaped symbols after them,
++then the proxied request was sent unescaped.
++
++
++
++
++
++метод $r->header_in("Cookie") модуля ngx_http_perl_module теперь возвращает
++все строки "Cookie" в заголовке запроса.
++
++
++the $r->header_in("Cookie") of the ngx_http_perl_module now returns
++all "Cookie" header lines.
++
++
++
++
++
++происходил segmentation fault, если использовался
++"client_body_in_file_only on"
++и делался переход к следующему бэкенду.
++
++
++a segmentation fault occurred if "client_body_in_file_only on"
++was used and nginx switched to a next upstream.
++
++
++
++
++
++при некоторых условиях во время переконфигурации коды символов
++внутри директивы charset_map могли считаться неверными;
++ошибка появилась в 0.3.50.
++
++
++on some condition while reconfiguration character codes
++inside the "charset_map" may be treated invalid;
++the bug had appeared in 0.3.50.
++
++
++
++
++
++
++
++
++
++
++nginx теперь записывает в лог информацию о подзапросах.
++
++
++nginx now logs the subrequest information to the error log.
++
++
++
++
++
++директивы proxy_next_upstream, fastcgi_next_upstream и memcached_next_upstream
++поддерживают параметр off.
++
++
++the "proxy_next_upstream", "fastcgi_next_upstream",
++and "memcached_next_upstream" directives support the "off" parameter.
++
++
++
++
++
++директива debug_connection поддерживает запись адресов в формате CIDR.
++
++
++the "debug_connection" directive supports the CIDR address form.
++
++
++
++
++
++при перекодировании ответа проксированного сервера или сервера FastCGI
++в UTF-8 или наоборот ответ мог передаваться не полностью.
++
++
++if a response of proxied server or FastCGI server was converted from UTF-8
++or back, then it may be transferred incomplete.
++
++
++
++
++
++переменная $upstream_response_time содержала время только первого
++обращения к бэкенду.
++
++
++the $upstream_response_time variable had the time of the first
++request to a backend only.
++
++
++
++
++
++nginx не собирался на платформе amd64;
++ошибка появилась в 0.3.53.
++
++
++nginx could not be built on amd64 platform;
++the bug had appeared in 0.3.53.
++
++
++
++
++
++
++
++
++
++
++директива add_header добавляет строки в ответы с кодом 204, 301 и 302.
++
++
++the "add_header" directive adds the string to 204, 301, and 302 responses.
++
++
++
++
++
++директива server в блоке upstream поддерживает параметр weight.
++
++
++the "server" directive in the "upstream" context supports
++the "weight" parameter.
++
++
++
++
++
++директива server_name поддерживает маску "*".
++
++
++the "server_name" directive supports the "*" wildcard.
++
++
++
++
++
++nginx поддерживает тело запроса больше 2G.
++
++
++nginx supports the request body size more than 2G.
++
++
++
++
++
++если при использовании "satisfy_any on" клиент успешно проходил аутентификацию,
++в лог всё равно записалоcь сообщение "access forbidden by rule".
++
++
++if a client was successfully authorized using "satisfy_any on", then anyway
++the message "access forbidden by rule" was written in the log.
++
++
++
++
++
++метод PUT мог ошибочно не создать файл и вернуть код 409.
++
++
++the "PUT" method may erroneously not create a file and return the 409 code.
++
++
++
++
++
++если во время аутентификации IMAP/POP3 бэкенд возвращал ошибку, nginx
++продолжал проксирование.
++
++
++if the IMAP/POP3 backend returned an error, then nginx continued proxying
++anyway.
++
++
++
++
++
++
++
++
++
++
++восстановлено поведение модуля ngx_http_index_module для запросов "POST /":
++как в версии до 0.3.40, модуль теперь не выдаёт ошибку 405.
++
++
++the ngx_http_index_module behavior for the "POST /" requests is reverted
++to the 0.3.40 version state: the module now does not return the 405 error.
++
++
++
++
++
++при использовании ограничения скорости рабочий процесс мог зациклиться;
++ошибка появилась в 0.3.37.
++
++
++the worker process may got caught in an endless loop if the limit rate was used;
++the bug had appeared in 0.3.37.
++
++
++
++
++
++модуль ngx_http_charset_module записывал в лог ошибку "unknown charset",
++даже если перекодировка не требовалась;
++ошибка появилась в 0.3.50.
++
++
++ngx_http_charset_module logged "unknown charset" alert, even if the recoding
++was not needed;
++the bug had appeared in 0.3.50.
++
++
++
++
++
++если в результате запроса PUT возвращался код 409, то временный файл
++не удалялся.
++
++
++if a code response of the PUT request was 409, then a temporary file
++was not removed.
++
++
++
++
++
++
++
++
++
++
++при некоторых условиях в SSI мог пропадать символы "<";
++ошибка появилась в 0.3.50.
++
++
++the "<" symbols might disappeared some conditions in the SSI;
++the bug had appeared in 0.3.50.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_redirect_errors и fastcgi_redirect_errors
++переименованы соответственно в proxy_intercept_errors и
++fastcgi_intercept_errors.
++
++
++the "proxy_redirect_errors" and "fastcgi_redirect_errors" directives
++was renamed to the "proxy_intercept_errors" and
++"fastcgi_intercept_errors" directives.
++
++
++
++
++
++модуль ngx_http_charset_module поддерживает перекодирование из
++однобайтных кодировок в UTF-8 и обратно.
++
++
++the ngx_http_charset_module supports the recoding from the single byte
++encodings to the UTF-8 encoding and back.
++
++
++
++
++
++в режиме прокси и FastCGI поддерживается строка заголовка "X-Accel-Charset"
++в ответе бэкенда.
++
++
++the "X-Accel-Charset" response header line is supported in proxy
++and FastCGI mode.
++
++
++
++
++
++символ "\" в парах "\"" и "\'" в SSI командах убирался, только если
++также использовался символ "$".
++
++
++the "\" escape symbol in the "\"" and "\'" pairs in the SSI command
++was removed only if the command also has the "$" symbol.
++
++
++
++
++
++при некоторых условиях в SSI после вставки могла быть добавлена
++строка "<!--".
++
++
++the "<!--" string might be added on some conditions
++in the SSI after inclusion.
++
++
++
++
++
++если в заголовке ответа была строка "Content-Length: 0",
++то при использовании небуферизированного проксировании не закрывалось соединение
++с клиентом.
++
++
++if the "Content-Length: 0" header line was in response, then
++in nonbuffered proxying mode the client connection was not closed.
++
++
++
++
++
++
++
++
++
++
++в директиве set.
++
++
++in the "set" directive.
++
++
++
++
++
++при включении в ssi двух и более подзапросов, обрабатываемых через FastCGI,
++вместо вывода второго и остальных подзапросов в ответ включался вывод
++первого подзапроса.
++
++
++if two or more FastCGI subrequests was in SSI, then first subrequest output
++was included instead of second and following subrequests.
++
++
++
++
++
++
++
++
++
++
++теперь модуль ngx_http_charset_module работает для подзапросов,
++в ответах которых нет строки заголовка "Content-Type".
++
++
++now the ngx_http_charset_module works for subrequests,
++if the response has no "Content-Type" header line.
++
++
++
++
++
++если в директиве proxy_pass не было URI,
++то директива "proxy_redirect default" добавляла в переписанный
++редирект в начало лишний слэш.
++
++
++if the "proxy_pass" directive has no URI part,
++then the "proxy_redirect default" directive add the unnecessary slash
++in start of the rewritten redirect.
++
++
++
++
++
++внутренний редирект всегда превращал любой HTTP-метод в GET,
++теперь это делается только для редиректов, выполняемых с помощью
++X-Accel-Redirect, и у которых метод не равен HEAD;
++ошибка появилась в 0.3.42.
++
++
++the internal redirect always transform client's HTTP method to GET,
++now the transformation is made for the "X-Accel-Redirect" redirects only
++and if the method is not HEAD;
++the bug had appeared in 0.3.42.
++
++
++
++
++
++модуль ngx_http_perl_module не собирался, если перл был с поддержкой потоков;
++ошибка появилась в 0.3.46.
++
++
++the ngx_http_perl_module could not be built, if the perl was built
++with the threads support;
++the bug had appeared in 0.3.46.
++
++
++
++
++
++
++
++
++
++
++директива upstream.
++
++
++the "upstream" directive.
++
++
++
++
++
++символ "\" в парах "\"" и "\'" в SSI командах теперь всегда убирается.
++
++
++now the "\" escape symbol in the "\"" and "\'" pairs in the SSI command
++is always removed.
++
++
++
++
++
++
++
++
++
++
++директивы proxy_hide_header, proxy_pass_header, fastcgi_hide_header
++и fastcgi_pass_header.
++
++
++the "proxy_hide_header", "proxy_pass_header", "fastcgi_hide_header",
++and "fastcgi_pass_header" directives.
++
++
++
++
++
++директивы proxy_pass_x_powered_by, fastcgi_x_powered_by и proxy_pass_server
++упразднены.
++
++
++the "proxy_pass_x_powered_by", "fastcgi_x_powered_by", and "proxy_pass_server"
++directives were canceled.
++
++
++
++
++
++в режиме прокси поддерживается строка заголовка "X-Accel-Buffering"
++в ответе бэкенда.
++
++
++the "X-Accel-Buffering" response header line is supported in proxy mode.
++
++
++
++
++
++ошибок и утечек памяти при переконфигурации в модуле ngx_http_perl_module.
++
++
++the reconfiguration bug and memory leaks in the ngx_http_perl_module.
++
++
++
++
++
++
++
++
++
++
++директивы ssl_verify_client, ssl_verify_depth и ssl_client_certificate.
++
++
++the "ssl_verify_client", "ssl_verify_depth", and "ssl_client_certificate"
++directives.
++
++
++
++
++
++теперь переменная $request_method возвращает метод только основного запроса.
++
++
++the $request_method variable now returns the main request method.
++
++
++
++
++
++в таблице перекодировки koi-win изменены коды символа °.
++
++
++the ° symbol codes were changed in koi-win conversion table.
++
++
++
++
++
++в таблицу перекодировки koi-win добавлены символы евро и номера.
++
++
++the euro and N symbols were added to koi-win conversion table.
++
++
++
++
++
++если nginx распределял запросы на несколько машин, то при падении
++одной из них запросы, предназначенные для этой машины, перенаправлялись только
++на одну машину вместо того, чтобы равномерно распределяться между остальными.
++
++
++if nginx distributed the requests among several backends and some backend
++failed, then requests intended for this backend was directed to one live
++backend only instead of being distributed among the rest.
++
++
++
++
++
++
++
++
++
++
++параметр wait в команде SSI include.
++
++
++the "wait" parameter in the "include" SSI command.
++
++
++
++
++
++в таблицу перекодировки koi-win добавлены украинские и белорусские символы.
++
++
++the Ukrainian and Byelorussian characters were added to koi-win conversion
++table.
++
++
++
++
++
++в SSI.
++
++
++in the SSI.
++
++
++
++
++
++
++
++
++
++
++в SSI.
++
++
++in the SSI.
++
++
++
++
++
++
++
++
++
++
++параметр bind в директиве listen в IMAP/POP3 прокси.
++
++
++the "bind" option of the "listen" directive in IMAP/POP3 proxy.
++
++
++
++
++
++ошибки при использовании в директиве rewrite одного и того же
++выделения более одного раза.
++
++
++if the same capture in the "rewrite" directive was used more then once.
++
++
++
++
++
++в лог не записывались переменные
++$sent_http_content_type, $sent_http_content_length, $sent_http_last_modified,
++$sent_http_connection, $sent_http_keep_alive и $sent_http_transfer_encoding.
++
++
++the $sent_http_content_type, $sent_http_content_length,
++$sent_http_last_modified, $sent_http_connection, $sent_http_keep_alive,
++and $sent_http_transfer_encoding variables were not written to access log.
++
++
++
++
++
++переменная $sent_http_cache_control возвращала содержимое только одной
++строки "Cache-Control" в заголовке ответа.
++
++
++the $sent_http_cache_control returned value of the single "Cache-Control"
++response header line.
++
++
++
++
++
++
++
++
++
++
++ключ -v.
++
++
++the -v switch.
++
++
++
++
++
++при включении в SSI удалённых подзапросов
++мог произойти segmentation fault.
++
++
++the segmentation fault may occurred if the SSI page has remote subrequests.
++
++
++
++
++
++в обработке FastCGI.
++
++
++in FastCGI handling.
++
++
++
++
++
++если путь к перловым модулям не был указан с помощью
++--with-perl_modules_path=PATH или директивы perl_modules,
++то на старте происходил segmentation fault.
++
++
++if the perl modules path was not set using
++--with-perl_modules_path=PATH or the "perl_modules", then
++the segmentation fault was occurred.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_dav_module поддерживает метод MKCOL.
++
++
++the ngx_http_dav_module supports the MKCOL method.
++
++
++
++
++
++директива create_full_put_path.
++
++
++the "create_full_put_path" directive.
++
++
++
++
++
++переменная $limit_rate.
++
++
++the "$limit_rate" variable.
++
++
++
++
++
++
++
++
++
++
++директива uninitialized_variable_warn; уровень логгирования сообщения
++о неинициализированной переменной понижен с уровня alert на warn.
++
++
++the "uninitialized_variable_warn" directive; the logging level of the
++"uninitialized variable" message was lowered from "alert" to "warn".
++
++
++
++
++
++директива override_charset.
++
++
++the "override_charset" directive.
++
++
++
++
++
++при использовании неизвестной переменной в SSI-командах echo и if expr='$name'
++теперь не записывается в лог сообщение о неизвестной переменной.
++
++
++now if the unknown variable is used in the "echo" and "if expr='$name'"
++SSI-commands, then the "unknown variable" message is not logged.
++
++
++
++
++
++счётчик активных соединений рос при превышении лимита соединений,
++заданного директивой worker_connections;
++ошибка появилась в 0.2.0.
++
++
++the active connection counter increased on the exceeding of the connection
++limit specified by the "worker_connections" directive;
++the bug had appeared in 0.2.0.
++
++
++
++
++
++при некоторых условия ограничение скорости соединения могло не работать;
++ошибка появилась в 0.3.38.
++
++
++the limit rate might not work on some condition;
++the bug had appeared in 0.3.38.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_dav_module.
++
++
++the ngx_http_dav_module.
++
++
++
++
++
++оптимизация модуля ngx_http_perl_module.
++Спасибо Сергею Скворцову.
++
++
++the ngx_http_perl_module optimizations.
++Thanks to Sergey Skvortsov.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает метод $r->request_body_file.
++
++
++the ngx_http_perl_module supports the $r->request_body_file method.
++
++
++
++
++
++директива client_body_in_file_only.
++
++
++the "client_body_in_file_only" directive.
++
++
++
++
++
++теперь при переполнении диска nginx пытается писать access_log'и только
++раз в секунду.
++Спасибо Антону Южанинову и Максиму Дунину.
++
++
++now on disk overflow nginx tries to write access logs once a second only.
++Thanks to Anton Yuzhaninov and Maxim Dounin.
++
++
++
++
++
++теперь директива limit_rate точнее ограничивает скорость при значениях
++больше 100 Kbyte/s.
++Спасибо ForJest.
++
++
++now the "limit_rate" directive more precisely limits rate if rate is more
++than 100 Kbyte/s.
++Thanks to ForJest.
++
++
++
++
++
++IMAP/POP3 прокси теперь передаёт серверу авторизации символы "\r" и "\n"
++в логине и пароле в закодированном виде.
++Спасибо Максиму Дунину.
++
++
++now the IMAP/POP3 proxy escapes the "\r" and "\n" symbols in login and
++password to pass authorization server.
++Thanks to Maxim Dounin.
++
++
++
++
++
++
++
++
++
++
++директива limit_except.
++
++
++the "limit_except" directive.
++
++
++
++
++
++директива if поддерживает операторы "!~", "!~*", "-f" и "!-f".
++
++
++the "if" directive supports the "!~", "!~*", "-f", and "!-f" operators.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает метод $r->request_body.
++
++
++the ngx_http_perl_module supports the $r->request_body method.
++
++
++
++
++
++в модуле ngx_http_addition_filter_module.
++
++
++in the ngx_http_addition_filter_module.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_addition_filter_module.
++
++
++the ngx_http_addition_filter_module.
++
++
++
++
++
++директивы proxy_pass и fastcgi_pass можно использовать внутри блока if.
++
++
++the "proxy_pass" and "fastcgi_pass" directives may be used inside
++the "if" block.
++
++
++
++
++
++директивы proxy_ignore_client_abort и fastcgi_ignore_client_abort.
++
++
++the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives.
++
++
++
++
++
++переменная $request_completion.
++
++
++the "$request_completion" variable.
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает методы $r->request_method и
++$r->remote_addr.
++
++
++the ngx_http_perl_module supports the $r->request_method and $r->remote_addr.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает команду elif.
++
++
++the ngx_http_ssi_module supports the "elif" command.
++
++
++
++
++
++строка "\/" в начале выражения команды if модуля ngx_http_ssi_module
++воспринималась неверно.
++
++
++the "\/" string in the expression of the "if" command of the
++ngx_http_ssi_module was treated incorrectly.
++
++
++
++
++
++в использовании регулярных выражениях в команде if модуля ngx_http_ssi_module.
++
++
++in the regular expressions in the "if" command of the ngx_http_ssi_module.
++
++
++
++
++
++при задании относительного пути в директивах
++client_body_temp_path, proxy_temp_path, fastcgi_temp_path и perl_modules
++использовался каталог относительно текущего каталога, а не относительно
++префикса сервера.
++
++
++if the relative path was specified in the "client_body_temp_path",
++"proxy_temp_path", "fastcgi_temp_path", and "perl_modules" directives,
++then the directory was used relatively to a current path but not
++to a server prefix.
++
++
++
++
++
++
++
++
++
++
++accept-фильтр и TCP_DEFER_ACCEPT устанавливались только для первой
++директивы listen;
++ошибка появилась в 0.3.31.
++
++
++the accept-filter and the TCP_DEFER_ACCEPT option were set for first "listen"
++directive only;
++the bug had appeared in 0.3.31.
++
++
++
++
++
++в директиве proxy_pass без URI при использовании в подзапросе.
++
++
++in the "proxy_pass" directive without the URI part in a subrequest.
++
++
++
++
++
++
++
++
++
++
++директива add_header поддерживает переменные.
++
++
++the "add_header" directive supports the variables.
++
++
++
++
++
++
++
++
++
++
++параметр http_503 в директивах proxy_next_upstream или fastcgi_next_upstream.
++
++
++the "http_503" parameter of the "proxy_next_upstream" or
++"fastcgi_next_upstream" directives.
++
++
++
++
++
++ngx_http_perl_module не работал со встроенным в конфигурационный файл кодом,
++если он не начинался сразу же с "sub".
++
++
++ngx_http_perl_module did not work with inlined in the configuration code,
++if it was not started with the "sub" word.
++
++
++
++
++
++в директиве post_action.
++
++
++in the "post_action" directive.
++
++
++
++
++
++
++
++
++
++
++удаление отладочного логгирования на старте и при переконфигурации;
++ошибка появилась в 0.3.31.
++
++
++the debug logging on startup and reconfiguration time was removed;
++the bug had appeared in 0.3.31.
++
++
++
++
++
++
++
++
++
++
++теперь nginx передаёт неверные ответы проксированного бэкенда.
++
++
++now nginx passes the malformed proxied backend responses.
++
++
++
++
++
++директивы listen поддерживают адрес в виде "*:порт".
++
++
++the "listen" directives support the address in the "*:port" form.
++
++
++
++
++
++поддержка EVFILER_TIMER в MacOSX 10.4.
++
++
++the EVFILER_TIMER support in MacOSX 10.4.
++
++
++
++
++
++обход ошибки обработки миллисекундных таймаутов kqueue в 64-битном ядре
++MacOSX.
++Спасибо Андрею Нигматулину.
++
++
++for MacOSX 64-bit kernel kqueue millisecond timeout bug.
++Thanks to Andrei Nigmatulin.
++
++
++
++
++
++если внутри одного сервера описаны несколько директив listen, слушающих на
++разных адресах, то имена серверов вида "*.domain.tld" работали только
++для первого адреса;
++ошибка появилась в 0.3.18.
++
++
++if there were several "listen" directives listening one various addresses
++inside one server, then server names like "*.domain.tld" worked for first
++address only;
++the bug had appeared in 0.3.18.
++
++
++
++
++
++при использовании протокола HTTPS в директиве proxy_pass не передавались
++запросы с телом, записанным во временный файл.
++
++
++if the HTTPS protocol was used in the "proxy_pass" directive and
++the request body was in temporary file then the request was not transferred.
++
++
++
++
++
++совместимость с perl 5.8.8.
++
++
++perl 5.8.8 compatibility.
++
++
++
++
++
++
++
++
++
++
++уровень записи в лог ошибки ECONNABORTED изменён на error с уровня crit.
++
++
++the ECONNABORTED error log level was changed to "error" from "crit".
++
++
++
++
++
++модуль ngx_http_perl_module не собирался без модуля ngx_http_ssi_filter_module.
++
++
++the ngx_http_perl_module could not be build without
++the ngx_http_ssi_filter_module.
++
++
++
++
++
++nginx не собирался на i386 платформе, если использовался PIC;
++ошибка появилась в 0.3.27.
++
++
++nginx could not be built on i386 platform, if the PIC was used;
++the bug had appeared in 0.3.27.
++
++
++
++
++
++
++
++
++
++
++теперь nginx использует меньше памяти, если PHP в режиме FastCGI передаёт
++большое количество предупреждений перед ответом.
++
++
++now nginx uses less memory, if PHP in FastCGI mode sends many warnings
++before the response.
++
++
++
++
++
++в ответах 204 для запросов версии HTTP/1.1 выдавалась строка заголовка
++"Transfer-Encoding: chunked".
++
++
++the "Transfer-Encoding: chunked" header line was issued in the 204 responses
++for the HTTP/1.1 requests.
++
++
++
++
++
++nginx возвращал 502 код ответа, если FastCGI сервер передавал полные строки
++заголовка ответа в отдельных FastCGI записях.
++
++
++nginx returned the 502 response, if the complete response header lines
++were transferred in a separate FastCGI records.
++
++
++
++
++
++если в директиве post_action был указан проксируемый URI, то он выполнялся
++только после успешного завершения запроса.
++
++
++if the proxied URI was specified in the "post_action" directive, then it ran
++only after a successful completion of a request.
++
++
++
++
++
++
++
++
++
++
++директива restrict_host_names упразднена.
++
++
++the "restrict_host_names" directive was canceled.
++
++
++
++
++
++параметр конфигурации --with-cpu-opt=ppc64.
++
++
++the --with-cpu-opt=ppc64 configuration parameter.
++
++
++
++
++
++при некоторых условиях проксированное соединение с клиентом завершалось
++преждевременно.
++Спасибо Владимиру Шутову.
++
++
++on some condition the proxied connection with a client was terminated
++prematurely.
++Thanks to Vladimir Shutoff.
++
++
++
++
++
++строка заголовка "X-Accel-Limit-Rate" не учитывалась для запросов,
++перенаправленных с помощью строки "X-Accel-Redirect".
++
++
++the "X-Accel-Limit-Rate" header line was not taken into account
++if the request was redirected using the "X-Accel-Redirect" header line.
++
++
++
++
++
++директива post_action работала только после успешного завершения запроса.
++
++
++the "post_action" directive ran only after a successful completion of a request.
++
++
++
++
++
++тело проксированного ответа, создаваемого директивой post_action,
++передавалось клиенту.
++
++
++the proxied response body generated by the "post_action" directive
++was transferred to a client.
++
++
++
++
++
++
++
++
++
++
++директивы variables_hash_max_size и variables_hash_bucket_size.
++
++
++the "variables_hash_max_size" and "variables_hash_bucket_size" directives.
++
++
++
++
++
++переменная $body_bytes_sent доступна не только в директиве log_format.
++
++
++the $body_bytes_sent variable can be used not only in the "log_format"
++directive.
++
++
++
++
++
++переменные $ssl_protocol и $ssl_cipher.
++
++
++the $ssl_protocol and $ssl_cipher variables.
++
++
++
++
++
++определение размера строки кэша распространённых процессоров при старте.
++
++
++the cache line size detection for widespread CPUs at start time.
++
++
++
++
++
++директива accept_mutex теперь поддерживается посредством fcntl(2)
++на платформах, отличных от i386, amd64, sparc64 и ppc.
++
++
++now the "accept_mutex" directive is supported using fcntl(2)
++on platforms different from i386, amd64, sparc64, and ppc.
++
++
++
++
++
++директива lock_file и параметр автоконфигурации --with-lock-path=PATH.
++
++
++the "lock_file" directive and the --with-lock-path=PATH autoconfiguration
++directive.
++
++
++
++
++
++при использовании протокола HTTPS в директиве proxy_pass не передавались
++запросы с телом.
++
++
++if the HTTPS protocol was used in the "proxy_pass" directive then
++the requests with the body was not transferred.
++
++
++
++
++
++
++
++
++
++
++директива optimize_host_names переименована в optimize_server_names.
++
++
++the "optimize_host_names" directive was renamed to the "optimize_server_names".
++
++
++
++
++
++при проксировании подзапроса в SSI бэкенду передавался URI основного запроса,
++если в директиве proxy_pass отсутствовал URI.
++
++
++if in the "proxy_pass" directive was no the URI part, then the main request
++URI was transferred to a backend while proxying the SSI subrequest.
++
++
++
++
++
++
++
++
++
++
++при неверной конфигурации на старте или во время переконфигурации происходил
++segmentation fault;
++ошибка появилась в 0.3.24.
++
++
++the segmentation fault was occurred on start or while reconfiguration
++if there was invalid configuration;
++the bug had appeared in 0.3.24.
++
++
++
++
++
++
++
++
++
++
++обход ошибки в kqueue во FreeBSD.
++
++
++for bug in FreeBSD kqueue.
++
++
++
++
++
++ответ, создаваемый директивой post_action, теперь не передаётся клиенту.
++
++
++now a response generated by the "post_action" directive is not transferred
++to a client.
++
++
++
++
++
++при использовании большого количества лог-файлов происходила утечка памяти.
++
++
++the memory leaks were occurring if many log files were used.
++
++
++
++
++
++внутри одного location работала только первая директива proxy_redirect.
++
++
++the first "proxy_redirect" directive was working inside one location.
++
++
++
++
++
++на 64-битных платформах при старте мог произойти segmentation fault,
++если использовалось большое количество имён в директивах server_name;
++ошибка появилась в 0.3.18.
++
++
++on 64-bit platforms segmentation fault may occurred on start
++if the many names were used in the "server_name" directives;
++the bug had appeared in 0.3.18.
++
++
++
++
++
++
++
++
++
++
++директива optimize_host_names.
++
++
++the "optimize_host_names" directive.
++
++
++
++
++
++ошибки при использовании переменных в директивах path и alias.
++
++
++in using of the variables in the "path" and "alias" directives.
++
++
++
++
++
++модуль ngx_http_perl_module неправильно собирался на Linux и Solaris.
++
++
++the ngx_http_perl_module was incorrectly built on Linux and Solaris.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_perl_module поддерживает методы $r->args и $r->unescape.
++
++
++the ngx_http_perl_module supports the $r->args and $r->unescape methods.
++
++
++
++
++
++метод $r->query_string в модуле ngx_http_perl_module упразднён.
++
++
++the method $r->query_string of ngx_http_perl_module was canceled.
++
++
++
++
++
++если в директиве valid_referers указаны только none или blocked, то
++происходил segmentation fault;
++ошибка появилась в 0.3.18.
++
++
++segmentation fault was occurred if the "none" or "blocked" values was
++specified in the "valid_referers" directive;
++the bug had appeared in 0.3.18.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_perl_module.
++
++
++the ngx_http_perl_module.
++
++
++
++
++
++директива valid_referers разрешает использовать рефереры совсем без URI.
++
++
++the "valid_referers" directive allows the referrers without URI part.
++
++
++
++
++
++
++
++
++
++
++ошибки в обработке SSI.
++
++
++in SSI handling.
++
++
++
++
++
++модуль ngx_http_memcached_module не поддерживал ключи в виде /uri?args.
++
++
++the ngx_http_memcached_module did not support the keys in the "/usr?args" form.
++
++
++
++
++
++
++
++
++
++директивы path и alias поддерживают переменные.
++
++
++the "path" and "alias" directives support the variables.
++
++
++
++
++
++теперь директива valid_referers опять учитывает URI.
++
++
++now the "valid_referers" directive again checks the URI part.
++
++
++
++
++
++ошибки в обработке SSI.
++
++
++in SSI handling.
++
++
++
++
++
++
++
++
++
++
++директива server_names поддерживает имена вида ".domain.tld".
++
++
++the "server_names" directive supports the ".domain.tld" names.
++
++
++
++
++
++директива server_names использует хэш для имён вида "*.domain.tld"
++и более эффективный хэш для обычных имён.
++
++
++the "server_names" directive uses the hash for the "*.domain.tld" names
++and more effective hash for usual names.
++
++
++
++
++
++директивы server_names_hash_max_size и server_names_hash_bucket_size.
++
++
++the "server_names_hash_max_size" and "server_names_hash_bucket_size" directives.
++
++
++
++
++
++директивы server_names_hash и server_names_hash_threshold упразднены.
++
++
++the "server_names_hash" and "server_names_hash_threshold" directives
++were canceled.
++
++
++
++
++
++директива valid_referers использует хэш для имён сайтов.
++
++
++the "valid_referers" directive uses the hash site names.
++
++
++
++
++
++теперь директива valid_referers проверяет только имена сайтов без учёта URI.
++
++
++now the "valid_referers" directive checks the site names only without
++the URI part.
++
++
++
++
++
++некоторые имена вида ".domain.tld" неверно обрабатывались модулем
++ngx_http_map_module.
++
++
++some ".domain.tld" names incorrectly processed by the ngx_http_map_module.
++
++
++
++
++
++если конфигурационного файла не было, то происходил segmentation fault;
++ошибка появилась в 0.3.12.
++
++
++segmentation fault was occurred if configuration file did not exist;
++the bug had appeared in 0.3.12.
++
++
++
++
++
++на 64-битных платформах при старте мог произойти segmentation fault;
++ошибка появилась в 0.3.16.
++
++
++on 64-bit platforms segmentation fault may occurred on start;
++the bug had appeared in 0.3.16.
++
++
++
++
++
++
++
++
++
++
++на Linux configure теперь проверяет наличие epoll и sendfile64() в ядре.
++
++
++now on Linux configure checks the presence of epoll and sendfile64() in kernel.
++
++
++
++
++
++директива map поддерживает доменные имена в формате ".domain.tld".
++
++
++the "map" directive supports domain names in the ".domain.tld" form.
++
++
++
++
++
++во время SSL handshake не иcпользовались таймауты;
++ошибка появилась в 0.2.4.
++
++
++the timeouts were not used in SSL handshake;
++the bug had appeared in 0.2.4.
++
++
++
++
++
++в использовании протокола HTTPS в директиве proxy_pass.
++
++
++in the HTTPS protocol in the "proxy_pass" directive.
++
++
++
++
++
++при использовании протокола HTTPS в директиве proxy_pass по умолчанию
++использовался порт 80.
++
++
++when the HTTPS protocol was used in the "proxy_pass" directive the port 80
++was used by default.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_map_module.
++
++
++the ngx_http_map_module.
++
++
++
++
++
++директивы types_hash_max_size и types_hash_bucket_size.
++
++
++the "types_hash_max_size" and "types_hash_bucket_size" directives.
++
++
++
++
++
++директива ssi_value_length.
++
++
++the "ssi_value_length" directive.
++
++
++
++
++
++директива worker_rlimit_core.
++
++
++the "worker_rlimit_core" directive.
++
++
++
++
++
++при сборке компиляторами icc 8.1 и 9.0 с оптимизацией для
++Pentium 4 номер соединения в логах всегда был равен 1.
++
++
++the connection number in logs was always 1 if nginx was built by the
++icc 8.1 or 9.0 compilers with optimization for Pentium 4.
++
++
++
++
++
++команда config timefmt в SSI задавала неверный формат времени.
++
++
++the "config timefmt" SSI command set incorrect time format.
++
++
++
++
++
++nginx не закрывал соединения с IMAP/POP3 бэкендом при использовании SSL
++соединений;
++ошибка появилась в 0.3.13.
++Спасибо Rob Mueller.
++
++
++nginx did not close connection to IMAP/POP3 backend for the SSL
++connections;
++the bug had appeared in 0.3.13.
++Thanks to Rob Mueller.
++
++
++
++
++
++segmentation fault мог произойти во время SSL shutdown;
++ошибка появилась в 0.3.13.
++
++
++segmentation fault may occurred in at SSL shutdown;
++the bug had appeared in 0.3.13.
++
++
++
++
++
++
++
++
++
++
++новой код 444 в директиве return для закрытия соединения.
++
++
++the new 444 code of the "return" directive to close connection.
++
++
++
++
++
++директива so_keepalive в IMAP/POP3 прокси.
++
++
++the "so_keepalive" directive in IMAP/POP3 proxy.
++
++
++
++
++
++nginx теперь вызывает abort() при обнаружении незакрытых соединений
++только при плавном выходе и включённой директиве debug_points.
++
++
++if there are unclosed connection nginx now calls abort() only on graceful
++quit and active "debug_points" directive.
++
++
++
++
++
++
++
++
++
++
++в ответе 304 передавалось тело ответа;
++ошибка появилась в 0.3.13.
++
++
++in the 304 response the body was transferred;
++the bug had appeared in 0.3.13.
++
++
++
++
++
++
++
++
++
++
++IMAP/POP3 прокси поддерживает STARTTLS и STLS.
++
++
++the IMAP/POP3 proxy supports STARTTLS and STLS.
++
++
++
++
++
++IMAP/POP3 прокси не работала с методами select, poll и /dev/poll.
++
++
++the IMAP/POP3 proxy did not work with the select, poll, and /dev/poll methods.
++
++
++
++
++
++ошибки в обработке SSI.
++
++
++in SSI handling.
++
++
++
++
++
++sendfilev() в Solaris теперь не используется при передаче тела запроса
++FastCGI-серверу через unix domain сокет.
++
++
++now Solaris sendfilev() is not used to transfer the client request body
++to FastCGI-server via the unix domain socket.
++
++
++
++
++
++директива auth_basic не запрещала аутентификацию;
++ошибка появилась в 0.3.11.
++
++
++the "auth_basic" directive did not disable the authorization;
++the bug had appeared in 0.3.11.
++
++
++
++
++
++
++
++
++
++
++если nginx был собран с модулем ngx_http_realip_module, то при использовании
++директивы "satisfy_any on" директивы доступа и аутентификации не работали.
++Модуль ngx_http_realip_module не собирался и не собирается по умолчанию.
++
++
++if nginx was built with the ngx_http_realip_module and the "satisfy_any on"
++directive was used, then access and authorization directives did not work.
++The ngx_http_realip_module was not built and is not built by default.
++
++
++
++
++
++имя переменной "$time_gmt" изменено на "$time_local".
++
++
++the "$time_gmt" variable name was changed to "$time_local".
++
++
++
++
++
++директивы proxy_header_buffer_size и fastcgi_header_buffer_size
++переименованы соответственно в proxy_buffer_size и fastcgi_buffer_size.
++
++
++the "proxy_header_buffer_size" and "fastcgi_header_buffer_size" directives
++was renamed to the "proxy_buffer_size" and "fastcgi_buffer_size" directives.
++
++
++
++
++
++модуль ngx_http_memcached_module.
++
++
++the ngx_http_memcached_module.
++
++
++
++
++
++директива proxy_buffering.
++
++
++the "proxy_buffering" directive.
++
++
++
++
++
++изменение в работе с accept mutex при использовании метода rtsig;
++ошибка появилась в 0.3.0.
++
++
++the changes in accept mutex handling when the "rtsig" method was used;
++the bug had appeared in 0.3.0.
++
++
++
++
++
++если клиент передал строку "Transfer-Encoding: chunked" в заголовке
++запроса, то nginx теперь выдаёт ошибку 411.
++
++
++if the client sent the "Transfer-Encoding: chunked" header line, then
++nginx returns the 411 error.
++
++
++
++
++
++при наследовании директивы auth_basic с уровня http в строке
++"WWW-Authenticate" заголовка ответа выводился realm без текста "Basic realm".
++
++
++if the "auth_basic" directive was inherited from the http level,
++then the realm in the "WWW-Authenticate" header line was without
++the "Basic realm" text.
++
++
++
++
++
++если в директиве access_log был явно указан формат combined, то в лог
++записывались пустые строки;
++ошибка появилась в 0.3.8.
++
++
++if the "combined" format was explicitly specified in the "access_log" directive,
++then the empty lines was written to the log;
++the bug had appeared in 0.3.8.
++
++
++
++
++
++nginx не работал на платформе sparc под любыми OS, кроме Solaris.
++
++
++nginx did not run on the sparc platform under any OS except Solaris.
++
++
++
++
++
++в директиве if теперь не нужно разделять пробелом строку в кавычках и
++закрывающую скобку.
++
++
++now it is not necessary to place space between the quoted string and closing
++bracket in the "if" directive.
++
++
++
++
++
++
++
++
++
++
++nginx не передавал при проксировании тело запроса и строки заголовка клиента;
++ошибка появилась в 0.3.10.
++
++
++nginx did not pass the client request headers and body while proxying;
++the bug had appeared in 0.3.10.
++
++
++
++
++
++
++
++
++
++
++директива valid_referers и переменная $invalid_referer перенесены
++из модуля ngx_http_rewrite_module в новый модуль ngx_http_referer_module.
++
++
++the "valid_referers" directive and the "$invalid_referer" variable
++were moved to the new ngx_http_referer_module from the ngx_http_rewrite_module.
++
++
++
++
++
++имя переменной "$apache_bytes_sent" изменено на "$body_bytes_sent".
++
++
++the "$apache_bytes_sent" variable name was changed to "$body_bytes_sent".
++
++
++
++
++
++переменные "$sent_http_...".
++
++
++the "$sent_http_..." variables.
++
++
++
++
++
++директива if поддерживает операции "=" и "!=".
++
++
++the "if" directive supports the "=" and "!=" operations.
++
++
++
++
++
++директива proxy_pass поддерживает протокол HTTPS.
++
++
++the "proxy_pass" directive supports the HTTPS protocol.
++
++
++
++
++
++директива proxy_set_body.
++
++
++the "proxy_set_body" directive.
++
++
++
++
++
++директива post_action.
++
++
++the "post_action" directive.
++
++
++
++
++
++модуль ngx_http_empty_gif_module.
++
++
++the ngx_http_empty_gif_module.
++
++
++
++
++
++директива worker_cpu_affinity для Linux.
++
++
++the "worker_cpu_affinity" directive for Linux.
++
++
++
++
++
++директива rewrite не раскодировала символы в редиректах в URI,
++теперь символы раскодируются, кроме символов %00-%25 и %7F-%FF.
++
++
++the "rewrite" directive did not unescape URI part in redirect,
++now it is unescaped except the %00-%25 and %7F-%FF characters.
++
++
++
++
++
++nginx не собирался компилятором icc 9.0.
++
++
++nginx could not be built by the icc 9.0 compiler.
++
++
++
++
++
++если для статического файла нулевого размера был разрешён SSI,
++то ответ передавался неверно при кодировании chunk'ами.
++
++
++if the SSI was enabled for zero size static file, then the chunked
++response was encoded incorrectly.
++
++
++
++
++
++
++
++
++
++
++nginx считал небезопасными URI, в которых между двумя слэшами
++находилось два любых символа;
++ошибка появилась в 0.3.8.
++
++
++nginx considered URI as unsafe if two any symbols was between two slashes;
++the bug had appeared in 0.3.8.
++
++
++
++
++
++
++
++
++
++
++nginx теперь проверят URI, полученные от бэкенда в строке "X-Accel-Redirect"
++в заголовке ответа, или в SSI файле на наличие путей "/../" и нулей.
++
++
++nginx now checks URI got from a backend in "X-Accel-Redirect" header line
++or in SSI file for the "/../" paths and zeroes.
++
++
++
++
++
++nginx теперь не воспринимает пустое имя как правильное
++в строке "Authorization" в заголовке запроса.
++
++
++nginx now does not treat the empty user name in the "Authorization" header
++line as valid one.
++
++
++
++
++
++директива ssl_session_timeout модулей
++ngx_http_ssl_module и ngx_imap_ssl_module.
++
++
++the "ssl_session_timeout" directives
++of the ngx_http_ssl_module and ngx_imap_ssl_module.
++
++
++
++
++
++директива auth_http_header модуля ngx_imap_auth_http_module.
++
++
++the "auth_http_header" directive of the ngx_imap_auth_http_module.
++
++
++
++
++
++директива add_header.
++
++
++the "add_header" directive.
++
++
++
++
++
++модуль ngx_http_realip_module.
++
++
++the ngx_http_realip_module.
++
++
++
++
++
++новые переменные для использования в директиве log_format:
++$bytes_sent, $apache_bytes_sent, $status, $time_gmt,
++$uri, $request_time, $request_length,
++$upstream_status, $upstream_response_time,
++$gzip_ratio,
++$uid_got, $uid_set,
++$connection, $pipe и $msec.
++Параметры в виде "%name" скоро будут упразднены.
++
++
++the new variables to use in the "log_format" directive:
++$bytes_sent, $apache_bytes_sent, $status, $time_gmt,
++$uri, $request_time, $request_length,
++$upstream_status, $upstream_response_time,
++$gzip_ratio,
++$uid_got, $uid_set,
++$connection, $pipe, and $msec.
++The parameters in the "%name" form will be canceled soon.
++
++
++
++
++
++в директиве "if" ложными значениями переменных теперь являются
++пустая строка "" и строки, начинающиеся на "0".
++
++
++now the false variable values in the "if" directive are the empty string ""
++and string starting with "0".
++
++
++
++
++
++при работает с проксированными или FastCGI-серверами nginx мог оставлять
++открытыми соединения и временные файлы с запросами клиентов.
++
++
++while using proxied or FastCGI-server nginx may leave connections
++and temporary files with client requests in open state.
++
++
++
++
++
++рабочие процессы не сбрасывали буферизированные логи при плавном выходе.
++
++
++the worker processes did not flush the buffered logs on graceful exit.
++
++
++
++
++
++если URI запроса изменялось с помощью rewrite, а затем запрос проксировался
++в location, заданном регулярным выражением, то бэкенду передавался
++неверный запрос;
++ошибка появилась в 0.2.6.
++
++
++if the request URI was changes by the "rewrite" directive and the request
++was proxied in location given by regular expression, then the incorrect
++request was transferred to backend;
++the bug had appeared in 0.2.6.
++
++
++
++
++
++директива expires не удаляла уже установленную строку заголовка "Expires".
++
++
++the "expires" directive did not remove the previous "Expires" header.
++
++
++
++
++
++при использовании метода rtsig и нескольких рабочих процессах nginx
++мог перестать принимать запросы.
++
++
++nginx may stop to accept requests if the "rtsig" method and several worker
++processes were used.
++
++
++
++
++
++в SSI командах неверно обрабатывались строки "\"" и "\'".
++
++
++the "\"" and "\'" escape symbols were incorrectly handled in SSI commands.
++
++
++
++
++
++если ответ заканчивался сразу же после SSI команды, то при использовании
++сжатия ответ передавался не до конца или не передавался вообще.
++
++
++if the response was ended just after the SSI command and gzipping was used,
++then the response did not transferred complete or did not transferred at all.
++
++
++
++
++
++
++
++
++
++
++директива access_log поддерживает параметр buffer=.
++
++
++the "access_log" supports the "buffer=" parameter.
++
++
++
++
++
++nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
++ошибка появилась в 0.3.2.
++
++
++nginx could not be built on platforms different from i386, amd64, sparc,
++and ppc;
++the bug had appeared in 0.3.2.
++
++
++
++
++
++
++
++
++
++
++IMAP/POP3 прокси теперь не передаёт серверу авторизации пустой логин.
++
++
++now the IMAP/POP3 proxy do not send the empty login to authorization server.
++
++
++
++
++
++директива log_format поддерживает переменные в виде $name.
++
++
++the "log_format" supports the variables in the $name form.
++
++
++
++
++
++если хотя бы в одном сервере не было описано ни одной директивы listen, то
++nginx не слушал на 80 порту;
++ошибка появилась в 0.3.3.
++
++
++if at least in one server was no the "listen" directive, then nginx did not
++listen on the 80 port;
++the bug had appeared in 0.3.3.
++
++
++
++
++
++если в директиве proxy_pass отсутствовал URI, то всегда использовался порт 80.
++
++
++if the URI part is omitted in "proxy_pass" directive, the 80 port was
++always used.
++
++
++
++
++
++
++
++
++
++
++если логин IMAP/POP3 менялся сервером авторизации, то мог произойти
++segmentation fault;
++ошибка появилась в 0.2.2.
++
++
++the segmentation fault may occurred if the IMAP/POP3 login was changed
++by authorization server;
++the bug had appeared in 0.2.2.
++
++
++
++
++
++accept mutex не работал, все соединения обрабатывались одним рабочим процессом;
++ошибка появилась в 0.3.3.
++
++
++the accept mutex did not work and all connections were handled by one process;
++the bug had appeared in 0.3.3.
++
++
++
++
++
++при использовании метода rtsig и директивы timer_resolution
++не работали таймауты.
++
++
++the timeout did not work if the "rtsig" method and the "timer_resolution"
++directive were used.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался на Linux 2.4+ и MacOS X;
++ошибка появилась в 0.3.3.
++
++
++nginx could not be built on Linux 2.4+ and MacOS X;
++the bug had appeared in 0.3.3.
++
++
++
++
++
++
++
++
++
++
++параметры "bl" и "af" директивы listen переименованы в "backlog"
++и "accept_filter".
++
++
++the "bl" and "af" parameters of the "listen" directive was renamed to
++the "backlog" and "accept_filter".
++
++
++
++
++
++параметры "rcvbuf" и "sndbuf" в директиве listen.
++
++
++the "rcvbuf" and "sndbuf" parameters of the "listen" directive.
++
++
++
++
++
++параметр лога $msec теперь не требует дополнительного системного
++вызова gettimeofday().
++
++
++the "$msec" log parameter does not require now the additional
++the gettimeofday() system call.
++
++
++
++
++
++ключ -t теперь проверяет директивы listen.
++
++
++the -t switch now tests the "listen" directives.
++
++
++
++
++
++если в директиве listen был указан неверный адрес, то nginx после
++сигнала -HUP оставлял открытый сокет в состоянии CLOSED.
++
++
++if the invalid address was specified in the "listen" directive, then
++after the -HUP signal nginx left an open socket in the CLOSED state.
++
++
++
++
++
++для индексных файлов, содержащих в имени переменную, мог неверно выставляться
++тип mime по умолчанию;
++ошибка появилась в 0.3.0.
++
++
++the mime type may be incorrectly set to default value for index file with
++variable in the name;
++the bug had appeared in 0.3.0.
++
++
++
++
++
++директива timer_resolution.
++
++
++the "timer_resolution" directive.
++
++
++
++
++
++параметр лога $upstream_response_time в миллисекундах.
++
++
++the millisecond "$upstream_response_time" log parameter.
++
++
++
++
++
++временный файл с телом запроса клиента теперь удаляется сразу после того,
++как клиенту передан заголовок ответа.
++
++
++a temporary file with client request body now is removed just after
++the response header was transferred to a client.
++
++
++
++
++
++совместимость с OpenSSL 0.9.6.
++
++
++OpenSSL 0.9.6 compatibility.
++
++
++
++
++
++пути к файлам с SSL сертификатом и ключом не могли быть относительными.
++
++
++the SSL certificate and key file paths could not be relative.
++
++
++
++
++
++директива ssl_prefer_server_ciphers не работала для модуля ngx_imap_ssl_module.
++
++
++the "ssl_prefer_server_ciphers" directive did not work in
++the ngx_imap_ssl_module.
++
++
++
++
++
++директива ssl_protocols позволяла задать только один протокол.
++
++
++the "ssl_protocols" directive allowed to specify the single protocol only.
++
++
++
++
++
++
++
++
++
++
++поддержка Sun Studio 10 C compiler.
++
++
++the Sun Studio 10 C compiler support.
++
++
++
++
++
++директивы proxy_upstream_max_fails, proxy_upstream_fail_timeout,
++fastcgi_upstream_max_fails и fastcgi_upstream_fail_timeout.
++
++
++the "proxy_upstream_max_fails", "proxy_upstream_fail_timeout",
++"fastcgi_upstream_max_fails", and "fastcgi_upstream_fail_timeout"
++directives.
++
++
++
++
++
++
++
++
++
++
++во время переполнения очереди сигналов при использовании метода rtsig
++происходил segmentation fault;
++ошибка появилась в 0.2.0.
++
++
++the segmentation fault occurred when the signal queue overflowed
++if the "rtsig" method was used;
++the bug had appeared in 0.2.0.
++
++
++
++
++
++корректная обработка пар "\\", "\"", "\'" и "\$" в SSI.
++
++
++correct handling of the "\\", "\"", "\'", and "\$" pairs in SSI.
++
++
++
++
++
++
++
++
++
++
++убрано десятидневное ограничение времени работы рабочего процесса.
++Ограничение было введено из-за переполнения миллисекундных таймеров.
++
++
++the 10-days live time limit of worker process was eliminated.
++The limit was introduced because of millisecond timers overflow.
++
++
++
++
++
++
++
++
++
++
++с 60 до 10 секунд уменьшено время повторного обращения к бэкенду
++при использовании распределения нагрузки.
++
++
++while using load-balancing the time before the failed backend retry
++was decreased from 60 to 10 seconds.
++
++
++
++
++
++директива proxy_pass_unparsed_uri упразднена, оригинальный запрос теперь
++передаётся, если в директиве proxy_pass отсутствует URI.
++
++
++the "proxy_pass_unparsed_uri" was canceled, the original URI now passed,
++if the URI part is omitted in "proxy_pass" directive.
++
++
++
++
++
++директива error_page поддерживает редиректы и позволяет более гибко
++менять код ошибки.
++
++
++the "error_page" directive supports redirects and allows more flexible
++to change an error code.
++
++
++
++
++
++в проксированных подзапросах теперь игнорируется переданный charset.
++
++
++the charset in the "Content-Type" header line now is ignored
++in proxied subrequests.
++
++
++
++
++
++если после изменения URI в блоке if для запроса не находилась
++новая конфигурация, то правила модуля ngx_http_rewrite_module выполнялись
++снова.
++
++
++if the URI was changed in the "if" block and request did not found
++new configuration, then the ngx_http_rewrite_module rules ran again.
++
++
++
++
++
++если директива set устанавливала переменную модуля ngx_http_geo_module
++в какой-либо части конфигурации, то эта переменная не была доступна в
++других частях конфигурации и выдавалась ошибка "using uninitialized variable";
++ошибка появилась в 0.2.2.
++
++
++if the "set" directive set the ngx_http_geo_module variable in some
++configuration part, the this variable was not available in other
++configuration parts and the "using uninitialized variable" error was occurred;
++the bug had appeared in 0.2.2.
++
++
++
++
++
++
++
++
++
++
++дублирующее значение переменной модуля ngx_http_geo_module теперь
++выдаёт предупреждение и изменяет старое значение.
++
++
++the duplicate value of the ngx_http_geo_module variable now causes
++the warning and changes old value.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает команду set.
++
++
++the ngx_http_ssi_module supports the "set" command.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает параметр file в команде include.
++
++
++the ngx_http_ssi_module supports the "file" parameter in the "include" command.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает подстановку значений переменных
++в выражениях команды if.
++
++
++the ngx_http_ssi_module supports the variable value substitutions in
++expressions of the "if" command.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает выражения
++"$var=text", "$var!=text", "$var=/text/" и "$var!=/text/"
++в команде if.
++
++
++the ngx_http_ssi_module supports
++"$var=text", "$var!=text", "$var=/text/", and "$var!=/text/" expressions
++in the "if" command.
++
++
++
++
++
++ошибки при проксировании location без слэша в конце;
++ошибка появилась в 0.1.44.
++
++
++in proxying location without trailing slash;
++the bug had appeared in 0.1.44.
++
++
++
++
++
++при использовании метода rtsig мог произойти segmentation fault;
++ошибка появилась в 0.2.0.
++
++
++the segmentation fault may occurred if the "rtsig" method was used;
++the bug had appeared in 0.2.0.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался без параметра --with-debug;
++ошибка появилась в 0.2.2.
++
++
++nginx could not be built without the --with-debug option;
++the bug had appeared in 0.2.2.
++
++
++
++
++
++
++
++
++
++
++команда config errmsg в модуле ngx_http_ssi_module.
++
++
++the "config errmsg" command of the ngx_http_ssi_module.
++
++
++
++
++
++переменные модуля ngx_http_geo_module можно переопределять директивой set.
++
++
++the ngx_http_geo_module variables can be overridden by the "set" directive.
++
++
++
++
++
++директивы ssl_protocols и ssl_prefer_server_ciphers модулей
++ngx_http_ssl_module и ngx_imap_ssl_module.
++
++
++the "ssl_protocols" and "ssl_prefer_server_ciphers" directives
++of the ngx_http_ssl_module and ngx_imap_ssl_module.
++
++
++
++
++
++ошибка в модуле ngx_http_autoindex_module при показе длинных имён файлов;
++
++
++the ngx_http_autoindex_module did not show correctly the long file names;
++
++
++
++
++
++модуль ngx_http_autoindex_module теперь не показывает файлы,
++начинающиеся на точку.
++
++
++the ngx_http_autoindex_module now do not show the files starting by dot.
++
++
++
++
++
++если SSL handshake завершался с ошибкой, то это могло привести также
++к закрытию другого соединения.
++Спасибо Rob Mueller.
++
++
++if the SSL handshake failed then another connection may be closed too.
++Thanks to Rob Mueller.
++
++
++
++
++
++экспортные версии MSIE 5.x не могли соединиться по HTTPS.
++
++
++the export versions of MSIE 5.x could not connect via HTTPS.
++
++
++
++
++
++
++
++
++
++
++если все бэкенды, используемые для балансировки нагрузки, оказывались
++в нерабочем состоянии после одной ошибки, то nginx мог зациклится;
++ошибка появилась в 0.2.0.
++
++
++if all backend using in load-balancing failed after one error, then
++nginx may got caught in an endless loop;
++the bug had appeared in 0.2.0.
++
++
++
++
++
++
++
++
++
++
++Изменились имена pid-файлов, используемые во время обновления исполняемого
++файла. Ручное переименование теперь не нужно.
++Старый основной процесс добавляет к своему pid-файл суффикс ".oldbin"
++и запускает новый исполняемый файл.
++Новый основной процесс создаёт обычный pid-файл без суффикса ".newbin".
++Если новый основной процесс выходит, то старый процесс переименовывает свой
++pid-файл c суффиксом ".oldbin" в pid-файл без суффикса.
++При обновлении с версии 0.1.х до 0.2.0 нужно учитывать, что оба
++процесса—старый 0.1.x и новый 0.2.0—используют pid-файл
++без суффиксов.
++
++
++The pid-file names used during online upgrade was changed and now is not
++required a manual rename operation.
++The old master process adds the ".oldbin" suffix to its pid-file and
++executes a new binary file.
++The new master process creates usual pid-file without the ".newbin" suffix.
++If the master process exits, then old master process renames back
++its pid-file with the ".oldbin" suffix to the pid-file without suffix.
++
++
++
++
++
++директива worker_connections, новое название директивы connections;
++директива теперь задаёт максимальное число соединений,
++а не максимально возможный номер дескриптора для сокета.
++
++
++the "worker_connections" directive, new name of the "connections" directive;
++now the directive specifies maximum number of connections,
++but not maximum socket descriptor number.
++
++
++
++
++
++SSL поддерживает кэширование сессий в пределах одного рабочего процесса.
++
++
++SSL supports the session cache inside one worker process.
++
++
++
++
++
++директива satisfy_any.
++
++
++the "satisfy_any" directive.
++
++
++
++
++
++модули ngx_http_access_module и ngx_http_auth_basic_module не работают
++для подзапросов.
++
++
++the ngx_http_access_module and ngx_http_auth_basic_module do not run
++for subrequests.
++
++
++
++
++
++директивы worker_rlimit_nofile и worker_rlimit_sigpending.
++
++
++the "worker_rlimit_nofile" and "worker_rlimit_sigpending" directives.
++
++
++
++
++
++если все бэкенды, используемые для балансировки нагрузки, оказывались
++в нерабочем состоянии после одной ошибки, то nginx не обращался к ним
++в течение 60 секунд.
++
++
++if all backend using in load-balancing failed after one error, then
++nginx did not try do connect to them during 60 seconds.
++
++
++
++
++
++в парсинге аргументов IMAP/POP3 команд.
++Спасибо Rob Mueller.
++
++
++in IMAP/POP3 command argument parsing.
++Thanks to Rob Mueller.
++
++
++
++
++
++ошибки при использовании SSL в IMAP/POP3 прокси.
++
++
++errors while using SSL in IMAP/POP3 proxy.
++
++
++
++
++
++ошибки при использовании SSI и сжатия.
++
++
++errors while using SSI and gzipping.
++
++
++
++
++
++в ответах 304 не добавлялись строки заголовка ответа "Expires" и
++"Cache-Control".
++Спасибо Александру Кукушкину.
++
++
++the "Expires" and "Cache-Control" header lines were omitted
++from the 304 responses.
++Thanks to Alexandr Kukushkin.
++
++
++
++
++
++
++
++
++
++
++директива ssl_engine упразднена в модуле ngx_http_ssl_module и
++перенесена на глобальный уровень.
++
++
++the "ssl_engine" directive was canceled in the ngx_http_ssl_module
++and now is introduced at global level.
++
++
++
++
++
++ответы с подзапросами, включённые с помощью SSI, не передавались
++через SSL соединение.
++
++
++the responses with SSI subrequests did not transferred via SSL connection.
++
++
++
++
++
++Разные исправления в IMAP/POP3 прокси.
++
++
++Various bug fixes in the IMAP/POP3 proxy.
++
++
++
++
++
++
++
++
++
++
++IMAP/POP3 прокси поддерживает SSL.
++
++
++the IMAP/POP3 proxy supports SSL.
++
++
++
++
++
++директива proxy_timeout модуля ngx_imap_proxy_module.
++
++
++the "proxy_timeout" directive of the ngx_imap_proxy_module.
++
++
++
++
++
++директива userid_mark.
++
++
++the "userid_mark" directive.
++
++
++
++
++
++значение переменной $remote_user определяется независимо от того,
++используется ли авторизация или нет.
++
++
++the $remote_user variable value is determined independently of
++authorization use.
++
++
++
++
++
++
++
++
++
++
++listen(2) backlog в директиве listen можно менять по сигналу -HUP.
++
++
++the listen(2) backlog in the "listen" directive
++can be changed using the -HUP signal.
++
++
++
++
++
++скрипт geo2nginx.pl добавлен в contrib.
++
++
++the geo2nginx.pl script was added to contrib.
++
++
++
++
++
++параметры FastCGI с пустым значениями теперь передаются серверу.
++
++
++the FastCGI parameters with the empty values now are passed to a server.
++
++
++
++
++
++
++
++если в ответе проксированного сервера или FastCGI сервера была строка
++"Cache-Control", то при использовании директивы expires происходил
++segmentation fault или рабочий процесс мог зациклится;
++в режиме прокси ошибка появилась в 0.1.29.
++
++
++the segmentation fault occurred or the worker process may got caught
++in an endless loop if the proxied or FastCGI server sent the "Cache-Control"
++header line and the "expires" directive was used;
++in the proxied mode the bug had appeared in 0.1.29.
++
++
++
++
++
++
++
++
++
++
++если URI запроса получался нулевой длины после обработки модулем
++ngx_http_rewrite_module, то в модуле ngx_http_proxy_module происходил
++segmentation fault или bus error.
++
++
++if the request URI had a zero length after the processing in
++the ngx_http_proxy_module, then the segmentation fault or bus error occurred
++in the ngx_http_proxy_module.
++
++
++
++
++
++директива limit_rate не работала внутри блока if;
++ошибка появилась в 0.1.38.
++
++
++the "limit_rate" directive did not work inside the "if" block;
++the bug had appeared in 0.1.38.
++
++
++
++
++
++
++
++
++
++
++если переменная использовалась в файле конфигурации,
++то она не могла использоваться в SSI.
++
++
++if the variable was used in the configuration file,
++then it can not be used in SSI.
++
++
++
++
++
++
++
++
++
++
++если клиент слал очень длинную строку заголовка, то в логе не помещалась
++информация, связанная с этим запросом.
++
++
++if a client sent too long header line, then the request information
++did not logged in the error log.
++
++
++
++
++
++при использовании "X-Accel-Redirect" не передавалась строка "Set-Cookie";
++ошибка появилась в 0.1.39.
++
++
++the "Set-Cookie" header line was not transferred when the "X-Accel-Redirect"
++was used;
++the bug had appeared in 0.1.39.
++
++
++
++
++
++при использовании "X-Accel-Redirect" не передавалась строка
++"Content-Disposition".
++
++
++the "Content-Disposition" header line was not transferred when
++the "X-Accel-Redirect" was used.
++
++
++
++
++
++по сигналу SIGQUIT основной процесс не закрывал сокеты, на которых он слушал.
++
++
++the master process did not close the listen socket on the SIGQUIT signal.
++
++
++
++
++
++после обновления исполняемого файла на лету на Linux и Solaris
++название процесса в команде ps становилось короче.
++
++
++after on-line upgrade on Linux and Solaris the process name
++became shorter in the "ps" command.
++
++
++
++
++
++
++
++
++
++
++Изменения в модуле ngx_http_charset_module:
++директива default_charset упразднена;
++директива charset задаёт кодировку ответа;
++директива source_charset задаёт только исходную кодировку.
++
++
++The changes in the ngx_http_charset_module:
++the "default_charset" directive was canceled;
++the "charset" directive sets the response charset;
++the "source_charset" directive sets the source charset only.
++
++
++
++
++
++при перенаправлении ошибки 401, полученной от бэкенда, не передавалась
++строка заголовка "WWW-Authenticate".
++
++
++the backend "WWW-Authenticate" header line did not transferred while
++the 401 response code redirecting.
++
++
++
++
++
++модули ngx_http_proxy_module и ngx_http_fastcgi_module могли закрыть
++соединение до того, как что-нибудь было передано клиенту;
++ошибка появилась в 0.1.38.
++
++
++the ngx_http_proxy_module and ngx_http_fastcgi_module may close
++a connection before anything was transferred to a client;
++the bug had appeared in 0.1.38.
++
++
++
++
++
++обработка ошибки инициализации в crypt_r() в Linux glibc.
++
++
++the Linux glibc crypt_r() initialization bug.
++
++
++
++
++
++модуль ngx_http_ssi_module не поддерживал относительные URI в
++команде include virtual.
++
++
++the ngx_http_ssi_module did not support the relative URI in
++the "include virtual" command.
++
++
++
++
++
++если в строке заголовка ответа бэкенда была строка "Location",
++которую nginx не должен был изменять, то в ответе передавалось тело 500 ошибки;
++ошибка появилась в 0.1.29.
++
++
++if the backend response had the "Location" header line and nginx
++should not rewrite this line, then the 500 code response body was transferred;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++некоторые директивы модулей ngx_http_proxy_module и ngx_http_fastcgi_module
++не наследовались с уровня server на уровень location;
++ошибка появилась в 0.1.29.
++
++
++some directives of the ngx_http_proxy_module and ngx_http_fastcgi_module
++were not inherited from the server to the location level;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++модуль ngx_http_ssl_module не поддерживал цепочки сертификатов.
++
++
++the ngx_http_ssl_module did not support the certificate chain.
++
++
++
++
++
++ошибка в модуле ngx_http_autoindex_module при показе длинных имён файлов;
++ошибка появилась в 0.1.38.
++
++
++the ngx_http_autoindex_module did not show correctly the long file names;
++the bug had appeared in 0.1.38.
++
++
++
++
++
++Исправления в IMAP/POP3 прокси при взаимодействии с бэкендом на стадии login.
++
++
++Bugfixes in IMAP/POP3 proxy in interaction with a backend at the login state.
++
++
++
++
++
++
++
++
++
++
++директива limit_rate поддерживается в режиме прокси и FastCGI.
++
++
++the "limit_rate" directive is supported in proxy and FastCGI mode.
++
++
++
++
++
++в режиме прокси и FastCGI поддерживается строка заголовка "X-Accel-Limit-Rate"
++в ответе бэкенда.
++
++
++the "X-Accel-Limit-Rate" response header line is supported in proxy
++and FastCGI mode.
++
++
++
++
++
++директива break.
++
++
++the "break" directive.
++
++
++
++
++
++директива log_not_found.
++
++
++the "log_not_found" directive.
++
++
++
++
++
++при перенаправлении запроса с помощью строки заголовка "X-Accel-Redirect"
++не изменялся код ответа.
++
++
++the response status code was not changed when request was redirected
++by the ""X-Accel-Redirect" header line.
++
++
++
++
++
++переменные, установленные директивой set не могли использоваться в SSI.
++
++
++the variables set by the "set" directive could not be used in SSI.
++
++
++
++
++
++при включении в SSI более одного удалённого подзапроса
++мог произойти segmentation fault.
++
++
++the segmentation fault may occurred if the SSI page has more than one
++remote subrequest.
++
++
++
++
++
++если статусная строка в ответе бэкенда передавалась в двух пакетах, то
++nginx считал ответ неверным;
++ошибка появилась в 0.1.29.
++
++
++nginx treated the backend response as invalid if the status line in the
++header was transferred in two packets;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++директива ssi_types.
++
++
++the "ssi_types" directive.
++
++
++
++
++
++директива autoindex_exact_size.
++
++
++the "autoindex_exact_size" directive.
++
++
++
++
++
++модуль ngx_http_autoindex_module не поддерживал длинные имена файлов в UTF-8.
++
++
++the ngx_http_autoindex_module did not support the long file names in UTF-8.
++
++
++
++
++
++IMAP/POP3 прокси.
++
++
++the IMAP/POP3 proxy.
++
++
++
++
++
++
++
++
++
++
++в конце файла nginx.pid теперь добавляется "\n".
++
++
++now the "\n" is added to the end of the "nginx.pid" file.
++
++
++
++
++
++при включении большого количества вставок или нескольких больших вставок
++с помощью SSI ответ мог передаваться не полностью.
++
++
++the responses may be transferred not completely,
++if many parts or the big parts were included by SSI.
++
++
++
++
++
++если все бэкенды возвращали ответ 404, то при использовании параметра http_404
++в директивах proxy_next_upstream или fastcgi_next_upstream, nginx
++начинал запрашивать все бэкенды снова.
++
++
++if all backends had returned the 404 response and the "http_404" parameter of
++the "proxy_next_upstream" or "fastcgi_next_upstream" directives was used,
++then nginx started to request all backends again.
++
++
++
++
++
++
++
++
++
++
++если в заголовке запроса есть дублирующиеся строки "Host", "Connection",
++"Content-Length" и "Authorization", то nginx теперь выдаёт ошибку 400.
++
++
++if the request header has duplicate the "Host", "Connection", "Content-Length",
++or "Authorization" lines, then nginx now returns the 400 error.
++
++
++
++
++
++директива post_accept_timeout упразднена.
++
++
++the "post_accept_timeout" directive was canceled.
++
++
++
++
++
++параметры default, af=, bl=, deferred и bind в директиве listen.
++
++
++the "default", "af=", "bl=", "deferred", and "bind" parameters
++of the "listen" directive.
++
++
++
++
++
++поддержка accept фильтров во FreeBSD.
++
++
++the FreeBSD accept filters support.
++
++
++
++
++
++поддержка TCP_DEFER_ACCEPT в Linux.
++
++
++the Linux TCP_DEFER_ACCEPT support.
++
++
++
++
++
++модуль ngx_http_autoindex_module не поддерживал имена файлов в UTF-8.
++
++
++the ngx_http_autoindex_module did not support the file names in UTF-8.
++
++
++
++
++
++после добавления новый лог-файл ротация этого лога по сигналу -USR1
++выполнялась, только если переконфигурировать nginx два раза по сигналу -HUP.
++
++
++the new log file can be rotated by the -USR1 signal only if
++the reconfiguration by the -HUP signal was made twice.
++
++
++
++
++
++
++
++
++
++
++директива working_directory.
++
++
++the "working_directory" directive.
++
++
++
++
++
++директива port_in_redirect.
++
++
++the "port_in_redirect" directive.
++
++
++
++
++
++если заголовок ответа бэкенда не помещался в один пакет, то
++происходил segmentation fault;
++ошибка появилась в 0.1.29.
++
++
++the segmentation fault was occurred if the backend response header was in
++several packets;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++если было сконфигурировано более 10 серверов или в сервере не описана
++директива "listen",
++то при запуске мог произойти segmentation fault.
++
++
++if more than 10 servers were configured or some server did not use the
++"listen" directive, then the segmentation fault was occurred on the start.
++
++
++
++
++
++если ответ не помещался во временный файл,
++то мог произойти segmentation fault.
++
++
++the segmentation fault might occur if the response was bigger than
++the temporary file.
++
++
++
++
++
++nginx возвращал ошибку 400 на запросы вида
++"GET http://www.domain.com/uri HTTP/1.0";
++ошибка появилась в 0.1.28.
++
++
++nginx returned the 400 response on requests like
++"GET http://www.domain.com/uri HTTP/1.0";
++the bug had appeared in 0.1.28.
++
++
++
++
++
++
++
++
++
++
++при включении больших ответов с помощью SSI рабочий процесс мог зациклиться.
++
++
++the worker process may got caught in an endless loop if the big response
++part were include by SSI.
++
++
++
++
++
++переменные, устанавливаемые директивой "set", не были доступны в SSI.
++
++
++the variables set by the "set" directive were not available in SSI.
++
++
++
++
++
++директива autoindex_localtime.
++
++
++the "autoindex_localtime" directive.
++
++
++
++
++
++пустое значение в директиве proxy_set_header запрещает передачу заголовка.
++
++
++the empty value of the "proxy_set_header" directive forbids the client
++request header line passing.
++
++
++
++
++
++
++
++
++
++
++nginx не собирался с параметром --without-pcre;
++ошибка появилась в 0.1.29.
++
++
++nginx could not be built with the --without-pcre parameter;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++3, 5, 7 и 8 директив proxy_set_header на одном уровне вызывали
++bus fault при запуске.
++
++
++3, 4, 7, and 8 the "proxy_set_header" directives in one level cause
++the bus fault on start up.
++
++
++
++
++
++в редиректах внутри HTTPS сервера был указан протокол HTTP.
++
++
++the HTTP protocol was specified in the HTTPS redirects.
++
++
++
++
++
++если директива rewrite использовала выделения внутри директивы if, то
++возвращалась ошибка 500.
++
++
++if the "rewrite" directive used the captures inside the "if" directive, then
++the 500 error code was returned.
++
++
++
++
++
++
++
++
++
++
++в редиректах, выдаваемых с помощью директивы rewrite, не передавались аргументы;
++ошибка появилась в 0.1.29.
++
++
++the arguments were omitted in the redirects, issued by the "rewrite" directive;
++the bug had appeared in 0.1.29.
++
++
++
++
++
++директива if поддерживает выделения в регулярных выражениях.
++
++
++the "if" directive supports the captures in regular expressions.
++
++
++
++
++
++директива set поддерживает переменные и выделения из регулярных выражений.
++
++
++the "set" directive supports the variables and the captures of regular
++expressions.
++
++
++
++
++
++в режиме прокси и FastCGI поддерживается строка заголовка "X-Accel-Redirect"
++в ответе бэкенда.
++
++
++the "X-Accel-Redirect" response header line is supported in proxy and FastCGI
++mode.
++
++
++
++
++
++
++
++
++
++
++при использовании SSL ответ мог передаваться не до конца.
++
++
++the response encrypted by SSL may not transferred complete.
++
++
++
++
++
++ошибки при обработке SSI в ответе, полученного от FastCGI-сервера.
++
++
++errors while processing FastCGI response by SSI.
++
++
++
++
++
++ошибки при использовании SSI и сжатия.
++
++
++errors while using SSI and gzipping.
++
++
++
++
++
++редирект с кодом 301 передавался без тела ответа;
++ошибка появилась в 0.1.30.
++
++
++the redirect with the 301 code was transferred without response body;
++the bug had appeared in 0.1.30.
++
++
++
++
++
++
++
++
++
++
++при использовании SSI рабочий процесс мог зациклиться.
++
++
++the worker process may got caught in an endless loop if the SSI was used.
++
++
++
++
++
++при использовании SSL ответ мог передаваться не до конца.
++
++
++the response encrypted by SSL may not transferred complete.
++
++
++
++
++
++если длина части ответа, полученного за один раз от проксируемого или
++FastCGI сервера была равна 500 байт, то nginx возвращал код ответа 500;
++в режиме прокси ошибка появилась только в 0.1.29.
++
++
++if the length of the response part received at once from proxied
++or FastCGI server was equal to 500, then nginx returns the 500 response code;
++in proxy mode the bug had appeared in 0.1.29 only.
++
++
++
++
++
++nginx не считал неверными директивы с 8-ю или 9-ю параметрами.
++
++
++nginx did not consider the directives with 8 or 9 parameters as invalid.
++
++
++
++
++
++директива return может возвращать код ответа 204.
++
++
++the "return" directive can return the 204 response code.
++
++
++
++
++
++директива ignore_invalid_headers.
++
++
++the "ignore_invalid_headers" directive.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает команду include virtual.
++
++
++the ngx_http_ssi_module supports "include virtual" command.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает условную команду вида
++'if expr="$NAME"' и команды else и endif.
++Допускается только один уровень вложенности.
++
++
++the ngx_http_ssi_module supports the condition command like
++'if expr="$NAME"' and "else" and "endif" commands.
++Only one nested level is supported.
++
++
++
++
++
++модуль ngx_http_ssi_module поддерживает две переменные DATE_LOCAL и DATE_GMT
++и команду config timefmt.
++
++
++the ngx_http_ssi_module supports the DATE_LOCAL and DATE_GMT variables
++and "config timefmt" command.
++
++
++
++
++
++директива ssi_ignore_recycled_buffers.
++
++
++the "ssi_ignore_recycled_buffers" directive.
++
++
++
++
++
++если переменная QUERY_STRING не была определена, то в команде echo
++не ставилось значение по умолчанию.
++
++
++the "echo" command did not show the default value for the empty QUERY_STRING
++variable.
++
++
++
++
++
++модуль ngx_http_proxy_module полностью переписан.
++
++
++the ngx_http_proxy_module was rewritten.
++
++
++
++
++
++директивы proxy_redirect, proxy_pass_request_headers,
++proxy_pass_request_body и proxy_method.
++
++
++the "proxy_redirect", "proxy_pass_request_headers",
++"proxy_pass_request_body", and "proxy_method" directives.
++
++
++
++
++
++директива proxy_set_header.
++Директива proxy_x_var упразднена и должна быть заменена директивой
++proxy_set_header.
++
++
++the "proxy_set_header" directive.
++The "proxy_x_var" was canceled and must be replaced with the proxy_set_header
++directive.
++
++
++
++
++
++директива proxy_preserve_host упразднена и должна быть заменена директивами
++"proxy_set_header Host $host" и "proxy_redirect off"
++или директивой "proxy_set_header Host $host:$proxy_port"
++и соответствующими ей директивами proxy_redirect.
++
++
++the "proxy_preserve_host" is canceled and must be replaced with
++the "proxy_set_header Host $host" and the "proxy_redirect off" directives,
++the "proxy_set_header Host $host:$proxy_port" directive
++and the appropriate proxy_redirect directives.
++
++
++
++
++
++директива proxy_set_x_real_ip упразднена и должна быть заменена директивой
++"proxy_set_header X-Real-IP $remote_addr".
++
++
++the "proxy_set_x_real_ip" is canceled and must be replaced with
++the "proxy_set_header X-Real-IP $remote_addr" directive.
++
++
++
++
++
++директива proxy_add_x_forwarded_for упразднена и должна быть заменена
++директивой
++"proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for".
++
++
++the "proxy_add_x_forwarded_for" is canceled and must be replaced with
++the "proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for"
++directive.
++
++
++
++
++
++директива proxy_set_x_url упразднена и должна быть заменена директивой
++"proxy_set_header X-URL http://$host:$server_port$request_uri".
++
++
++the "proxy_set_x_url" is canceled and must be replaced with
++the "proxy_set_header X-URL http://$host:$server_port$request_uri"
++directive.
++
++
++
++
++
++директива fastcgi_param.
++
++
++the "fastcgi_param" directive.
++
++
++
++
++
++директивы fastcgi_root, fastcgi_set_var и fastcgi_params упразднены
++и должны быть замены директивами fastcgi_param.
++
++
++the "fastcgi_root", "fastcgi_set_var" and "fastcgi_params" directive
++are canceled and must be replaced with the fastcgi_param directives.
++
++
++
++
++
++директива index может использовать переменные.
++
++
++the "index" directive can use the variables.
++
++
++
++
++
++директива index может быть указана на уровне http и server.
++
++
++the "index" directive can be used at http and server levels.
++
++
++
++
++
++только последний параметр в директиве index может быть абсолютным.
++
++
++the last index only in the "index" directive can be absolute.
++
++
++
++
++
++в директиве rewrite могут использоваться переменные.
++
++
++the "rewrite" directive can use the variables.
++
++
++
++
++
++директива internal.
++
++
++the "internal" directive.
++
++
++
++
++
++переменные CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
++SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
++REQUEST_METHOD, REQUEST_URI и REMOTE_USER.
++
++
++the CONTENT_LENGTH, CONTENT_TYPE, REMOTE_PORT, SERVER_ADDR,
++SERVER_PORT, SERVER_PROTOCOL, DOCUMENT_ROOT, SERVER_NAME,
++REQUEST_METHOD, REQUEST_URI, and REMOTE_USER variables.
++
++
++
++
++
++nginx теперь передаёт неверные строки в заголовках запроса клиента и
++ответа бэкенда.
++
++
++nginx now passes the invalid lines in a client request headers
++or a backend response header.
++
++
++
++
++
++если бэкенд долго не передавал ответ и send_timeout был меньше, чем
++proxy_read_timeout, то клиенту возвращался ответ 408.
++
++
++if the backend did not transfer response for a long time and
++the "send_timeout" was less than "proxy_read_timeout", then nginx
++returned the 408 response.
++
++
++
++
++
++если бэкенд передавал неверную строку в заголовке ответа, то происходил
++segmentation fault;
++ошибка появилась в 0.1.26.
++
++
++the segmentation fault was occurred if the backend sent an invalid line
++in response header;
++the bug had appeared in 0.1.26.
++
++
++
++
++
++при использовании отказоустойчивой конфигурации в FastCGI мог
++происходить segmentation fault.
++
++
++the segmentation fault may occurred in FastCGI fault tolerance configuration.
++
++
++
++
++
++директива expires не удаляла уже установленные строки заголовка
++"Expires" и "Cache-Control".
++
++
++the "expires" directive did not remove the previous "Expires" and
++"Cache-Control" headers.
++
++
++
++
++
++nginx не учитывал завершающую точку в строке заголовка запроса "Host".
++
++
++nginx did not take into account trailing dot in "Host" header line.
++
++
++
++
++
++модуль ngx_http_auth_module не работал на Linux.
++
++
++the ngx_http_auth_module did not work under Linux.
++
++
++
++
++
++директива rewrite неверно работала, если в запросе присутствовали аргументы.
++
++
++the rewrite directive worked incorrectly, if the arguments were in a request.
++
++
++
++
++
++nginx не собирался на MacOS X.
++
++
++nginx could not be built on MacOS X.
++
++
++
++
++
++
++
++
++
++
++при проксировании больших файлов nginx сильно нагружал процессор.
++
++
++nginx hogs CPU while proxying the huge files.
++
++
++
++
++
++nginx не собирался gcc 4.0 на Linux.
++
++
++nginx could not be built by gcc 4.0 on Linux.
++
++
++
++
++
++
++
++
++
++
++параметр blocked в директиве valid_referers.
++
++
++the "blocked" parameter of the "valid_referers" directive.
++
++
++
++
++
++ошибки обработки заголовка запроса теперь записываются на уровне
++info, в лог также записывается имя сервера и строки заголовка
++запроса "Host" и "Referer".
++
++
++the errors while handling the request header now logged at "info" level.
++The server name and the "Host" and "Referer" header lines also logged.
++
++
++
++
++
++при записи ошибок в лог записывается также строка заголовка запроса "Host".
++
++
++the "Host" header line is also logged in error log.
++
++
++
++
++
++директива proxy_pass_unparsed_uri.
++Специальная обработка символов "://" в URI, введённая в версии 0.1.11,
++теперь упразднена.
++
++
++the proxy_pass_unparsed_uri directive.
++The special handling of the "://" symbols in URI, appeared in 0.1.11 version,
++now is canceled.
++
++
++
++
++
++nginx не собирался на FreeBSD и Linux, если был указан параметр конфигурации
++--without-ngx_http_auth_basic_module.
++
++
++nginx could not be built on FreeBSD and Linux, if the
++--without-ngx_http_auth_basic_module configuration parameter was used.
++
++
++
++
++
++
++
++
++
++
++неверные строки заголовка, переданные клиентом, теперь игнорируется и
++записываются в error_log на уровне info.
++
++
++the invalid client header lines are now ignored and logged at the info level.
++
++
++
++
++
++при записи ошибок в лог записывается также имя сервера, при обращении
++к которому произошла ошибка.
++
++
++the server name is also logged in error log.
++
++
++
++
++
++модуль ngx_http_auth_basic_module и директивы auth_basic и
++auth_basic_user_file.
++
++
++the ngx_http_auth_basic_module module and the auth_basic and
++auth_basic_user_file directives.
++
++
++
++
++
++
++
++
++
++
++nginx не работал на Linux parisc.
++
++
++nginx did run on Linux parisc.
++
++
++
++
++
++nginx теперь не запускается под FreeBSD, если значение
++sysctl kern.ipc.somaxconn слишком большое.
++
++
++nginx now does not start under FreeBSD if the sysctl kern.ipc.somaxconn
++value is too big.
++
++
++
++
++
++если модуль ngx_http_index_module делал внутреннее перенаправление запроса
++в модули ngx_http_proxy_module или ngx_http_fastcgi_module, то файл индекса
++не закрывался после обслуживания запроса.
++
++
++if a request was internally redirected by the ngx_http_index_module
++module to the ngx_http_proxy_module or ngx_http_fastcgi_module modules,
++then the index file was not closed after request completion.
++
++
++
++
++
++директива proxy_pass может использоваться в location, заданных регулярным
++выражением.
++
++
++the "proxy_pass" can be used in location with regular expression.
++
++
++
++
++
++модуль ngx_http_rewrite_filter_module поддерживает условия вида
++"if ($HTTP_USER_AGENT ~ MSIE)".
++
++
++the ngx_http_rewrite_filter_module module supports the condition like
++"if ($HTTP_USER_AGENT ~ MSIE)".
++
++
++
++
++
++nginx очень медленно запускался при большом количестве адресов и
++использовании текстовых значений в директиве geo.
++
++
++nginx started too slow if the large number of addresses and text values
++were used in the "geo" directive.
++
++
++
++
++
++имя переменной в директиве geo нужно указывать, как $name.
++Прежний вариант без "$" пока работает, но вскоре будет убран.
++
++
++a variable name must be declared as "$name" in the "geo" directive.
++The previous variant without "$" is still supported, but will be removed soon.
++
++
++
++
++
++параметр лога "%{VARIABLE}v".
++
++
++the "%{VARIABLE}v" logging parameter.
++
++
++
++
++
++директива "set $name value".
++
++
++the "set $name value" directive.
++
++
++
++
++
++совместимость с gcc 4.0.
++
++
++gcc 4.0 compatibility.
++
++
++
++
++
++параметр автоконфигурации --with-openssl-opt=OPTIONS.
++
++
++the --with-openssl-opt=OPTIONS autoconfiguration directive.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_ssi_filter_module поддерживает переменные
++QUERY_STRING и DOCUMENT_URI.
++
++
++the ngx_http_ssi_filter_module supports the QUERY_STRING and DOCUMENT_URI
++variables.
++
++
++
++
++
++модуль ngx_http_autoindex_module мог выдавать ответ 404
++на существующий каталог, если этот каталог был указан как alias.
++
++
++the ngx_http_autoindex_module may some times return the 404 response
++for existent directory, if this directory was used in "alias" directive.
++
++
++
++
++
++модуль ngx_http_ssi_filter_module неправильно работал при больших
++ответах.
++
++
++the ngx_http_ssi_filter_module ran incorrectly for large responses.
++
++
++
++
++
++отсутствие строки заголовка "Referer" всегда считалось правильным referrer'ом.
++
++
++the lack of the "Referer" header line was always accounted as valid referrer.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_ssi_filter_module и
++директивы ssi, ssi_silent_errors и ssi_min_file_chunk.
++Поддерживаются команды 'echo var="HTTP_..." default=""' и
++'echo var="REMOTE_ADDR"'.
++
++
++the ngx_http_ssi_filter_module and
++the ssi, ssi_silent_errors, and ssi_min_file_chunk directives.
++The 'echo var="HTTP_..." default=""' and 'echo var="REMOTE_ADDR"' commands
++are supported.
++
++
++
++
++
++параметр лога %request_time.
++
++
++the %request_time log parameter.
++
++
++
++
++
++если запрос пришёл без строки заголовка "Host", то директива
++proxy_preserve_host устанавливает в качестве этого заголовка первое имя
++сервера из директивы server_name.
++
++
++if the request has no the "Host" header line, then the "proxy_preserve_host"
++directive set this header line to the first server name of the "server_name"
++directive.
++
++
++
++
++
++nginx не собирался на платформах, отличных от i386, amd64, sparc и ppc;
++ошибка появилась в 0.1.22.
++
++
++nginx could not be built on platforms different from i386, amd64, sparc,
++and ppc;
++the bug had appeared in 0.1.22.
++
++
++
++
++
++модуль ngx_http_autoindex_module теперь показывает информацию не о
++символическом линке, а о файле или каталоге, на который он указывает.
++
++
++the ngx_http_autoindex_module now shows the information not about the symlink,
++but about file or directory it points to.
++
++
++
++
++
++если клиенту ничего не передавалось, то параметр %apache_length
++записывал в лог отрицательную длину заголовка ответа.
++
++
++the %apache_length parameter logged the negative length
++of the response header if the no response was transferred to a client.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_stub_status_module показывал неверную статистику
++для обработанных соединений, если использовалось проксирование
++или FastCGI-сервер.
++
++
++the ngx_http_stub_status_module showed incorrect handled connections
++statistics if the proxying or FastCGI server were used.
++
++
++
++
++
++на Linux и Solaris установочные пути были неверно заключены в кавычки;
++ошибка появилась в 0.1.21.
++
++
++the installation paths were incorrectly quoted on Linux and Solaris;
++the bug had appeared in 0.1.21.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_stub_status_module показывал неверную статистику
++при использовании метода rtsig или при использовании нескольких
++рабочих процессов на SMP машине.
++
++
++the ngx_http_stub_status_module showed incorrect statistics
++if "rtsig" method was used or if several worker process ran on SMP.
++
++
++
++
++
++nginx не собирался компилятором icc под Линуксом или
++если библиотека zlib-1.2.x собиралась из исходных текстов.
++
++
++nginx could not be built by the icc compiler on Linux or
++if the zlib-1.2.x library was building from sources.
++
++
++
++
++
++nginx не собирался под NetBSD 2.0.
++
++
++nginx could not be built on NetBSD 2.0.
++
++
++
++
++
++
++
++
++
++
++новые параметры script_filename и remote_port в директиве fastcgi_params.
++
++
++the new "script_filename" and "remote_port" parameters
++of the fastcgi_params directive.
++
++
++
++
++
++неправильно обрабатывался поток stderr от FastCGI-сервера.
++
++
++the FastCGI stderr stream was handled incorrectly.
++
++
++
++
++
++
++
++
++
++
++если в запросе есть нуль, то для локальных запросов теперь возвращается
++ошибка 404.
++
++
++now, if request contains the zero, then the 404 error is returned
++for the local requests.
++
++
++
++
++
++nginx не собирался под NetBSD 2.0.
++
++
++nginx could not be built on NetBSD 2.0.
++
++
++
++
++
++во время чтения тела запроса клиента в SSL соединении мог произойти таймаут.
++
++
++the timeout may occur while reading of the client request body
++via SSL connections.
++
++
++
++
++
++
++
++
++
++
++для совместимости с Solaris 10 в директивах devpoll_events и devpoll_changes
++значения по умолчанию уменьшены с 512 до 32.
++
++
++the default values of the devpoll_events and the devpoll_changes directives
++changed from 512 to 32 to be compatible with Solaris 10.
++
++
++
++
++
++директивы proxy_set_x_var и fastcgi_set_var не наследовались.
++
++
++the proxy_set_x_var and fastcgi_set_var directives were not inherited.
++
++
++
++
++
++в директиве rewrite, возвращающей редирект, аргументы присоединялись
++к URI через символ "&" вместо "?".
++
++
++in a redirect rewrite directive arguments were concatenated with URI
++by an "&" rather than a "?".
++
++
++
++
++
++строки для модуля ngx_http_geo_module без символа ";" во включённом файле
++игнорировались.
++
++
++the lines without trailing ";" in the file being included
++by the ngx_http_geo_module were silently ignored.
++
++
++
++
++
++модуль ngx_http_stub_status_module.
++
++
++the ngx_http_stub_status_module.
++
++
++
++
++
++неизвестный формат лог-файла в директиве access_log вызывал segmentation fault.
++
++
++the unknown log format in the access_log directive caused
++the segmentation fault.
++
++
++
++
++
++новый параметр document_root в директиве fastcgi_params.
++
++
++the new "document_root" parameter of the fastcgi_params directive.
++
++
++
++
++
++директива fastcgi_redirect_errors.
++
++
++the fastcgi_redirect_errors directive.
++
++
++
++
++
++новый модификатор break в директиве rewrite позволяет прекратить
++цикл rewrite/location и устанавливает текущую конфигурацию для запроса.
++
++
++the new "break" modifier of the "rewrite" directive allows to stop
++the rewrite/location cycle and sets the current configuration to the request.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_rewrite_module полностью переписан.
++Теперь можно делать редиректы, возвращать коды ошибок
++и проверять переменные и рефереры.
++Эти директивы можно использовать внутри location.
++Директива redirect упразднена.
++
++
++the ngx_http_rewrite_module was rewritten from the scratch.
++Now it is possible to redirect, to return the error codes,
++to check the variables and referrers. The directives can be used
++inside locations.
++The redirect directive was canceled.
++
++
++
++
++
++модуль ngx_http_geo_module.
++
++
++the ngx_http_geo_module.
++
++
++
++
++
++директивы proxy_set_x_var и fastcgi_set_var.
++
++
++the proxy_set_x_var and fastcgi_set_var directives.
++
++
++
++
++
++конфигурация location с модификатором "=" могла использоваться
++в другом location.
++
++
++the location configuration with "=" modifier may be used in another
++location.
++
++
++
++
++
++правильный тип ответа выставлялся только для запросов, у которых в расширении
++были только маленькие буквы.
++
++
++the correct content type was set only for requests that use small caps letters
++in extension.
++
++
++
++
++
++если для location установлен proxy_pass или fastcgi_pass, и доступ
++к нему запрещался, а ошибка перенаправлялась на статическую страницу,
++то происходил segmentation fault.
++
++
++if the proxy_pass or fastcgi_pass directives were set in the location,
++and access was denied, and the error was redirected to a static page,
++then the segmentation fault occurred.
++
++
++
++
++
++если в проксированном ответе в заголовке "Location" передавался
++относительный URL, то к нему добавлялось имя хоста и слэш;
++ошибка появилась в 0.1.14.
++
++
++if in a proxied "Location" header was a relative URL,
++then a host name and a slash were added to them;
++the bug had appeared in 0.1.14.
++
++
++
++
++
++на Linux в лог не записывался текст системной ошибки.
++
++
++the system error message was not logged on Linux.
++
++
++
++
++
++
++
++
++
++
++если ответ передавался chunk'ами, то при запросе HEAD выдавался
++завершающий chunk.
++
++
++if the response were transferred by chunks, then on the HEAD request
++the final chunk was issued.
++
++
++
++
++
++заголовок "Connection: keep-alive" выдавался, даже если директива
++keepalive_timeout запрещала использование keep-alive.
++
++
++the "Connection: keep-alive" header were issued, even if the
++keepalive_timeout directive forbade the keep-alive use.
++
++
++
++
++
++ошибки в модуле ngx_http_fastcgi_module вызывали segmentation fault.
++
++
++the errors in the ngx_http_fastcgi_module caused the segmentation faults.
++
++
++
++
++
++при использовании SSL сжатый ответ мог передаваться не до конца.
++
++
++the compressed response encrypted by SSL may not transferred complete.
++
++
++
++
++
++опции TCP_NODELAY, TCP_NOPUSH и TCP_CORK, специфичные для TCP сокетов,
++не используются для unix domain сокетов.
++
++
++the TCP-specific TCP_NODELAY, TCP_NOPUSH, and TCP_CORK options,
++are not used for the unix domain sockets.
++
++
++
++
++
++директива rewrite поддерживает перезаписывание аргументов.
++
++
++the rewrite directive supports the arguments rewriting.
++
++
++
++
++
++на запрос POST с заголовком "Content-Length: 0" возвращался ответ 400;
++ошибка появилась в 0.1.14.
++
++
++the response code 400 was returned for the POST request with the
++"Content-Length: 0" header;
++the bug had appeared in 0.1.14.
++
++
++
++
++
++
++
++
++
++
++ошибка соединения с FastCGI-сервером вызывала segmentation fault.
++
++
++the error while the connecting to the FastCGI server caused
++segmentation fault.
++
++
++
++
++
++корректная обработка регулярного выражения, в котором число
++выделенных частей не совпадает с числом подстановок.
++
++
++the correct handling of the regular expression, that
++has different number of the captures and substitutions.
++
++
++
++
++
++location, который передаётся FastCGI-серверу, может быть задан
++с помощью регулярного выражения.
++
++
++the location, that is passed to the FastCGI server, can be
++regular expression.
++
++
++
++
++
++параметр FastCGI REQUEST_URI теперь передаётся вместе с аргументами
++и в том виде, в котором был получен от клиента.
++
++
++the FastCGI's parameter REQUEST_URI is now passed with the arguments
++and in the original state.
++
++
++
++
++
++для использования регулярных выражений в location нужно было
++собирать nginx вместе с ngx_http_rewrite_module.
++
++
++the ngx_http_rewrite_module module was required to be built to use
++the regular expressions in locations.
++
++
++
++
++
++если бэкенд слушал на 80-ом порту, то при использовании директивы
++"proxy_preserve_host on" в заголовке "Host" указывался
++также порт 80;
++ошибка появилась в 0.1.14.
++
++
++the directive "proxy_preserve_host on" adds port 80
++to the "Host" headers, if upstream listen on port 80;
++the bug had appeared in 0.1.14.
++
++
++
++
++
++если задать одинаковые пути в параметрах автоконфигурации
++--http-client-body-temp-path=PATH и --http-proxy-temp-path=PATH
++или --http-client-body-temp-path=PATH и --http-fastcgi-temp-path=PATH,
++то происходил segmentation fault.
++
++
++the same paths in autoconfiguration parameters
++--http-client-body-temp-path=PATH and --http-proxy-temp-path=PATH,
++or --http-client-body-temp-path=PATH and --http-fastcgi-temp-path=PATH
++caused segmentation fault.
++
++
++
++
++
++
++
++
++
++
++параметры автоконфигурации
++--http-client-body-temp-path=PATH,
++--http-proxy-temp-path=PATH
++и --http-fastcgi-temp-path=PATH
++
++
++the autoconfiguration directives:
++--http-client-body-temp-path=PATH,
++--http-proxy-temp-path=PATH,
++and --http-fastcgi-temp-path=PATH
++
++
++
++
++
++имя каталога с временными файлами, содержащие тело запроса клиента,
++задаётся директивой client_body_temp_path,
++по умолчанию <prefix>/client_body_temp.
++
++
++the directory name for the temporary files with the client request body
++is specified by directive client_body_temp_path,
++by default it is <prefix>/client_body_temp.
++
++
++
++
++
++модуль ngx_http_fastcgi_module и директивы
++fastcgi_pass,
++fastcgi_root,
++fastcgi_index,
++fastcgi_params,
++fastcgi_connect_timeout,
++fastcgi_send_timeout,
++fastcgi_read_timeout,
++fastcgi_send_lowat,
++fastcgi_header_buffer_size,
++fastcgi_buffers,
++fastcgi_busy_buffers_size,
++fastcgi_temp_path,
++fastcgi_max_temp_file_size,
++fastcgi_temp_file_write_size,
++fastcgi_next_upstream
++и fastcgi_x_powered_by.
++
++
++
++the ngx_http_fastcgi_module and the directives:
++fastcgi_pass,
++fastcgi_root,
++fastcgi_index,
++fastcgi_params,
++fastcgi_connect_timeout,
++fastcgi_send_timeout,
++fastcgi_read_timeout,
++fastcgi_send_lowat,
++fastcgi_header_buffer_size,
++fastcgi_buffers,
++fastcgi_busy_buffers_size,
++fastcgi_temp_path,
++fastcgi_max_temp_file_size,
++fastcgi_temp_file_write_size,
++fastcgi_next_upstream,
++and fastcgi_x_powered_by.
++
++
++
++
++
++ошибка "[alert] zero size buf";
++ошибка появилась в 0.1.3.
++
++
++the "[alert] zero size buf" error;
++the bug had appeared in 0.1.3.
++
++
++
++
++
++в директиве proxy_pass нужно обязательно указывать URI после имени хоста.
++
++
++the URI must be specified after the host name in the proxy_pass directive.
++
++
++
++
++
++если в URI встречался символ %3F, то он считался началом строки аргументов.
++
++
++the %3F symbol in the URI was considered as the argument string start.
++
++
++
++
++
++поддержка unix domain сокетов в модуле ngx_http_proxy_module.
++
++
++the unix domain sockets support in the ngx_http_proxy_module.
++
++
++
++
++
++директивы ssl_engine и ssl_ciphers.
++Спасибо Сергею Скворцову за SSL-акселератор.
++
++
++the ssl_engine and ssl_ciphers directives.
++Thanks to Sergey Skvortsov for SSL-accelerator.
++
++
++
++
++
++
++
++
++
++
++директивы server_names_hash и server_names_hash_threshold.
++
++
++the server_names_hash and server_names_hash_threshold directives.
++
++
++
++
++
++имена *.domain.tld в директиве server_name не работали.
++
++
++the *.domain.tld names in the "server_name" directive did not work.
++
++
++
++
++
++параметр лога %request_length записывал неверную длину.
++
++
++the %request_length log parameter logged the incorrect length.
++
++
++
++
++
++
++
++
++
++
++параметр лога %request_length.
++
++
++the %request_length log parameter.
++
++
++
++
++
++при использовании /dev/poll, select и poll на платформах, где возможны
++ложные срабатывания указанных методов, могли быть длительные задержки
++при обработке запроса по keep-alive соединению.
++Наблюдалось по крайней мере на Solaris с использованием /dev/poll.
++
++
++when using the /dev/poll, select and poll on the platforms, where
++these methods may do the false reports, there may be the long delay when
++the request was passed via the keep-alive connection.
++It may be at least on Solaris when using the /dev/poll.
++
++
++
++
++
++директива send_lowat игнорируется на Linux, так как Linux не поддерживает
++опцию SO_SNDLOWAT.
++
++
++the send_lowat directive is ignored on Linux because Linux does not support
++the SO_SNDLOWAT option.
++
++
++
++
++
++
++
++
++
++
++директива worker_priority.
++
++
++the worker_priority directive.
++
++
++
++
++
++под FreeBSD директивы tcp_nopush и tcp_nodelay вместе влияют на передачу
++ответа.
++
++
++both tcp_nopush and tcp_nodelay directives affect the transferred response.
++
++
++
++
++
++nginx не вызывал initgroups().
++Спасибо Андрею Ситникову и Андрею Нигматулину.
++
++
++nginx did not call initgroups().
++Thanks to Andrew Sitnikov and Andrei Nigmatulin.
++
++
++
++
++
++ngx_http_auto_index_module теперь выдаёт размер файлов в байтах.
++
++
++now the ngx_http_autoindex_module shows the file size in the bytes.
++
++
++
++
++
++ngx_http_auto_index_module возвращал ошибку 500, если в каталоге есть
++битый symlink.
++
++
++the ngx_http_autoindex_module returned the 500 error if the broken symlink
++was in a directory.
++
++
++
++
++
++файлы больше 4G не передавались с использованием sendfile.
++
++
++the files bigger than 4G could not be transferred using sendfile.
++
++
++
++
++
++если бэкенд резолвился в несколько адресов и при ожидании от него ответа
++происходила ошибка, то процесс зацикливался.
++
++
++if the backend was resolved to several backends and there was an error while
++the response waiting then process may got caught in an endless loop.
++
++
++
++
++
++при использовании метода /dev/poll рабочий процесс мог завершиться
++с сообщением "unknown cycle".
++
++
++the worker process may exit with the "unknown cycle" message when the /dev/poll
++method was used.
++
++
++
++
++
++ошибки "close() channel failed".
++
++
++"close() channel failed" errors.
++
++
++
++
++
++автоматическое определение групп nobody и nogroup.
++
++
++the autodetection of the "nobody" and "nogroup" groups.
++
++
++
++
++
++директива send_lowat не работала на Linux.
++
++
++the send_lowat directive did not work on Linux.
++
++
++
++
++
++если в конфигурации не было раздела events, то происходил segmentation fault.
++
++
++the segmentation fault occurred if there was no events section
++in configuration.
++
++
++
++
++
++nginx не собирался под OpenBSD.
++
++
++nginx could not be built on OpenBSD.
++
++
++
++
++
++двойные слэшы в "://" в URI превращались в ":/".
++
++
++the double slashes in "://" in the URI were converted to ":/".
++
++
++
++
++
++
++
++
++
++
++если в запросе без аргументов есть "//", "/./", "/../" или "%XX",
++то терялся последний символ в строке запроса;
++ошибка появилась в 0.1.9.
++
++
++if the request without arguments contains "//", "/./", "/../" or "%XX"
++then the last character in the request line was lost;
++the bug had appeared in 0.1.9.
++
++
++
++
++
++исправление в версии 0.1.9 для файлов больше 2G на Linux не работало.
++
++
++the fix in 0.1.9 for the files bigger than 2G on Linux did not work.
++
++
++
++
++
++
++
++
++
++
++если в запросе есть "//", "/./", "/../" или "%XX", то проксируемый
++запрос передавался без аргументов.
++
++
++the proxied request was sent without arguments if the request contains
++"//", "/./", "/../" or "%XX".
++
++
++
++
++
++при сжатии больших ответов иногда они передавались не полностью.
++
++
++the large compressed responses may be transferred not completely.
++
++
++
++
++
++не передавались файлы больше 2G на Linux, неподдерживающем sendfile64().
++
++
++the files bigger than 2G was not transferred on Linux that does not support
++sendfile64().
++
++
++
++
++
++на Linux при конфигурации сборки нужно было обязательно использовать
++параметр --with-poll_module;
++ошибка появилась в 0.1.8.
++
++
++while the build configuration on Linux the --with-poll_module parameter
++was required;
++the bug had appeared in 0.1.8.
++
++
++
++
++
++
++
++
++
++
++ошибка в модуле ngx_http_autoindex_module при показе длинных имён файлов.
++
++
++in the ngx_http_autoindex_module if the long file names were in the listing.
++
++
++
++
++
++модификатор "^~" в директиве location.
++
++
++the "^~" modifier in the location directive.
++
++
++
++
++
++директива proxy_max_temp_file_size.
++
++
++the proxy_max_temp_file_size directive.
++
++
++
++
++
++
++
++
++
++
++при использовании sendfile, если передаваемый файл менялся, то мог
++произойти segmentation fault на FreeBSD;
++ошибка появилась в 0.1.5.
++
++
++on FreeBSD the segmentation fault may occur if the size of the transferred
++file was changed;
++the bug had appeared in 0.1.5.
++
++
++
++
++
++
++
++
++
++
++при некоторых комбинациях директив location c регулярными выражениями
++использовалась конфигурация не из того location.
++
++
++some location directive combinations with the regular expressions caused
++the wrong configuration choose.
++
++
++
++
++
++
++
++
++
++
++на Solaris и Linux могло быть очень много сообщений "recvmsg() returned
++not enough data".
++
++
++on Solaris and Linux there may be too many "recvmsg() returned not enough data"
++alerts.
++
++
++
++
++
++в режиме прокси без использования sendfile на Solaris возникала
++ошибка "writev() failed (22: Invalid argument)".
++На других платформах, не поддерживающих sendfile, процесс зацикливался.
++
++
++there were the "writev() failed (22: Invalid argument)" errors on
++Solaris in proxy mode without sendfile. On other platforms that do not
++support sendfile at all the process got caught in an endless loop.
++
++
++
++
++
++при использовании sendfile в режиме прокси на Solaris возникал
++segmentation fault.
++
++
++segmentation fault on Solaris in proxy mode and using sendfile.
++
++
++
++
++
++segmentation fault на Solaris.
++
++
++segmentation fault on Solaris.
++
++
++
++
++
++обновление исполняемого файла на лету не работало на Linux.
++
++
++on-line upgrade did not work on Linux.
++
++
++
++
++
++в списке файлов, выдаваемом модулем ngx_http_autoindex_module,
++не перекодировались пробелы, кавычки и знаки процента.
++
++
++the ngx_http_autoindex_module module did not escape the spaces,
++the quotes, and the percent signs in the directory listing.
++
++
++
++
++
++уменьшение операций копирования.
++
++
++the decrease of the copy operations.
++
++
++
++
++
++директива userid_p3p.
++
++
++the userid_p3p directive.
++
++
++
++
++
++
++
++
++
++
++ошибка в модуле ngx_http_autoindex_module.
++
++
++in the ngx_http_autoindex_module.
++
++
++
++
++
++
++
++
++
++
++модуль ngx_http_autoindex_module и директива autoindex.
++
++
++the ngx_http_autoindex_module and the autoindex directive.
++
++
++
++
++
++директива proxy_set_x_url.
++
++
++the proxy_set_x_url directive.
++
++
++
++
++
++модуль проксировании мог привести к зацикливанию, если не использовался
++sendfile.
++
++
++proxy module may get caught in an endless loop when sendfile is not used.
++
++
++
++
++
++
++
++
++
++
++параметры --user=USER, --group=GROUP и --with-ld-opt=OPTIONS в configure.
++
++
++the --user=USER, --group=GROUP, and --with-ld-opt=OPTIONS options in configure.
++
++
++
++
++
++директива server_name поддерживает *.domain.tld.
++
++
++the server_name directive supports *.domain.tld.
++
++
++
++
++
++улучшена переносимость на неизвестные платформы.
++
++
++the portability improvements.
++
++
++
++
++
++нельзя переконфигурировать nginx, если конфигурационный файл указан
++в командной строке;
++ошибка появилась в 0.1.1.
++
++
++if configuration file was set in command line, the reconfiguration
++was impossible;
++the bug had appeared in 0.1.1.
++
++
++
++
++
++модуль проксировании мог привести к зацикливанию, если не использовался
++sendfile.
++
++
++proxy module may get caught in an endless loop when sendfile is not used.
++
++
++
++
++
++при использовании sendfile текст ответа не перекодировался
++согласно директивам модуля charset;
++ошибка появилась в 0.1.1.
++
++
++with sendfile the response was not recoded according to the charset
++module directives;
++the bug had appeared in 0.1.1.
++
++
++
++
++
++очень редкая ошибка при обработке kqueue.
++
++
++very seldom bug in the kqueue processing.
++
++
++
++
++
++модуль сжатия сжимал уже сжатые ответы, полученные при проксировании.
++
++
++the gzip module compressed the proxied responses that was already compressed.
++
++
++
++
++
++
++
++
++
++
++директива gzip_types.
++
++
++the gzip_types directive.
++
++
++
++
++
++директива tcp_nodelay.
++
++
++the tcp_nodelay directive.
++
++
++
++
++
++директива send_lowat работает не только на платформах, поддерживающих
++kqueue NOTE_LOWAT, но и на всех, поддерживающих SO_SNDLOWAT.
++
++
++the send_lowat directive is working not only on OSes that support
++kqueue NOTE_LOWAT, but also on OSes that support SO_SNDLOWAT.
++
++
++
++
++
++эмуляция setproctitle() для Linux и Solaris.
++
++
++the setproctitle() emulation for Linux and Solaris.
++
++
++
++
++
++ошибка при переписывании заголовка "Location" при проксировании.
++
++
++the "Location" header rewrite bug fixed while the proxying.
++
++
++
++
++
++ошибка в модуле ngx_http_chunked_module, приводившая к зацикливанию.
++
++
++the ngx_http_chunked_module module may get caught in an endless loop.
++
++
++
++
++
++ошибки в модуле /dev/poll.
++
++
++the /dev/poll module bugs fixed.
++
++
++
++
++
++при проксировании и использовании временных файлов ответы портились.
++
++
++the responses were corrupted when the temporary files were used
++while the proxying.
++
++
++
++
++
++бэкенду передавались запросы с неперекодированными символами.
++
++
++the unescaped requests were passed to the backend.
++
++
++
++
++
++на Linux 2.4 при конфигурации сборки нужно было обязательно использовать
++параметр --with-poll_module.
++
++
++while the build configuration on Linux 2.4 the --with-poll_module parameter
++was required.
++
++
++
++
++
++
++
++
++
++
++Первая публично доступная версия.
++
++
++The first public version.
++
++
++
++
++
++
++
+diff -urN nginx-1.24.0/docs/xsls/changes.xsls nginx/docs/xsls/changes.xsls
+--- nginx-1.24.0/docs/xsls/changes.xsls 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/xsls/changes.xsls 2023-03-04 13:25:23.478122500 +0530
+@@ -0,0 +1,134 @@
++X:stylesheet {
++
++X:output method="text";
++
++X:param lang="'en'";
++X:param configuration="'../xml/change_log_conf.xml'";
++
++X:var conf = "document($configuration)/configuration";
++X:var start = "$conf/start";
++X:var indent = "$conf/indent";
++X:var max = "$conf/length";
++X:var br = {<br>}
++
++
++X:template = "/" { !! "change_log"; }
++X:template = "change_log" { !! "changes"; }
++
++
++X:template = "changes" {
++ X:text {
}
++
++ !{substring(concat($conf/changes[@lang=$lang]/title,
++ //change_log/@title,
++ ' ', @ver,
++ ' '),
++ 1, $conf/changes[@lang=$lang]/length)}
++
++ X:if "$lang='ru'" {
++ !{substring(@date, 9, 2)}
++ X:text {.}
++ !{substring(@date, 6, 2)}
++ X:text {.}
++ !{substring(@date, 1, 4)}
++ }
++
++ X:if "$lang='en'" {
++ !{substring(@date, 9, 2)}
++ !{$conf/changes[@lang=$lang]/month[number(substring(current()/@date,
++ 6, 2))]}
++ !{substring(@date, 1, 4)}
++ }
++
++ X:text {
}
++
++ !! "change";
++
++ X:text {
}
++}
++
++
++X:template = "change" {
++ X:var prefix = "$conf/changes[@lang=$lang]/*[local-name(.)=current()/@type]"
++
++ X:var postfix = { X:if "$prefix" { X:text {: } } }
++
++ !! "para[@lang=$lang]" (prefix = "concat($start, $prefix, $postfix)");
++}
++
++
++X:template para(prefix) = "para" {
++ X:var text = { !!; }
++
++ X:text {
}
++
++ !wrap(text = "normalize-space($text)",
++ prefix = { X:if "position() = 1" { !{$prefix} } else { !{$indent} } })
++}
++
++
++X:template wrap(text, prefix) {
++ X:if "$text" {
++ X:var offset = {
++ X:choose {
++ X:when "starts-with($text, concat($br, ' '))" {
++ !{string-length($br) + 2}
++ }
++ X:when "starts-with($text, $br)" {
++ !{string-length($br) + 1}
++ }
++ X:otherwise {
++ 1
++ }
++ }
++ }
++
++ X:var length = {
++ !length(text = "substring($text, $offset)",
++ prefix = "string-length($prefix)",
++ length = "$max")
++ }
++
++ !{$prefix}
++
++ !{normalize-space(translate(substring($text, $offset, $length),
++ ' ', ' '))}
++
++ X:text {
}
++
++ !wrap(text = "substring($text, $length + $offset)", prefix = "$indent")
++ }
++}
++
++
++X:template length(text, prefix, length) {
++ X:var break = "substring-before(substring($text, 1,
++ $length - $prefix + string-length($br)),
++ $br)"
++
++ X:choose {
++ X:when "$break" { !{string-length($break)} }
++
++ X:when "$length = 0" { !{$max - $prefix} }
++
++ X:when "string-length($text) + $prefix <= $length" {
++ !{$length - $prefix}
++ }
++
++ X:when "substring($text, $length - $prefix + 1, 1) = ' '" {
++ !{$length - $prefix + 1}
++ }
++
++ X:otherwise {
++ !length(text = "$text", prefix = "$prefix", length = "$length - 1")
++ }
++ }
++}
++
++
++X:template = "at" {@}
++X:template = "br" { !{$br} }
++X:template = "nobr" { !{translate(., ' ', ' ')} }
++
++
++}
+diff -urN nginx-1.24.0/docs/xslt/changes.xslt nginx/docs/xslt/changes.xslt
+--- nginx-1.24.0/docs/xslt/changes.xslt 1970-01-01 05:30:00.000000000 +0530
++++ nginx/docs/xslt/changes.xslt 2023-03-04 13:25:23.479171700 +0530
+@@ -0,0 +1,128 @@
++
++
++
++
++
++
++
++
++
++
++
++
++<br>
++
++
++
++
++
++
++
++
++
++
++
++
++
++ .
++
++ .
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ :
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++ 1
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++
++@
++
++
++
++
++
diff --git a/thirdparty/nginx/patches/nginx_src_event.patch b/thirdparty/nginx/patches/nginx_src_event.patch
index b790f61b1..5ec093185 100644
--- a/thirdparty/nginx/patches/nginx_src_event.patch
+++ b/thirdparty/nginx/patches/nginx_src_event.patch
@@ -1,20 +1,17 @@
diff -urN nginx/src/event/ngx_event_openssl.c nginx/src/event/ngx_event_openssl.c
---- nginx/src/event/ngx_event_openssl.c 2023-10-01 23:06:48.920736200 +0530
-+++ nginx/src/event/ngx_event_openssl.c 2023-10-01 23:19:50.724583800 +0530
-@@ -3203,9 +3203,9 @@
+--- nginx/src/event/ngx_event_openssl.c 2023-10-03 16:49:31.242377500 +0530
++++ nginx/src/event/ngx_event_openssl.c 2023-10-12 01:03:16.055868100 +0530
+@@ -3203,9 +3203,6 @@
ngx_uint_t tries;
rc = NGX_OK;
-
- ngx_ssl_ocsp_cleanup(c);
-
-+// Zimbra customizations start here (Jira Tickets: )
-+// ngx_ssl_ocsp_cleanup(c);
-+// Zimbra customizations end here
if (SSL_in_init(c->ssl->connection)) {
/*
* OpenSSL 1.0.2f complains if SSL_shutdown() is called during
-@@ -3216,6 +3216,9 @@
+@@ -3216,6 +3213,9 @@
goto done;
}
@@ -25,7 +22,7 @@ diff -urN nginx/src/event/ngx_event_openssl.c nginx/src/event/ngx_event_openssl.
mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
SSL_set_quiet_shutdown(c->ssl->connection, 1);
diff -urN nginx/src/event/ngx_event_udp.h nginx/src/event/ngx_event_udp.h
---- nginx/src/event/ngx_event_udp.h 2023-08-18 17:02:49.289936600 +0530
+--- nginx/src/event/ngx_event_udp.h 2023-10-03 16:49:31.264377900 +0530
+++ nginx/src/event/ngx_event_udp.h 2023-09-19 12:57:46.301787700 +0530
@@ -33,10 +33,11 @@
#if (NGX_HAVE_IP_PKTINFO)
From b18ba85e4ba229881c727dc712f9379f1e9d5033 Mon Sep 17 00:00:00 2001
From: Amol Suryawanshi
Date: Thu, 12 Oct 2023 14:45:51 +0530
Subject: [PATCH 12/14] ZCS-14068 : NGINX - Update review comments and
documentation
- Some review comments
---
thirdparty/nginx/zimbra-nginx/debian/patches/series | 3 ++-
thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec | 3 +++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/thirdparty/nginx/zimbra-nginx/debian/patches/series b/thirdparty/nginx/zimbra-nginx/debian/patches/series
index 7e145a7f8..1f028f9e1 100644
--- a/thirdparty/nginx/zimbra-nginx/debian/patches/series
+++ b/thirdparty/nginx/zimbra-nginx/debian/patches/series
@@ -19,4 +19,5 @@ nginx_src_mail_ngx_mail_pop3_handler.patch
nginx_src_mail_ngx_mail_pop3_module_c.patch
nginx_src_mail_ngx_mail_pop3_module_h.patch
nginx_src_mail_ngx_mail_proxy_module.patch
-nginx_src_mail_ngx_mail_smtp_module.patch
\ No newline at end of file
+nginx_src_mail_ngx_mail_smtp_module.patch
+nginx_docs.patch
\ No newline at end of file
diff --git a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
index 98e994915..42df7e7d7 100644
--- a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
+++ b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
@@ -26,6 +26,8 @@ Patch18: nginx_src_mail_ngx_mail_pop3_module_c.patch
Patch19: nginx_src_mail_ngx_mail_pop3_module_h.patch
Patch20: nginx_src_mail_ngx_mail_proxy_module.patch
Patch21: nginx_src_mail_ngx_mail_smtp_module.patch
+Patch22: nginx_docs.patch
+
BuildRequires: pcre-devel, zlib-devel
BuildRequires: zimbra-openssl-devel >= 3.0.9-1zimbra8.8b1ZAPPEND
BuildRequires: zimbra-cyrus-sasl-devel >= 2.1.28-1zimbra8.7b4ZAPPEND
@@ -106,6 +108,7 @@ The Zimbra nginx build
%patch19 -p1
%patch20 -p1
%patch21 -p1
+%patch22 -p1
%build
LDFLAGS="-Wl,-rpath,OZCL"; export LDFLAGS; \
From 26c7cdd23c7b8acc161acaa25a3397abfb579211 Mon Sep 17 00:00:00 2001
From: Umashankar Avagadda
Date: Mon, 5 Feb 2024 07:10:20 +0000
Subject: [PATCH 13/14] ZCS-11179:Updated changelog for nginx
---
thirdparty/nginx/zimbra-nginx/debian/changelog | 6 ++++++
thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec | 2 ++
2 files changed, 8 insertions(+)
diff --git a/thirdparty/nginx/zimbra-nginx/debian/changelog b/thirdparty/nginx/zimbra-nginx/debian/changelog
index 8a6c12723..7025a45ac 100644
--- a/thirdparty/nginx/zimbra-nginx/debian/changelog
+++ b/thirdparty/nginx/zimbra-nginx/debian/changelog
@@ -1,3 +1,9 @@
+zimbra-nginx (VERSION-1zimbra8.8b4ZAPPEND) unstable; urgency=medium
+
+ * Upgraded zimbra-nginx to 1.24.0
+
+ -- Zimbra Packaging Services Mon, 05 Feb 2024 05:12:55 +0000
+
zimbra-nginx (VERSION-1zimbra8.8b4ZAPPEND) unstable; urgency=medium
* ZBUG-3355, Upgraded OpenSSL to 3.0.9
diff --git a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
index 42df7e7d7..b5044e231 100644
--- a/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
+++ b/thirdparty/nginx/zimbra-nginx/rpm/SPECS/nginx.spec
@@ -41,6 +41,8 @@ URL: http://nginx.org
The Zimbra nginx build
%changelog
+* Mon Feb 05 2024 Zimbra Packaging Services - VERSION-1zimbra8.8b4ZAPPEND
+- Upgraded zimbra-nginx to 1.24.0
* Tue Jun 13 2023 Zimbra Packaging Services - VERSION-1zimbra8.8b4ZAPPEND
- ZBUG-3355, Upgraded OpenSSL to 3.0.9
* Fri May 06 2022 Zimbra Packaging Services - VERSION-1zimbra8.8b3ZAPPEND
From bfb49fa4ea1df7244a76d5652fc3d5558d7855e1 Mon Sep 17 00:00:00 2001
From: Umashankar Avagadda
Date: Mon, 5 Feb 2024 07:11:19 +0000
Subject: [PATCH 14/14] ZCS-11179:Updated proxy-components
---
.../zimbra-proxy-components/debian/changelog | 6 ++++++
.../proxy-components/zimbra-proxy-components/debian/control | 2 +-
.../zimbra-proxy-components/rpm/SPECS/proxy-components.spec | 6 ++++--
3 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/zimbra/proxy-components/zimbra-proxy-components/debian/changelog b/zimbra/proxy-components/zimbra-proxy-components/debian/changelog
index 0d32e6035..bf6565630 100644
--- a/zimbra/proxy-components/zimbra-proxy-components/debian/changelog
+++ b/zimbra/proxy-components/zimbra-proxy-components/debian/changelog
@@ -1,3 +1,9 @@
+zimbra-proxy-components (1.0.12-1zimbra8.8b1ZAPPEND) unstable; urgency=low
+
+ * Upgraded zimbra-nginx to 1.24.0
+
+ -- Zimbra Packaging Services Mon, 05 Feb 2024 05:12:55 +0000
+
zimbra-proxy-components (1.0.11-1zimbra8.8b1ZAPPEND) unstable; urgency=low
* Updated zimbra-nginx
diff --git a/zimbra/proxy-components/zimbra-proxy-components/debian/control b/zimbra/proxy-components/zimbra-proxy-components/debian/control
index 892598175..c8fee5dcf 100644
--- a/zimbra/proxy-components/zimbra-proxy-components/debian/control
+++ b/zimbra/proxy-components/zimbra-proxy-components/debian/control
@@ -8,7 +8,7 @@ Standards-Version: 3.9.5
Package: zimbra-proxy-components
Architecture: all
Depends: ${misc:Depends}, ${perl:Depends}, ${shlibs:Depends},
- zimbra-proxy-base, zimbra-nginx (>= 1.20.0-1zimbra8.8b4ZAPPEND)
+ zimbra-proxy-base, zimbra-nginx (>= 1.24.0-1zimbra8.8b4ZAPPEND)
Description: Zimbra components for proxy package
Zimbra proxy components pulls in all the packages used by
zimbra-proxy
diff --git a/zimbra/proxy-components/zimbra-proxy-components/rpm/SPECS/proxy-components.spec b/zimbra/proxy-components/zimbra-proxy-components/rpm/SPECS/proxy-components.spec
index b29c1c9b6..4d55b8772 100644
--- a/zimbra/proxy-components/zimbra-proxy-components/rpm/SPECS/proxy-components.spec
+++ b/zimbra/proxy-components/zimbra-proxy-components/rpm/SPECS/proxy-components.spec
@@ -1,9 +1,9 @@
Summary: Zimbra components for proxy package
Name: zimbra-proxy-components
-Version: 1.0.11
+Version: 1.0.12
Release: 1zimbra8.8b1ZAPPEND
License: GPL-2
-Requires: zimbra-proxy-base, zimbra-nginx >= 1.20.0-1zimbra8.8b4ZAPPEND
+Requires: zimbra-proxy-base, zimbra-nginx >= 1.24.0-1zimbra8.8b4ZAPPEND
Packager: Zimbra Packaging Services
Group: Development/Languages
AutoReqProv: no
@@ -11,6 +11,8 @@ AutoReqProv: no
%define debug_package %{nil}
%changelog
+* Mon Feb 05 2024 Zimbra Packaging Services - 1.0.12
+- Upgraded zimbra-nginx to 1.24.0
* Tue Jun 13 2023 Zimbra Packaging Services - 1.0.11
- Updated zimbra-nginx
* Fri May 06 2022 Zimbra Packaging Services - 1.0.10