[PATCH] Added support for client_scheme_in_redirect directive

Kyle Ibrahim kibrahim at getpantheon.com
Sun Mar 15 11:07:11 UTC 2015


Currently, there is no way way to control the scheme which will be used in
nginx-issued redirects. This is a problem when the client is potentially
using a different scheme than nginx due to a SSL terminating load balancer.
As some client requests may have started over http and some over https,
we'd like to way to dynamically set the proper client scheme.

This is a patch which adds a directive `client_scheme_in_redirect` to
complement `server_name_in_redirect` and `port_in_redirect`.

A suggested documentation block is included in the commit.

# HG changeset patch
# User Kyle Ibrahim <kibrahim at getpantheon.com>
# Date 1426414581 25200
#      Sun Mar 15 03:16:21 2015 -0700
# Node ID 9785f13c006025f180b354bdeac2de5d8cc9af8e
# Parent  79b473d5381d85f79ab71b7aa85ecf9be1caf9fb
Added support for client_scheme_in_redirect directive

Syntax: client_scheme_in_redirect scheme;
Default: --
Context: http, server, location

The client_scheme_in_redirect directive defines the scheme in redirects
issued by nginx. When not specified, the scheme will be https if the
current connection is
over ssl and http otherwise. The scheme value can contain variables.

diff -r 79b473d5381d -r 9785f13c0060 contrib/vim/syntax/nginx.vim
--- a/contrib/vim/syntax/nginx.vim Fri Mar 13 16:43:01 2015 +0300
+++ b/contrib/vim/syntax/nginx.vim Sun Mar 15 03:16:21 2015 -0700
@@ -96,6 +96,7 @@
 syn keyword ngxDirective client_header_buffer_size
 syn keyword ngxDirective client_header_timeout
 syn keyword ngxDirective client_max_body_size
+syn keyword ngxDirective client_scheme_in_redirect
 syn keyword ngxDirective connection_pool_size
 syn keyword ngxDirective create_full_put_path
 syn keyword ngxDirective daemon
diff -r 79b473d5381d -r 9785f13c0060 src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c Fri Mar 13 16:43:01 2015 +0300
+++ b/src/http/ngx_http_core_module.c Sun Mar 15 03:16:21 2015 -0700
@@ -72,6 +72,8 @@
     void *conf);
 static char *ngx_http_core_resolver(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_client_scheme_in_redirect(ngx_conf_t *cf,
+    ngx_command_t *cmd, void *conf);
 #if (NGX_HTTP_GZIP)
 static ngx_int_t ngx_http_gzip_accept_encoding(ngx_str_t *ae);
 static ngx_uint_t ngx_http_gzip_quantity(u_char *p, u_char *last);
@@ -560,6 +562,13 @@
       offsetof(ngx_http_core_loc_conf_t, reset_timedout_connection),
       NULL },

+    { ngx_string("client_scheme_in_redirect"),
+
 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+      ngx_http_client_scheme_in_redirect,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      0,
+      NULL },
+
     { ngx_string("server_name_in_redirect"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
       ngx_conf_set_flag_slot,
@@ -3642,6 +3651,7 @@
     clcf->lingering_timeout = NGX_CONF_UNSET_MSEC;
     clcf->resolver_timeout = NGX_CONF_UNSET_MSEC;
     clcf->reset_timedout_connection = NGX_CONF_UNSET;
+    clcf->client_scheme_in_redirect = NGX_CONF_UNSET_PTR;
     clcf->server_name_in_redirect = NGX_CONF_UNSET;
     clcf->port_in_redirect = NGX_CONF_UNSET;
     clcf->msie_padding = NGX_CONF_UNSET;
@@ -3898,6 +3908,8 @@

     ngx_conf_merge_value(conf->reset_timedout_connection,
                               prev->reset_timedout_connection, 0);
+    ngx_conf_merge_ptr_value(conf->client_scheme_in_redirect,
+                              prev->client_scheme_in_redirect, NULL);
     ngx_conf_merge_value(conf->server_name_in_redirect,
                               prev->server_name_in_redirect, 0);
     ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect,
1);
@@ -5066,6 +5078,38 @@
     return NGX_CONF_OK;
 }

+static char *
+ngx_http_client_scheme_in_redirect(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
+{
+    ngx_http_core_loc_conf_t *clcf = conf;
+
+    ngx_str_t                         *value;
+    ngx_http_compile_complex_value_t   ccv;
+
+    if (clcf->client_scheme_in_redirect != NGX_CONF_UNSET_PTR) {
+        return "is duplicate";
+    }
+
+    value = cf->args->elts;
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = &value[1];
+    ccv.complex_value = ngx_palloc(cf->pool,
+                                   sizeof(ngx_http_complex_value_t));
+    if (ccv.complex_value == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
+        return NGX_CONF_ERROR;
+    }
+
+    clcf->client_scheme_in_redirect = ccv.complex_value;
+
+    return NGX_CONF_OK;
+}

 #if (NGX_HTTP_GZIP)

diff -r 79b473d5381d -r 9785f13c0060 src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h Fri Mar 13 16:43:01 2015 +0300
+++ b/src/http/ngx_http_core_module.h Sun Mar 15 03:16:21 2015 -0700
@@ -399,6 +399,7 @@
     ngx_flag_t    tcp_nopush;              /* tcp_nopush */
     ngx_flag_t    tcp_nodelay;             /* tcp_nodelay */
     ngx_flag_t    reset_timedout_connection; /* reset_timedout_connection
*/
+    ngx_http_complex_value_t    *client_scheme_in_redirect; /*
client_scheme_in_redirect */
     ngx_flag_t    server_name_in_redirect; /* server_name_in_redirect */
     ngx_flag_t    port_in_redirect;        /* port_in_redirect */
     ngx_flag_t    msie_padding;            /* msie_padding */
diff -r 79b473d5381d -r 9785f13c0060
src/http/ngx_http_header_filter_module.c
--- a/src/http/ngx_http_header_filter_module.c Fri Mar 13 16:43:01 2015
+0300
+++ b/src/http/ngx_http_header_filter_module.c Sun Mar 15 03:16:21 2015
-0700
@@ -152,7 +152,7 @@
 {
     u_char                    *p;
     size_t                     len;
-    ngx_str_t                  host, *status_line;
+    ngx_str_t                  client_scheme, host, *status_line;
     ngx_buf_t                 *b;
     ngx_uint_t                 status, i, port;
     ngx_chain_t                out;
@@ -317,6 +317,15 @@
     {
         r->headers_out.location->hash = 0;

+        if (clcf->client_scheme_in_redirect) {
+            if (ngx_http_complex_value(r, clcf->client_scheme_in_redirect,
&client_scheme) != NGX_OK) {
+                return NGX_ERROR;
+            }
+
+        } else {
+            ngx_str_null(&client_scheme);
+        }
+
         if (clcf->server_name_in_redirect) {
             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
             host = cscf->server_name;
@@ -352,7 +361,12 @@
             break;
         }

-        len += sizeof("Location: https://") - 1
+        if (client_scheme.len) {
+            len += client_scheme.len;
+        } else {
+            len += sizeof("https") - 1;
+        }
+        len += sizeof("Location: ://") - 1
                + host.len
                + r->headers_out.location->value.len + 2;

@@ -374,6 +388,7 @@
         }

     } else {
+        ngx_str_null(&client_scheme);
         ngx_str_null(&host);
         port = 0;
     }
@@ -521,14 +536,19 @@

         p = b->last + sizeof("Location: ") - 1;

-        b->last = ngx_cpymem(b->last, "Location: http",
-                             sizeof("Location: http") - 1);
+        b->last = ngx_cpymem(b->last, "Location: ",
+                             sizeof("Location: ") - 1);

+        if (client_scheme.len) {
+            b->last = ngx_copy(b->last, client_scheme.data,
client_scheme.len);
+        } else {
+            b->last = ngx_cpymem(b->last, "http", sizeof("http") - 1);
 #if (NGX_HTTP_SSL)
-        if (c->ssl) {
-            *b->last++ ='s';
+            if (c->ssl) {
+                *b->last++ ='s';
+            }
+#endif
         }
-#endif

         *b->last++ = ':'; *b->last++ = '/'; *b->last++ = '/';
         b->last = ngx_copy(b->last, host.data, host.len);
diff -r 79b473d5381d -r 9785f13c0060 src/http/ngx_http_spdy_filter_module.c
--- a/src/http/ngx_http_spdy_filter_module.c Fri Mar 13 16:43:01 2015 +0300
+++ b/src/http/ngx_http_spdy_filter_module.c Sun Mar 15 03:16:21 2015 -0700
@@ -99,7 +99,7 @@
     size_t                        len;
     u_char                       *p, *buf, *last;
     ngx_buf_t                    *b;
-    ngx_str_t                     host;
+    ngx_str_t                     client_scheme, host;
     ngx_uint_t                    i, j, count, port;
     ngx_chain_t                  *cl;
     ngx_list_part_t              *part, *pt;
@@ -217,6 +217,15 @@
     {
         r->headers_out.location->hash = 0;

+        if (clcf->client_scheme_in_redirect) {
+            if (ngx_http_complex_value(r, clcf->client_scheme_in_redirect,
&client_scheme) != NGX_OK) {
+                return NGX_ERROR;
+            }
+
+        } else {
+            ngx_str_null(&client_scheme);
+        }
+
         if (clcf->server_name_in_redirect) {
             cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
             host = cscf->server_name;
@@ -252,8 +261,14 @@
             break;
         }

+        if (client_scheme.len) {
+            len += client_scheme.len;
+        } else {
+            len += ngx_http_spdy_nv_vsize("https");
+        }
+
         len += ngx_http_spdy_nv_nsize("location")
-               + ngx_http_spdy_nv_vsize("https://")
+               + ngx_http_spdy_nv_vsize("://")
                + host.len
                + r->headers_out.location->value.len;

@@ -275,6 +290,7 @@
         }

     } else {
+        ngx_str_null(&client_scheme);
         ngx_str_null(&host);
         port = 0;
     }
@@ -411,13 +427,16 @@

         p = last + NGX_SPDY_NV_VLEN_SIZE;

-        last = ngx_cpymem(p, "http", sizeof("http") - 1);
-
+        if (client_scheme.len) {
+            last = ngx_cpymem(p, client_scheme.data, client_scheme.len);
+        } else {
+            last = ngx_cpymem(p, "http", sizeof("http") - 1);
 #if (NGX_HTTP_SSL)
-        if (c->ssl) {
-            *last++ ='s';
+            if (c->ssl) {
+                *last++ ='s';
+            }
+#endif
         }
-#endif

         *last++ = ':'; *last++ = '/'; *last++ = '/';
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20150315/2d78e538/attachment-0001.html>


More information about the nginx-devel mailing list