Merge branch 'nginx' (nginx-1.19.3).
Change-Id: I04e2df8650ca308cd4799b106ee889863d6b9936
Signed-off-by: Piotr Sikora <piotrsikora@google.com>
diff --git a/.hgtags b/.hgtags
index edcbdac..713fa4a 100644
--- a/.hgtags
+++ b/.hgtags
@@ -452,3 +452,4 @@
cbe6ba650211541310618849168631ce0b788f35 release-1.19.0
062920e2f3bf871ef7a3d8496edec1b3065faf80 release-1.19.1
a7b46539f507e6c64efa0efda69ad60b6f4ffbce release-1.19.2
+3cbc2602325f0ac08917a4397d76f5155c34b7b1 release-1.19.3
diff --git a/BUILD b/BUILD
index 8f78db1..6350360 100644
--- a/BUILD
+++ b/BUILD
@@ -1293,6 +1293,21 @@
)
cc_library(
+ name = "stream_set",
+ srcs = [
+ "src/stream/ngx_stream_set_module.c",
+ ],
+ copts = nginx_copts,
+ defines = [
+ "NGX_STREAM_SET",
+ ],
+ deps = [
+ ":core",
+ ":stream",
+ ],
+)
+
+cc_library(
name = "stream_split_clients",
srcs = [
"src/stream/ngx_stream_split_clients_module.c",
@@ -1436,6 +1451,7 @@
":stream_map",
":stream_realip",
":stream_return",
+ ":stream_set",
":stream_split_clients",
":stream_ssl_preread",
":stream_upstream_hash",
@@ -1520,5 +1536,5 @@
preinst = "@nginx_pkgoss//:debian_preinst",
prerm = "@nginx_pkgoss//:debian_prerm",
section = "httpd",
- version = "1.19.2",
+ version = "1.19.3",
)
diff --git a/auto/modules b/auto/modules
index ac662a2..e9d2923 100644
--- a/auto/modules
+++ b/auto/modules
@@ -1119,6 +1119,16 @@
. $NGX_AUTO/module
fi
+ if [ $STREAM_SET = YES ]; then
+ ngx_module_name=ngx_stream_set_module
+ ngx_module_deps=
+ ngx_module_srcs=src/stream/ngx_stream_set_module.c
+ ngx_module_libs=
+ ngx_module_link=$STREAM_SET
+
+ . $NGX_AUTO/module
+ fi
+
if [ $STREAM_UPSTREAM_HASH = YES ]; then
ngx_module_name=ngx_stream_upstream_hash_module
ngx_module_deps=
diff --git a/auto/options b/auto/options
index ec2c5e9..2b80e64 100644
--- a/auto/options
+++ b/auto/options
@@ -124,6 +124,7 @@
STREAM_MAP=YES
STREAM_SPLIT_CLIENTS=YES
STREAM_RETURN=YES
+STREAM_SET=YES
STREAM_UPSTREAM_HASH=YES
STREAM_UPSTREAM_LEAST_CONN=YES
STREAM_UPSTREAM_RANDOM=YES
@@ -324,6 +325,7 @@
--without-stream_split_clients_module)
STREAM_SPLIT_CLIENTS=NO ;;
--without-stream_return_module) STREAM_RETURN=NO ;;
+ --without-stream_set_module) STREAM_SET=NO ;;
--without-stream_upstream_hash_module)
STREAM_UPSTREAM_HASH=NO ;;
--without-stream_upstream_least_conn_module)
@@ -538,6 +540,7 @@
--without-stream_split_clients_module
disable ngx_stream_split_clients_module
--without-stream_return_module disable ngx_stream_return_module
+ --without-stream_set_module disable ngx_stream_set_module
--without-stream_upstream_hash_module
disable ngx_stream_upstream_hash_module
--without-stream_upstream_least_conn_module
diff --git a/build.bzl b/build.bzl
index beed032..3a96e82 100644
--- a/build.bzl
+++ b/build.bzl
@@ -673,9 +673,9 @@
name = "nginx_pkgoss",
build_file_content = _PKGOSS_BUILD_FILE.format(nginx = nginx) +
_PKGOSS_BUILD_FILE_TAIL,
- commit = "d02e5c2fdd53ca365e688602851c8f89526b9404", # nginx-1.19.2
+ commit = "e2f55198a552a62e81759264645d0d3219db8611", # nginx-1.19.3
remote = "https://nginx.googlesource.com/nginx-pkgoss",
- shallow_since = "1597157447 +0300",
+ shallow_since = "1601388760 +0300",
)
def nginx_repositories_zlib(bind):
diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml
index 2106c87..976c9de 100644
--- a/docs/xml/nginx/changes.xml
+++ b/docs/xml/nginx/changes.xml
@@ -5,6 +5,112 @@
<change_log title="nginx">
+<changes ver="1.19.3" date="2020-09-29">
+
+<change type="feature">
+<para lang="ru">
+модуль ngx_stream_set_module.
+</para>
+<para lang="en">
+the ngx_stream_set_module.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива proxy_cookie_flags.
+</para>
+<para lang="en">
+the "proxy_cookie_flags" directive.
+</para>
+</change>
+
+<change type="feature">
+<para lang="ru">
+директива userid_flags.
+</para>
+<para lang="en">
+the "userid_flags" directive.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+расширение управления кэшированием stale-if-error
+ошибочно применялось, если бэкенд возвращал ответ
+с кодом 500, 502, 503, 504, 403, 404 или 429.
+</para>
+<para lang="en">
+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.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+если использовалось кэширование
+и бэкенд возвращал ответы с строкой заголовка Vary,
+в логах могли появляться сообщения "[crit] cache file ... has too long header".
+</para>
+<para lang="en">
+"[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.
+</para>
+</change>
+
+<change type="workaround">
+<para lang="ru">
+при использовании OpenSSL 1.1.1
+в логах могли появляться сообщения "[crit] SSL_write() failed".
+</para>
+<para lang="en">
+"[crit] SSL_write() failed" messages might appear in logs
+when using OpenSSL 1.1.1.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+в логах могли появляться сообщения
+"SSL_shutdown() failed (SSL: ... bad write retry)";
+ошибка появилась в 1.19.2.
+</para>
+<para lang="en">
+"SSL_shutdown() failed (SSL: ... bad write retry)"
+messages might appear in logs;
+the bug had appeared in 1.19.2.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+при использовании HTTP/2
+в рабочем процессе мог произойти segmentation fault,
+если ошибки с кодом 400 с помощью директивы error_page
+перенаправлялись в проксируемый location.
+</para>
+<para lang="en">
+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.
+</para>
+</change>
+
+<change type="bugfix">
+<para lang="ru">
+утечки сокетов при использовании HTTP/2 и подзапросов в модуле njs.
+</para>
+<para lang="en">
+socket leak when using HTTP/2 and subrequests in the njs module.
+</para>
+</change>
+
+</changes>
+
+
<changes ver="1.19.2" date="2020-08-11">
<change type="change">
diff --git a/misc/GNUmakefile b/misc/GNUmakefile
index 4582e44..80eb9b9 100644
--- a/misc/GNUmakefile
+++ b/misc/GNUmakefile
@@ -6,7 +6,7 @@
CC = cl
OBJS = objs.msvc8
-OPENSSL = openssl-1.1.1g
+OPENSSL = openssl-1.1.1h
ZLIB = zlib-1.2.11
PCRE = pcre-8.44
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 1720d9e..0964302 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -13,8 +13,8 @@
#define NGINX_NAME "nginx"
#endif
-#define nginx_version 1019002
-#define NGINX_VERSION "1.19.2"
+#define nginx_version 1019003
+#define NGINX_VERSION "1.19.3"
#define NGINX_VER NGINX_NAME "/" NGINX_VERSION
#ifdef NGX_BUILD
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index e51712c..5b716ee 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1918,7 +1918,7 @@
if (rn == NULL) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
+ "unexpected DNS response for %V", &name);
ngx_resolver_free(r, name.data);
goto failed;
}
@@ -1930,7 +1930,7 @@
if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
+ "unexpected DNS response for %V", &name);
ngx_resolver_free(r, name.data);
goto failed;
}
@@ -1949,7 +1949,7 @@
if (rn->query == NULL || rn->naddrs != (u_short) -1) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
+ "unexpected DNS response for %V", &name);
ngx_resolver_free(r, name.data);
goto failed;
}
@@ -1964,7 +1964,7 @@
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %V, expect %ui",
+ "wrong ident %ui in DNS response for %V, expect %ui",
ident, &name, qident);
ngx_resolver_free(r, name.data);
goto failed;
@@ -2149,7 +2149,7 @@
if (class != 1) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR class %ui", class);
+ "unexpected RR class %ui in DNS response", class);
goto failed;
}
@@ -2218,7 +2218,7 @@
default:
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR type %ui", type);
+ "unexpected RR type %ui in DNS response", type);
}
i += len;
@@ -2567,7 +2567,7 @@
if (rn == NULL || rn->query == NULL) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
+ "unexpected DNS response for %V", &name);
ngx_resolver_free(r, name.data);
goto failed;
}
@@ -2581,7 +2581,7 @@
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %V, expect %ui",
+ "wrong ident %ui in DNS response for %V, expect %ui",
ident, &name, qident);
ngx_resolver_free(r, name.data);
goto failed;
@@ -2691,7 +2691,7 @@
if (class != 1) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR class %ui", class);
+ "unexpected RR class %ui in DNS response", class);
goto failed;
}
@@ -2734,7 +2734,7 @@
default:
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR type %ui", type);
+ "unexpected RR type %ui in DNS response", type);
}
i += len;
@@ -3165,7 +3165,7 @@
if (rn == NULL || rn->query == NULL) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected response for %V", &name);
+ "unexpected DNS response for %V", &name);
ngx_resolver_free(r, name.data);
goto failed;
}
@@ -3174,7 +3174,7 @@
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
- "wrong ident %ui response for %V, expect %ui",
+ "wrong ident %ui in DNS response for %V, expect %ui",
ident, &name, qident);
ngx_resolver_free(r, name.data);
goto failed;
@@ -3256,7 +3256,7 @@
if (class != 1) {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR class %ui", class);
+ "unexpected RR class %ui in DNS response", class);
goto failed;
}
@@ -3283,7 +3283,7 @@
default:
ngx_log_error(r->log_level, r->log, 0,
- "unexpected RR type %ui", type);
+ "unexpected RR type %ui in DNS response", type);
}
i += len;
@@ -3952,12 +3952,12 @@
}
if (p >= last) {
- err = "name is out of response";
+ err = "name is out of DNS response";
goto invalid;
}
}
- err = "compression pointers loop";
+ err = "compression pointers loop in DNS response";
invalid:
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 9bf976a..c186b9b 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -2596,6 +2596,18 @@
sslerr = SSL_get_error(c->ssl->connection, n);
+ if (sslerr == SSL_ERROR_ZERO_RETURN) {
+
+ /*
+ * OpenSSL 1.1.1 fails to return SSL_ERROR_SYSCALL if an error
+ * happens during SSL_write() after close_notify alert from the
+ * peer, and returns SSL_ERROR_ZERO_RETURN instead,
+ * https://git.openssl.org/?p=openssl.git;a=commitdiff;h=8051ab2
+ */
+
+ sslerr = SSL_ERROR_SYSCALL;
+ }
+
err = (sslerr == SSL_ERROR_SYSCALL) ? ngx_errno : 0;
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d", sslerr);
@@ -2816,7 +2828,7 @@
return NGX_OK;
}
- if (c->timedout) {
+ if (c->timedout || c->error || c->buffered) {
mode = SSL_RECEIVED_SHUTDOWN|SSL_SENT_SHUTDOWN;
SSL_set_quiet_shutdown(c->ssl->connection, 1);
@@ -2876,6 +2888,13 @@
c->read->handler = ngx_ssl_shutdown_handler;
c->write->handler = ngx_ssl_shutdown_handler;
+ if (sslerr == SSL_ERROR_WANT_READ) {
+ c->read->ready = 0;
+
+ } else {
+ c->write->ready = 0;
+ }
+
if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
return NGX_ERROR;
}
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 68ad6d3..64393dc 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -10,6 +10,19 @@
#include <ngx_http.h>
+#define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001
+#define NGX_HTTP_PROXY_COOKIE_SECURE_ON 0x0002
+#define NGX_HTTP_PROXY_COOKIE_SECURE_OFF 0x0004
+#define NGX_HTTP_PROXY_COOKIE_HTTPONLY 0x0008
+#define NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON 0x0010
+#define NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF 0x0020
+#define NGX_HTTP_PROXY_COOKIE_SAMESITE 0x0040
+#define NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT 0x0080
+#define NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX 0x0100
+#define NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE 0x0200
+#define NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF 0x0400
+
+
typedef struct {
ngx_array_t caches; /* ngx_http_file_cache_t * */
} ngx_http_proxy_main_conf_t;
@@ -18,7 +31,7 @@
typedef struct ngx_http_proxy_rewrite_s ngx_http_proxy_rewrite_t;
typedef ngx_int_t (*ngx_http_proxy_rewrite_pt)(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix, size_t len,
+ ngx_str_t *value, size_t prefix, size_t len,
ngx_http_proxy_rewrite_t *pr);
struct ngx_http_proxy_rewrite_s {
@@ -36,6 +49,19 @@
typedef struct {
+ union {
+ ngx_http_complex_value_t complex;
+#if (NGX_PCRE)
+ ngx_http_regex_t *regex;
+#endif
+ } cookie;
+
+ ngx_uint_t flags;
+ ngx_uint_t regex;
+} ngx_http_proxy_cookie_flags_t;
+
+
+typedef struct {
ngx_str_t key_start;
ngx_str_t schema;
ngx_str_t host_header;
@@ -72,6 +98,7 @@
ngx_array_t *redirects;
ngx_array_t *cookie_domains;
ngx_array_t *cookie_paths;
+ ngx_array_t *cookie_flags;
ngx_http_complex_value_t *method;
ngx_str_t location;
@@ -158,10 +185,16 @@
ngx_table_elt_t *h, size_t prefix);
static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r,
ngx_table_elt_t *h);
+static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value,
+ ngx_array_t *attrs);
static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r,
- ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites);
+ ngx_str_t *value, ngx_array_t *rewrites);
+static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r,
+ ngx_array_t *attrs, ngx_array_t *flags);
+static ngx_int_t ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r,
+ ngx_array_t *attrs, ngx_uint_t flags);
static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix, size_t len, ngx_str_t *replacement);
+ ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement);
static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf);
static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf);
@@ -180,6 +213,8 @@
void *conf);
static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
#if (NGX_HTTP_CACHE)
@@ -282,6 +317,13 @@
0,
NULL },
+ { ngx_string("proxy_cookie_flags"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234,
+ ngx_http_proxy_cookie_flags,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("proxy_store"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_proxy_store,
@@ -852,6 +894,36 @@
};
+static ngx_conf_bitmask_t ngx_http_proxy_cookie_flags_masks[] = {
+
+ { ngx_string("secure"),
+ NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_ON },
+
+ { ngx_string("nosecure"),
+ NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_OFF },
+
+ { ngx_string("httponly"),
+ NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON },
+
+ { ngx_string("nohttponly"),
+ NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF },
+
+ { ngx_string("samesite=strict"),
+ NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT },
+
+ { ngx_string("samesite=lax"),
+ NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX },
+
+ { ngx_string("samesite=none"),
+ NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE },
+
+ { ngx_string("nosamesite"),
+ NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF },
+
+ { ngx_null_string, 0 }
+};
+
+
static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t *r)
{
@@ -913,7 +985,7 @@
u->rewrite_redirect = ngx_http_proxy_rewrite_redirect;
}
- if (plcf->cookie_domains || plcf->cookie_paths) {
+ if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) {
u->rewrite_cookie = ngx_http_proxy_rewrite_cookie;
}
@@ -2591,7 +2663,7 @@
len = h->value.len - prefix;
for (i = 0; i < plcf->redirects->nelts; i++) {
- rc = pr[i].handler(r, h, prefix, len, &pr[i]);
+ rc = pr[i].handler(r, &h->value, prefix, len, &pr[i]);
if (rc != NGX_DECLINED) {
return rc;
@@ -2605,27 +2677,43 @@
static ngx_int_t
ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h)
{
- size_t prefix;
u_char *p;
+ size_t len;
ngx_int_t rc, rv;
+ ngx_str_t *key, *value;
+ ngx_uint_t i;
+ ngx_array_t attrs;
+ ngx_keyval_t *attr;
ngx_http_proxy_loc_conf_t *plcf;
- p = (u_char *) ngx_strchr(h->value.data, ';');
- if (p == NULL) {
- return NGX_DECLINED;
+ if (ngx_array_init(&attrs, r->pool, 2, sizeof(ngx_keyval_t)) != NGX_OK) {
+ return NGX_ERROR;
}
- prefix = p + 1 - h->value.data;
+ if (ngx_http_proxy_parse_cookie(&h->value, &attrs) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ attr = attrs.elts;
+
+ if (attr[0].value.data == NULL) {
+ return NGX_DECLINED;
+ }
rv = NGX_DECLINED;
plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module);
- if (plcf->cookie_domains) {
- p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1);
+ for (i = 1; i < attrs.nelts; i++) {
- if (p) {
- rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7,
+ key = &attr[i].key;
+ value = &attr[i].value;
+
+ if (plcf->cookie_domains && key->len == 6
+ && ngx_strncasecmp(key->data, (u_char *) "domain", 6) == 0
+ && value->data)
+ {
+ rc = ngx_http_proxy_rewrite_cookie_value(r, value,
plcf->cookie_domains);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -2635,13 +2723,12 @@
rv = rc;
}
}
- }
- if (plcf->cookie_paths) {
- p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1);
-
- if (p) {
- rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5,
+ if (plcf->cookie_paths && key->len == 4
+ && ngx_strncasecmp(key->data, (u_char *) "path", 4) == 0
+ && value->data)
+ {
+ rc = ngx_http_proxy_rewrite_cookie_value(r, value,
plcf->cookie_paths);
if (rc == NGX_ERROR) {
return NGX_ERROR;
@@ -2653,30 +2740,153 @@
}
}
- return rv;
+ if (plcf->cookie_flags) {
+ rc = ngx_http_proxy_rewrite_cookie_flags(r, &attrs,
+ plcf->cookie_flags);
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc != NGX_DECLINED) {
+ rv = rc;
+ }
+
+ attr = attrs.elts;
+ }
+
+ if (rv != NGX_OK) {
+ return rv;
+ }
+
+ len = 0;
+
+ for (i = 0; i < attrs.nelts; i++) {
+
+ if (attr[i].key.data == NULL) {
+ continue;
+ }
+
+ if (i > 0) {
+ len += 2;
+ }
+
+ len += attr[i].key.len;
+
+ if (attr[i].value.data) {
+ len += 1 + attr[i].value.len;
+ }
+ }
+
+ p = ngx_pnalloc(r->pool, len + 1);
+ if (p == NULL) {
+ return NGX_ERROR;
+ }
+
+ h->value.data = p;
+ h->value.len = len;
+
+ for (i = 0; i < attrs.nelts; i++) {
+
+ if (attr[i].key.data == NULL) {
+ continue;
+ }
+
+ if (i > 0) {
+ *p++ = ';';
+ *p++ = ' ';
+ }
+
+ p = ngx_cpymem(p, attr[i].key.data, attr[i].key.len);
+
+ if (attr[i].value.data) {
+ *p++ = '=';
+ p = ngx_cpymem(p, attr[i].value.data, attr[i].value.len);
+ }
+ }
+
+ *p = '\0';
+
+ return NGX_OK;
}
static ngx_int_t
-ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h,
- u_char *value, ngx_array_t *rewrites)
+ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs)
{
- size_t len, prefix;
- u_char *p;
+ u_char *start, *end, *p, *last;
+ ngx_str_t name, val;
+ ngx_keyval_t *attr;
+
+ start = value->data;
+ end = value->data + value->len;
+
+ for ( ;; ) {
+
+ last = (u_char *) ngx_strchr(start, ';');
+
+ if (last == NULL) {
+ last = end;
+ }
+
+ while (start < last && *start == ' ') { start++; }
+
+ for (p = start; p < last && *p != '='; p++) { /* void */ }
+
+ name.data = start;
+ name.len = p - start;
+
+ while (name.len && name.data[name.len - 1] == ' ') {
+ name.len--;
+ }
+
+ if (p < last) {
+
+ p++;
+
+ while (p < last && *p == ' ') { p++; }
+
+ val.data = p;
+ val.len = last - val.data;
+
+ while (val.len && val.data[val.len - 1] == ' ') {
+ val.len--;
+ }
+
+ } else {
+ ngx_str_null(&val);
+ }
+
+ attr = ngx_array_push(attrs);
+ if (attr == NULL) {
+ return NGX_ERROR;
+ }
+
+ attr->key = name;
+ attr->value = val;
+
+ if (last == end) {
+ break;
+ }
+
+ start = last + 1;
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_str_t *value,
+ ngx_array_t *rewrites)
+{
ngx_int_t rc;
ngx_uint_t i;
ngx_http_proxy_rewrite_t *pr;
- prefix = value - h->value.data;
-
- p = (u_char *) ngx_strchr(value, ';');
-
- len = p ? (size_t) (p - value) : (h->value.len - prefix);
-
pr = rewrites->elts;
for (i = 0; i < rewrites->nelts; i++) {
- rc = pr[i].handler(r, h, prefix, len, &pr[i]);
+ rc = pr[i].handler(r, value, 0, value->len, &pr[i]);
if (rc != NGX_DECLINED) {
return rc;
@@ -2688,8 +2898,194 @@
static ngx_int_t
-ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
+ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs,
+ ngx_array_t *flags)
+{
+ ngx_str_t pattern;
+#if (NGX_PCRE)
+ ngx_int_t rc;
+#endif
+ ngx_uint_t i;
+ ngx_keyval_t *attr;
+ ngx_http_proxy_cookie_flags_t *pcf;
+
+ attr = attrs->elts;
+ pcf = flags->elts;
+
+ for (i = 0; i < flags->nelts; i++) {
+
+#if (NGX_PCRE)
+ if (pcf[i].regex) {
+ rc = ngx_http_regex_exec(r, pcf[i].cookie.regex, &attr[0].key);
+
+ if (rc == NGX_ERROR) {
+ return NGX_ERROR;
+ }
+
+ if (rc == NGX_OK) {
+ break;
+ }
+
+ /* NGX_DECLINED */
+
+ continue;
+ }
+#endif
+
+ if (ngx_http_complex_value(r, &pcf[i].cookie.complex, &pattern)
+ != NGX_OK)
+ {
+ return NGX_ERROR;
+ }
+
+ if (pattern.len == attr[0].key.len
+ && ngx_strncasecmp(attr[0].key.data, pattern.data, pattern.len)
+ == 0)
+ {
+ break;
+ }
+ }
+
+ if (i == flags->nelts) {
+ return NGX_DECLINED;
+ }
+
+ return ngx_http_proxy_edit_cookie_flags(r, attrs, pcf[i].flags);
+}
+
+
+static ngx_int_t
+ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs,
+ ngx_uint_t flags)
+{
+ ngx_str_t *key, *value;
+ ngx_uint_t i;
+ ngx_keyval_t *attr;
+
+ attr = attrs->elts;
+
+ for (i = 1; i < attrs->nelts; i++) {
+ key = &attr[i].key;
+
+ if (key->len == 6
+ && ngx_strncasecmp(key->data, (u_char *) "secure", 6) == 0)
+ {
+ if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) {
+ flags &= ~NGX_HTTP_PROXY_COOKIE_SECURE_ON;
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_OFF) {
+ key->data = NULL;
+ }
+
+ continue;
+ }
+
+ if (key->len == 8
+ && ngx_strncasecmp(key->data, (u_char *) "httponly", 8) == 0)
+ {
+ if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) {
+ flags &= ~NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON;
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF) {
+ key->data = NULL;
+ }
+
+ continue;
+ }
+
+ if (key->len == 8
+ && ngx_strncasecmp(key->data, (u_char *) "samesite", 8) == 0)
+ {
+ value = &attr[i].value;
+
+ if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) {
+ flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT;
+
+ if (value->len != 6
+ || ngx_strncasecmp(value->data, (u_char *) "strict", 6)
+ != 0)
+ {
+ ngx_str_set(key, "SameSite");
+ ngx_str_set(value, "Strict");
+ }
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) {
+ flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX;
+
+ if (value->len != 3
+ || ngx_strncasecmp(value->data, (u_char *) "lax", 3) != 0)
+ {
+ ngx_str_set(key, "SameSite");
+ ngx_str_set(value, "Lax");
+ }
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE) {
+ flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE;
+
+ if (value->len != 4
+ || ngx_strncasecmp(value->data, (u_char *) "none", 4) != 0)
+ {
+ ngx_str_set(key, "SameSite");
+ ngx_str_set(value, "None");
+ }
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF) {
+ key->data = NULL;
+ }
+
+ continue;
+ }
+ }
+
+ if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) {
+ attr = ngx_array_push(attrs);
+ if (attr == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_str_set(&attr->key, "Secure");
+ ngx_str_null(&attr->value);
+ }
+
+ if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) {
+ attr = ngx_array_push(attrs);
+ if (attr == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_str_set(&attr->key, "HttpOnly");
+ ngx_str_null(&attr->value);
+ }
+
+ if (flags & (NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT
+ |NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX
+ |NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE))
+ {
+ attr = ngx_array_push(attrs);
+ if (attr == NULL) {
+ return NGX_ERROR;
+ }
+
+ ngx_str_set(&attr->key, "SameSite");
+
+ if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) {
+ ngx_str_set(&attr->value, "Strict");
+
+ } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) {
+ ngx_str_set(&attr->value, "Lax");
+
+ } else {
+ ngx_str_set(&attr->value, "None");
+ }
+ }
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value,
+ size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
{
ngx_str_t pattern, replacement;
@@ -2698,8 +3094,7 @@
}
if (pattern.len > len
- || ngx_rstrncmp(h->value.data + prefix, pattern.data,
- pattern.len) != 0)
+ || ngx_rstrncmp(value->data + prefix, pattern.data, pattern.len) != 0)
{
return NGX_DECLINED;
}
@@ -2708,20 +3103,20 @@
return NGX_ERROR;
}
- return ngx_http_proxy_rewrite(r, h, prefix, pattern.len, &replacement);
+ return ngx_http_proxy_rewrite(r, value, prefix, pattern.len, &replacement);
}
#if (NGX_PCRE)
static ngx_int_t
-ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_table_elt_t *h,
+ngx_http_proxy_rewrite_regex_handler(ngx_http_request_t *r, ngx_str_t *value,
size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
{
ngx_str_t pattern, replacement;
pattern.len = len;
- pattern.data = h->value.data + prefix;
+ pattern.data = value->data + prefix;
if (ngx_http_regex_exec(r, pr->pattern.regex, &pattern) != NGX_OK) {
return NGX_DECLINED;
@@ -2731,20 +3126,15 @@
return NGX_ERROR;
}
- if (prefix == 0 && h->value.len == len) {
- h->value = replacement;
- return NGX_OK;
- }
-
- return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
+ return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement);
}
#endif
static ngx_int_t
-ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r,
- ngx_table_elt_t *h, size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
+ngx_http_proxy_rewrite_domain_handler(ngx_http_request_t *r, ngx_str_t *value,
+ size_t prefix, size_t len, ngx_http_proxy_rewrite_t *pr)
{
u_char *p;
ngx_str_t pattern, replacement;
@@ -2753,9 +3143,9 @@
return NGX_ERROR;
}
- p = h->value.data + prefix;
+ p = value->data + prefix;
- if (p[0] == '.') {
+ if (len && p[0] == '.') {
p++;
prefix++;
len--;
@@ -2769,18 +3159,23 @@
return NGX_ERROR;
}
- return ngx_http_proxy_rewrite(r, h, prefix, len, &replacement);
+ return ngx_http_proxy_rewrite(r, value, prefix, len, &replacement);
}
static ngx_int_t
-ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_table_elt_t *h, size_t prefix,
+ngx_http_proxy_rewrite(ngx_http_request_t *r, ngx_str_t *value, size_t prefix,
size_t len, ngx_str_t *replacement)
{
u_char *p, *data;
size_t new_len;
- new_len = replacement->len + h->value.len - len;
+ if (len == value->len) {
+ *value = *replacement;
+ return NGX_OK;
+ }
+
+ new_len = replacement->len + value->len - len;
if (replacement->len > len) {
@@ -2789,23 +3184,22 @@
return NGX_ERROR;
}
- p = ngx_copy(data, h->value.data, prefix);
+ p = ngx_copy(data, value->data, prefix);
p = ngx_copy(p, replacement->data, replacement->len);
- ngx_memcpy(p, h->value.data + prefix + len,
- h->value.len - len - prefix + 1);
+ ngx_memcpy(p, value->data + prefix + len,
+ value->len - len - prefix + 1);
- h->value.data = data;
+ value->data = data;
} else {
- p = ngx_copy(h->value.data + prefix, replacement->data,
- replacement->len);
+ p = ngx_copy(value->data + prefix, replacement->data, replacement->len);
- ngx_memmove(p, h->value.data + prefix + len,
- h->value.len - len - prefix + 1);
+ ngx_memmove(p, value->data + prefix + len,
+ value->len - len - prefix + 1);
}
- h->value.len = new_len;
+ value->len = new_len;
return NGX_OK;
}
@@ -2965,6 +3359,7 @@
conf->cookie_domains = NGX_CONF_UNSET_PTR;
conf->cookie_paths = NGX_CONF_UNSET_PTR;
+ conf->cookie_flags = NGX_CONF_UNSET_PTR;
conf->http_version = NGX_CONF_UNSET_UINT;
@@ -3362,6 +3757,8 @@
ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL);
+ ngx_conf_merge_ptr_value(conf->cookie_flags, prev->cookie_flags, NULL);
+
ngx_conf_merge_uint_value(conf->http_version, prev->http_version,
NGX_HTTP_VERSION_10);
@@ -3796,7 +4193,7 @@
ngx_http_compile_complex_value_t ccv;
if (plcf->redirect == 0) {
- return NGX_CONF_OK;
+ return "is duplicate";
}
plcf->redirect = 1;
@@ -3805,16 +4202,12 @@
if (cf->args->nelts == 2) {
if (ngx_strcmp(value[1].data, "off") == 0) {
- plcf->redirect = 0;
- plcf->redirects = NULL;
- return NGX_CONF_OK;
- }
- if (ngx_strcmp(value[1].data, "false") == 0) {
- ngx_conf_log_error(NGX_LOG_ERR, cf, 0,
- "invalid parameter \"false\", use \"off\" instead");
+ if (plcf->redirects) {
+ return "is duplicate";
+ }
+
plcf->redirect = 0;
- plcf->redirects = NULL;
return NGX_CONF_OK;
}
@@ -3838,7 +4231,9 @@
return NGX_CONF_ERROR;
}
- if (ngx_strcmp(value[1].data, "default") == 0) {
+ if (cf->args->nelts == 2
+ && ngx_strcmp(value[1].data, "default") == 0)
+ {
if (plcf->proxy_lengths) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_redirect default\" cannot be used "
@@ -3941,7 +4336,7 @@
ngx_http_compile_complex_value_t ccv;
if (plcf->cookie_domains == NULL) {
- return NGX_CONF_OK;
+ return "is duplicate";
}
value = cf->args->elts;
@@ -3949,6 +4344,11 @@
if (cf->args->nelts == 2) {
if (ngx_strcmp(value[1].data, "off") == 0) {
+
+ if (plcf->cookie_domains != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
plcf->cookie_domains = NULL;
return NGX_CONF_OK;
}
@@ -4028,7 +4428,7 @@
ngx_http_compile_complex_value_t ccv;
if (plcf->cookie_paths == NULL) {
- return NGX_CONF_OK;
+ return "is duplicate";
}
value = cf->args->elts;
@@ -4036,6 +4436,11 @@
if (cf->args->nelts == 2) {
if (ngx_strcmp(value[1].data, "off") == 0) {
+
+ if (plcf->cookie_paths != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
plcf->cookie_paths = NULL;
return NGX_CONF_OK;
}
@@ -4105,6 +4510,131 @@
}
+static char *
+ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_proxy_loc_conf_t *plcf = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t i, m;
+ ngx_conf_bitmask_t *mask;
+ ngx_http_proxy_cookie_flags_t *pcf;
+ ngx_http_compile_complex_value_t ccv;
+#if (NGX_PCRE)
+ ngx_regex_compile_t rc;
+ u_char errstr[NGX_MAX_CONF_ERRSTR];
+#endif
+
+ if (plcf->cookie_flags == NULL) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ if (cf->args->nelts == 2) {
+
+ if (ngx_strcmp(value[1].data, "off") == 0) {
+
+ if (plcf->cookie_flags != NGX_CONF_UNSET_PTR) {
+ return "is duplicate";
+ }
+
+ plcf->cookie_flags = NULL;
+ return NGX_CONF_OK;
+ }
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ if (plcf->cookie_flags == NGX_CONF_UNSET_PTR) {
+ plcf->cookie_flags = ngx_array_create(cf->pool, 1,
+ sizeof(ngx_http_proxy_cookie_flags_t));
+ if (plcf->cookie_flags == NULL) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ pcf = ngx_array_push(plcf->cookie_flags);
+ if (pcf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pcf->regex = 0;
+
+ if (value[1].data[0] == '~') {
+ value[1].len--;
+ value[1].data++;
+
+#if (NGX_PCRE)
+ ngx_memzero(&rc, sizeof(ngx_regex_compile_t));
+
+ rc.pattern = value[1];
+ rc.err.len = NGX_MAX_CONF_ERRSTR;
+ rc.err.data = errstr;
+ rc.options = NGX_REGEX_CASELESS;
+
+ pcf->cookie.regex = ngx_http_regex_compile(cf, &rc);
+ if (pcf->cookie.regex == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ pcf->regex = 1;
+#else
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "using regex \"%V\" requires PCRE library",
+ &value[1]);
+ return NGX_CONF_ERROR;
+#endif
+
+ } else {
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = &pcf->cookie.complex;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ mask = ngx_http_proxy_cookie_flags_masks;
+ pcf->flags = 0;
+
+ for (i = 2; i < cf->args->nelts; i++) {
+ for (m = 0; mask[m].name.len != 0; m++) {
+
+ if (mask[m].name.len != value[i].len
+ || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0)
+ {
+ continue;
+ }
+
+ if (pcf->flags & mask[m].mask) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "duplicate parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+
+ pcf->flags |= mask[m].mask;
+
+ break;
+ }
+
+ if (mask[m].name.len == 0) {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter \"%V\"", &value[i]);
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
static ngx_int_t
ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr,
ngx_str_t *regex, ngx_uint_t caseless)
diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c
index 31cf402..1e33c5c 100644
--- a/src/http/modules/ngx_http_userid_filter_module.c
+++ b/src/http/modules/ngx_http_userid_filter_module.c
@@ -15,12 +15,21 @@
#define NGX_HTTP_USERID_V1 2
#define NGX_HTTP_USERID_ON 3
+#define NGX_HTTP_USERID_COOKIE_OFF 0x0002
+#define NGX_HTTP_USERID_COOKIE_SECURE 0x0004
+#define NGX_HTTP_USERID_COOKIE_HTTPONLY 0x0008
+#define NGX_HTTP_USERID_COOKIE_SAMESITE 0x0010
+#define NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT 0x0020
+#define NGX_HTTP_USERID_COOKIE_SAMESITE_LAX 0x0040
+#define NGX_HTTP_USERID_COOKIE_SAMESITE_NONE 0x0080
+
/* 31 Dec 2037 23:55:55 GMT */
#define NGX_HTTP_USERID_MAX_EXPIRES 2145916555
typedef struct {
ngx_uint_t enable;
+ ngx_uint_t flags;
ngx_int_t service;
@@ -88,6 +97,20 @@
};
+static ngx_conf_bitmask_t ngx_http_userid_flags[] = {
+ { ngx_string("off"), NGX_HTTP_USERID_COOKIE_OFF },
+ { ngx_string("secure"), NGX_HTTP_USERID_COOKIE_SECURE },
+ { ngx_string("httponly"), NGX_HTTP_USERID_COOKIE_HTTPONLY },
+ { ngx_string("samesite=strict"),
+ NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT },
+ { ngx_string("samesite=lax"),
+ NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_LAX },
+ { ngx_string("samesite=none"),
+ NGX_HTTP_USERID_COOKIE_SAMESITE|NGX_HTTP_USERID_COOKIE_SAMESITE_NONE },
+ { ngx_null_string, 0 }
+};
+
+
static ngx_conf_post_handler_pt ngx_http_userid_domain_p =
ngx_http_userid_domain;
static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path;
@@ -138,6 +161,13 @@
0,
NULL },
+ { ngx_string("userid_flags"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+ ngx_conf_set_bitmask_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_userid_conf_t, flags),
+ &ngx_http_userid_flags },
+
{ ngx_string("userid_p3p"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
@@ -383,6 +413,26 @@
len += conf->domain.len;
}
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SECURE) {
+ len += sizeof("; secure") - 1;
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_HTTPONLY) {
+ len += sizeof("; httponly") - 1;
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT) {
+ len += sizeof("; samesite=strict") - 1;
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_LAX) {
+ len += sizeof("; samesite=lax") - 1;
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_NONE) {
+ len += sizeof("; samesite=none") - 1;
+ }
+
cookie = ngx_pnalloc(r->pool, len);
if (cookie == NULL) {
return NGX_ERROR;
@@ -422,6 +472,26 @@
p = ngx_copy(p, conf->path.data, conf->path.len);
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SECURE) {
+ p = ngx_cpymem(p, "; secure", sizeof("; secure") - 1);
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_HTTPONLY) {
+ p = ngx_cpymem(p, "; httponly", sizeof("; httponly") - 1);
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_STRICT) {
+ p = ngx_cpymem(p, "; samesite=strict", sizeof("; samesite=strict") - 1);
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_LAX) {
+ p = ngx_cpymem(p, "; samesite=lax", sizeof("; samesite=lax") - 1);
+ }
+
+ if (conf->flags & NGX_HTTP_USERID_COOKIE_SAMESITE_NONE) {
+ p = ngx_cpymem(p, "; samesite=none", sizeof("; samesite=none") - 1);
+ }
+
set_cookie = ngx_list_push(&r->headers_out.headers);
if (set_cookie == NULL) {
return NGX_ERROR;
@@ -658,6 +728,7 @@
/*
* set by ngx_pcalloc():
*
+ * conf->flags = 0;
* conf->name = { 0, NULL };
* conf->domain = { 0, NULL };
* conf->path = { 0, NULL };
@@ -682,6 +753,9 @@
ngx_conf_merge_uint_value(conf->enable, prev->enable,
NGX_HTTP_USERID_OFF);
+ ngx_conf_merge_bitmask_value(conf->flags, prev->flags,
+ (NGX_CONF_BITMASK_SET|NGX_HTTP_USERID_COOKIE_OFF));
+
ngx_conf_merge_str_value(conf->name, prev->name, "uid");
ngx_conf_merge_str_value(conf->domain, prev->domain, "");
ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
diff --git a/src/http/ngx_http_cache.h b/src/http/ngx_http_cache.h
index cd0b4bb..bb936c5 100644
--- a/src/http/ngx_http_cache.h
+++ b/src/http/ngx_http_cache.h
@@ -80,6 +80,7 @@
ngx_str_t vary;
u_char variant[NGX_HTTP_CACHE_KEY_LEN];
+ size_t buffer_size;
size_t header_start;
size_t body_start;
off_t length;
@@ -116,6 +117,7 @@
unsigned purged:1;
unsigned reading:1;
unsigned secondary:1;
+ unsigned update_variant:1;
unsigned background:1;
unsigned stale_updating:1;
diff --git a/src/http/ngx_http_file_cache.c b/src/http/ngx_http_file_cache.c
index e985f27..c40093b 100644
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -294,6 +294,8 @@
cln->data = c;
}
+ c->buffer_size = c->body_start;
+
rc = ngx_http_file_cache_exists(cache, c);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -852,7 +854,7 @@
if (fcn->exists || fcn->uses >= c->min_uses) {
c->exists = fcn->exists;
- if (fcn->body_start) {
+ if (fcn->body_start && !c->update_variant) {
c->body_start = fcn->body_start;
}
@@ -1230,7 +1232,7 @@
c->secondary = 1;
c->file.name.len = 0;
- c->body_start = c->buf->end - c->buf->start;
+ c->body_start = c->buffer_size;
ngx_memcpy(c->key, c->variant, NGX_HTTP_CACHE_KEY_LEN);
@@ -1337,6 +1339,7 @@
ngx_shmtx_unlock(&cache->shpool->mutex);
c->file.name.len = 0;
+ c->update_variant = 1;
ngx_memcpy(c->key, c->main, NGX_HTTP_CACHE_KEY_LEN);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index e8dbb03..0c8104b 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -1087,7 +1087,10 @@
c->ssl->buffer_size = sscf->buffer_size;
if (sscf->ssl.ctx && sscf->ssl.ctx != SSL_get_SSL_CTX(ssl_conn)) {
- SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
+ if (SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx) == NULL) {
+ *ad = SSL_AD_INTERNAL_ERROR;
+ return SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
/*
* SSL_set_SSL_CTX() only changes certs as of 1.0.0d
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index a7b8339..a071bfe 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2477,7 +2477,7 @@
#if (NGX_HTTP_CACHE)
if (u->cache_status == NGX_HTTP_CACHE_EXPIRED
- && ((u->conf->cache_use_stale & un->mask) || r->cache->stale_error))
+ && (u->conf->cache_use_stale & un->mask))
{
ngx_int_t rc;
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
index 90dcfd4..1dfd7d2 100644
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -954,6 +954,13 @@
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 DATA frame");
+ if (h2c->state.sid == 0) {
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+ "client sent DATA frame with incorrect identifier");
+
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
+ }
+
if (size > h2c->recv_window) {
ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
"client violated connection flow control: "
@@ -1052,6 +1059,7 @@
size_t size;
ngx_buf_t *buf;
ngx_int_t rc;
+ ngx_connection_t *fc;
ngx_http_request_t *r;
ngx_http_v2_stream_t *stream;
ngx_http_v2_srv_conf_t *h2scf;
@@ -1070,6 +1078,7 @@
}
r = stream->request;
+ fc = r->connection;
if (r->reading_body && !r->request_body_no_buffering) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
@@ -1078,6 +1087,13 @@
return ngx_http_v2_state_skip_padded(h2c, pos, end);
}
+ if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+ "skipping http2 DATA frame");
+
+ return ngx_http_v2_state_skip_padded(h2c, pos, end);
+ }
+
size = end - pos;
if (size >= h2c->state.length) {
@@ -1095,6 +1111,8 @@
ngx_http_finalize_request(r, rc);
}
+ ngx_http_run_posted_requests(fc);
+
} else if (size) {
buf = stream->preread;
@@ -2101,6 +2119,16 @@
ngx_http_v2_state_settings(ngx_http_v2_connection_t *h2c, u_char *pos,
u_char *end)
{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
+ "http2 SETTINGS frame");
+
+ if (h2c->state.sid) {
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+ "client sent SETTINGS frame with incorrect identifier");
+
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
+ }
+
if (h2c->state.flags == NGX_HTTP_V2_ACK_FLAG) {
if (h2c->state.length != 0) {
@@ -2127,9 +2155,6 @@
return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
}
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
- "http2 SETTINGS frame");
-
return ngx_http_v2_state_settings_params(h2c, pos, end);
}
@@ -2296,6 +2321,13 @@
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
"http2 PING frame");
+ if (h2c->state.sid) {
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+ "client sent PING frame with incorrect identifier");
+
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
+ }
+
if (h2c->state.flags & NGX_HTTP_V2_ACK_FLAG) {
return ngx_http_v2_state_skip(h2c, pos, end);
}
@@ -2340,6 +2372,13 @@
return ngx_http_v2_state_save(h2c, pos, end, ngx_http_v2_state_goaway);
}
+ if (h2c->state.sid) {
+ ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
+ "client sent GOAWAY frame with incorrect identifier");
+
+ return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_PROTOCOL_ERROR);
+ }
+
#if (NGX_DEBUG)
h2c->state.length -= NGX_HTTP_V2_GOAWAY_SIZE;
diff --git a/src/ngx_modules.c b/src/ngx_modules.c
index 584dea1..304a2d1 100644
--- a/src/ngx_modules.c
+++ b/src/ngx_modules.c
@@ -276,6 +276,9 @@
#if (NGX_STREAM_RETURN)
extern ngx_module_t ngx_stream_return_module;
#endif
+#if (NGX_STREAM_SET)
+extern ngx_module_t ngx_stream_set_module;
+#endif
#if (NGX_STREAM_UPSTREAM_HASH)
extern ngx_module_t ngx_stream_upstream_hash_module;
#endif
@@ -565,6 +568,9 @@
#if (NGX_STREAM_RETURN)
&ngx_stream_return_module,
#endif
+#if (NGX_STREAM_SET)
+ &ngx_stream_set_module,
+#endif
#if (NGX_STREAM_UPSTREAM_HASH)
&ngx_stream_upstream_hash_module,
#endif
@@ -856,6 +862,9 @@
#if (NGX_STREAM_RETURN)
"ngx_stream_return_module",
#endif
+#if (NGX_STREAM_SET)
+ "ngx_stream_set_module",
+#endif
#if (NGX_STREAM_UPSTREAM_HASH)
"ngx_stream_upstream_hash_module",
#endif
@@ -1146,6 +1155,9 @@
#if !(NGX_STREAM_RETURN)
ngx_write_stderr(" --without-stream_return_module");
#endif
+#if !(NGX_STREAM_SET)
+ ngx_write_stderr(" --without-stream_set_module");
+#endif
#if !(NGX_STREAM_SPLIT_CLIENTS)
ngx_write_stderr(" --without-stream_split_clients_module");
#endif
diff --git a/src/stream/ngx_stream_set_module.c b/src/stream/ngx_stream_set_module.c
new file mode 100644
index 0000000..9b34a60
--- /dev/null
+++ b/src/stream/ngx_stream_set_module.c
@@ -0,0 +1,226 @@
+
+/*
+ * Copyright (C) Pavel Pautov
+ * Copyright (C) Nginx, Inc.
+ */
+
+
+#include <ngx_config.h>
+#include <ngx_core.h>
+#include <ngx_stream.h>
+
+
+typedef struct {
+ ngx_int_t index;
+ ngx_stream_set_variable_pt set_handler;
+ uintptr_t data;
+ ngx_stream_complex_value_t value;
+} ngx_stream_set_cmd_t;
+
+
+typedef struct {
+ ngx_array_t commands;
+} ngx_stream_set_srv_conf_t;
+
+
+static ngx_int_t ngx_stream_set_handler(ngx_stream_session_t *s);
+static ngx_int_t ngx_stream_set_var(ngx_stream_session_t *s,
+ ngx_stream_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_stream_set_init(ngx_conf_t *cf);
+static void *ngx_stream_set_create_srv_conf(ngx_conf_t *cf);
+static char *ngx_stream_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+
+
+static ngx_command_t ngx_stream_set_commands[] = {
+
+ { ngx_string("set"),
+ NGX_STREAM_SRV_CONF|NGX_CONF_TAKE2,
+ ngx_stream_set,
+ NGX_STREAM_SRV_CONF_OFFSET,
+ 0,
+ NULL },
+
+ ngx_null_command
+};
+
+
+static ngx_stream_module_t ngx_stream_set_module_ctx = {
+ NULL, /* preconfiguration */
+ ngx_stream_set_init, /* postconfiguration */
+
+ NULL, /* create main configuration */
+ NULL, /* init main configuration */
+
+ ngx_stream_set_create_srv_conf, /* create server configuration */
+ NULL /* merge server configuration */
+};
+
+
+ngx_module_t ngx_stream_set_module = {
+ NGX_MODULE_V1,
+ &ngx_stream_set_module_ctx, /* module context */
+ ngx_stream_set_commands, /* module directives */
+ NGX_STREAM_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_int_t
+ngx_stream_set_handler(ngx_stream_session_t *s)
+{
+ ngx_str_t str;
+ ngx_uint_t i;
+ ngx_stream_set_cmd_t *cmds;
+ ngx_stream_set_srv_conf_t *scf;
+ ngx_stream_variable_value_t vv;
+
+ scf = ngx_stream_get_module_srv_conf(s, ngx_stream_set_module);
+ cmds = scf->commands.elts;
+ vv = ngx_stream_variable_null_value;
+
+ for (i = 0; i < scf->commands.nelts; i++) {
+ if (ngx_stream_complex_value(s, &cmds[i].value, &str) != NGX_OK) {
+ return NGX_ERROR;
+ }
+
+ if (cmds[i].set_handler != NULL) {
+ vv.len = str.len;
+ vv.data = str.data;
+ cmds[i].set_handler(s, &vv, cmds[i].data);
+
+ } else {
+ s->variables[cmds[i].index].len = str.len;
+ s->variables[cmds[i].index].valid = 1;
+ s->variables[cmds[i].index].no_cacheable = 0;
+ s->variables[cmds[i].index].not_found = 0;
+ s->variables[cmds[i].index].data = str.data;
+ }
+ }
+
+ return NGX_DECLINED;
+}
+
+
+static ngx_int_t
+ngx_stream_set_var(ngx_stream_session_t *s, ngx_stream_variable_value_t *v,
+ uintptr_t data)
+{
+ *v = ngx_stream_variable_null_value;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_stream_set_init(ngx_conf_t *cf)
+{
+ ngx_stream_handler_pt *h;
+ ngx_stream_core_main_conf_t *cmcf;
+
+ cmcf = ngx_stream_conf_get_module_main_conf(cf, ngx_stream_core_module);
+
+ h = ngx_array_push(&cmcf->phases[NGX_STREAM_PREACCESS_PHASE].handlers);
+ if (h == NULL) {
+ return NGX_ERROR;
+ }
+
+ *h = ngx_stream_set_handler;
+
+ return NGX_OK;
+}
+
+
+static void *
+ngx_stream_set_create_srv_conf(ngx_conf_t *cf)
+{
+ ngx_stream_set_srv_conf_t *conf;
+
+ conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_set_srv_conf_t));
+ if (conf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * set by ngx_pcalloc():
+ *
+ * conf->commands = { NULL };
+ */
+
+ return conf;
+}
+
+
+static char *
+ngx_stream_set(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_stream_set_srv_conf_t *scf = conf;
+
+ ngx_str_t *args;
+ ngx_int_t index;
+ ngx_stream_set_cmd_t *set_cmd;
+ ngx_stream_variable_t *v;
+ ngx_stream_compile_complex_value_t ccv;
+
+ args = cf->args->elts;
+
+ if (args[1].data[0] != '$') {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid variable name \"%V\"", &args[1]);
+ return NGX_CONF_ERROR;
+ }
+
+ args[1].len--;
+ args[1].data++;
+
+ v = ngx_stream_add_variable(cf, &args[1],
+ NGX_STREAM_VAR_CHANGEABLE|NGX_STREAM_VAR_WEAK);
+ if (v == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ index = ngx_stream_get_variable_index(cf, &args[1]);
+ if (index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ if (v->get_handler == NULL) {
+ v->get_handler = ngx_stream_set_var;
+ }
+
+ if (scf->commands.elts == NULL) {
+ if (ngx_array_init(&scf->commands, cf->pool, 1,
+ sizeof(ngx_stream_set_cmd_t))
+ != NGX_OK)
+ {
+ return NGX_CONF_ERROR;
+ }
+ }
+
+ set_cmd = ngx_array_push(&scf->commands);
+ if (set_cmd == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ set_cmd->index = index;
+ set_cmd->set_handler = v->set_handler;
+ set_cmd->data = v->data;
+
+ ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &args[2];
+ ccv.complex_value = &set_cmd->value;
+
+ if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ return NGX_CONF_OK;
+}