[PATCH] Proxy: make timeout directives accept variables
Thibault Charbonnier
thibaultcha at fastmail.com
Tue Jan 31 01:39:13 UTC 2017
Hello!
This is a proposal to allow for better granularity (eventually, on a
per-request basis?) regarding the proxy_*_timeout directives.
Please let me know how you feel about such a feature, and if you think
this patch should be implemented in a different way.
Thanks!
# HG changeset patch
# User Thibault Charbonnier <thibaultcha at fastmail.com>
# Date 1485823618 28800
# Mon Jan 30 16:46:58 2017 -0800
# Branch proxy/variables-in-timeouts
# Node ID 9f27c1d40590566ae5ac55e04af473d5f8e97d87
# Parent 640f035293959b2d4b0ba5939d954bc517f57f77
Proxy: make timeout directives accept variables
We try to stay as close as possible from the original behavior regarding the
parsing of the ngx_msec_t fields, to preserve the proper parsing error logs.
As long as the timeout directives do not contain a variable, the behavior is
identical as prior to this patch.
If a timeout directive contains a variable, we consider such variable to
contain the related timeout in ms precision.
diff -r 640f03529395 -r 9f27c1d40590
src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c Fri Jan 27 19:06:35
2017 +0300
+++ b/src/http/modules/ngx_http_proxy_module.c Mon Jan 30 16:46:58
2017 -0800
@@ -45,6 +45,16 @@
typedef struct {
+ ngx_uint_t complex;
+
+ union {
+ ngx_msec_t simple;
+ ngx_http_complex_value_t *complex;
+ } value;
+} ngx_http_proxy_timeout_t;
+
+
+typedef struct {
ngx_array_t *flushes;
ngx_array_t *lengths;
ngx_array_t *values;
@@ -77,6 +87,10 @@
ngx_str_t location;
ngx_str_t url;
+ ngx_http_proxy_timeout_t *connect_timeout;
+ ngx_http_proxy_timeout_t *send_timeout;
+ ngx_http_proxy_timeout_t *read_timeout;
+
#if (NGX_HTTP_CACHE)
ngx_http_complex_value_t cache_key;
#endif
@@ -171,6 +185,8 @@
static ngx_int_t ngx_http_proxy_init_headers(ngx_conf_t *cf,
ngx_http_proxy_loc_conf_t *conf, ngx_http_proxy_headers_t *headers,
ngx_keyval_t *default_headers);
+static ngx_int_t ngx_http_proxy_compile_timeout(ngx_http_request_t *r,
+ ngx_http_complex_value_t *c_timeout, ngx_msec_t *u_timeout);
static char *ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -182,6 +198,8 @@
void *conf);
static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char * ngx_http_proxy_timeout(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
#if (NGX_HTTP_CACHE)
static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
@@ -324,16 +342,16 @@
{ ngx_string("proxy_connect_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_msec_slot,
+ ngx_http_proxy_timeout,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.connect_timeout),
+ offsetof(ngx_http_proxy_loc_conf_t, connect_timeout),
NULL },
{ ngx_string("proxy_send_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_msec_slot,
+ ngx_http_proxy_timeout,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.send_timeout),
+ offsetof(ngx_http_proxy_loc_conf_t, send_timeout),
NULL },
{ ngx_string("proxy_send_lowat"),
@@ -408,9 +426,9 @@
{ ngx_string("proxy_read_timeout"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
- ngx_conf_set_msec_slot,
+ ngx_http_proxy_timeout,
NGX_HTTP_LOC_CONF_OFFSET,
- offsetof(ngx_http_proxy_loc_conf_t, upstream.read_timeout),
+ offsetof(ngx_http_proxy_loc_conf_t, read_timeout),
NULL },
{ ngx_string("proxy_buffers"),
@@ -829,6 +847,11 @@
};
+static ngx_http_proxy_timeout_t ngx_http_proxy_default_timeout = {
+ 0, { 60000 }
+};
+
+
static ngx_int_t
ngx_http_proxy_handler(ngx_http_request_t *r)
{
@@ -1137,6 +1160,7 @@
size_t len, uri_len, loc_len, body_len;
uintptr_t escape;
ngx_buf_t *b;
+ ngx_int_t rc;
ngx_str_t method;
ngx_uint_t i, unparsed_uri;
ngx_chain_t *cl, *body;
@@ -1160,6 +1184,33 @@
headers = &plcf->headers;
#endif
+ if (plcf->connect_timeout->complex) {
+ rc = ngx_http_proxy_compile_timeout(r,
+ plcf->connect_timeout->value.complex,
+ &u->conf->connect_timeout);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
+ if (plcf->send_timeout->complex) {
+ rc = ngx_http_proxy_compile_timeout(r,
+ plcf->send_timeout->value.complex,
+ &u->conf->send_timeout);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
+ if (plcf->read_timeout->complex) {
+ rc = ngx_http_proxy_compile_timeout(r,
+ plcf->read_timeout->value.complex,
+ &u->conf->read_timeout);
+ if (rc != NGX_OK) {
+ return rc;
+ }
+ }
+
if (u->method.len) {
/* HEAD was changed to GET to cache response */
method = u->method;
@@ -2805,6 +2856,9 @@
* conf->upstream.ssl_name = NULL;
*
* conf->method = NULL;
+ * conf->connect_timeout = NULL;
+ * conf->send_timeout = NULL;
+ * conf->read_timeout = NULL;
* conf->headers_source = NULL;
* conf->headers.lengths = NULL;
* conf->headers.values = NULL;
@@ -2953,14 +3007,35 @@
ngx_conf_merge_ptr_value(conf->upstream.local,
prev->upstream.local, NULL);
- ngx_conf_merge_msec_value(conf->upstream.connect_timeout,
- prev->upstream.connect_timeout, 60000);
-
- ngx_conf_merge_msec_value(conf->upstream.send_timeout,
- prev->upstream.send_timeout, 60000);
-
- ngx_conf_merge_msec_value(conf->upstream.read_timeout,
- prev->upstream.read_timeout, 60000);
+ if (conf->connect_timeout == NULL) {
+ conf->connect_timeout = (prev->connect_timeout != NULL)
+ ? prev->connect_timeout
+ : &ngx_http_proxy_default_timeout;
+ }
+
+ if (!conf->connect_timeout->complex) {
+ conf->upstream.connect_timeout =
conf->connect_timeout->value.simple;
+ }
+
+ if (conf->send_timeout == NULL) {
+ conf->send_timeout = (prev->send_timeout != NULL)
+ ? prev->send_timeout
+ : &ngx_http_proxy_default_timeout;
+ }
+
+ if (!conf->send_timeout->complex) {
+ conf->upstream.send_timeout = conf->send_timeout->value.simple;
+ }
+
+ if (conf->read_timeout == NULL) {
+ conf->read_timeout = (prev->read_timeout != NULL)
+ ? prev->read_timeout
+ : &ngx_http_proxy_default_timeout;
+ }
+
+ if (!conf->read_timeout->complex) {
+ conf->upstream.read_timeout = conf->read_timeout->value.simple;
+ }
ngx_conf_merge_msec_value(conf->upstream.next_upstream_timeout,
prev->upstream.next_upstream_timeout, 0);
@@ -3746,6 +3821,61 @@
static char *
+ngx_http_proxy_timeout(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *p = conf;
+
+ ngx_msec_t msp;
+ ngx_str_t *value;
+ ngx_http_proxy_timeout_t **t;
+ ngx_http_complex_value_t *cv;
+ ngx_http_compile_complex_value_t ccv;
+
+ t = (ngx_http_proxy_timeout_t **) (p + cmd->offset);
+ if (*t != NULL) {
+ return "is duplicate";
+ }
+
+ *t = ngx_palloc(cf->pool, sizeof(ngx_http_proxy_timeout_t));
+ if (*t == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ value = cf->args->elts;
+
+ if (ngx_http_script_variables_count(&value[1]) > 0) {
+ cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
+ if (cv == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+ ccv.cf = cf;
+ ccv.value = &value[1];
+ ccv.complex_value = cv;
+
+ if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ (*t)->complex = 1;
+ (*t)->value.complex = cv;
+
+ } else {
+ msp = ngx_parse_time(&value[1], 0);
+ if (msp == (ngx_msec_t) NGX_ERROR) {
+ return "invalid value";
+ }
+
+ (*t)->value.simple = msp;
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_proxy_loc_conf_t *plcf = conf;
@@ -4410,3 +4540,29 @@
v->uri = u->uri;
}
+
+
+static ngx_int_t
+ngx_http_proxy_compile_timeout(ngx_http_request_t *r,
+ ngx_http_complex_value_t *c_timeout, ngx_msec_t *u_timeout)
+{
+ ngx_str_t timeout;
+ ngx_msec_t msp;
+
+ if (ngx_http_complex_value(r, c_timeout, &timeout) != NGX_OK) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "could not compile timeout value");
+ return NGX_ERROR;
+ }
+
+ msp = ngx_atoi(timeout.data, timeout.len);
+ if (msp == (ngx_msec_t) NGX_ERROR) {
+ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+ "invalid timeout value: \"%V\"", &timeout);
+ return NGX_ERROR;
+ }
+
+ *u_timeout = msp;
+
+ return NGX_OK;
+}
More information about the nginx-devel
mailing list