[PATCH] Added merge inheritance to proxy_set_header

J Carter jordanc.carter at outlook.com
Thu Nov 23 14:52:55 UTC 2023


# HG changeset patch
# User J Carter <jordan.carter at outlook.com>
# Date 1700751016 0
#      Thu Nov 23 14:50:16 2023 +0000
# Node ID cc79903ca02eff8aa87238a0f801f8070425d9ab
# Parent  7ec761f0365f418511e30b82e9adf80bc56681df
Added merge inheritance to proxy_set_header

This patch introduces 'inherit' argument to proxy_set_header
directive. When marked as such it will be merge inherited into child
contexts regardless of the presence of other proxy_set_header
directives within those contexts.

This patch also introduces the 'proxy_set_header_inherit' directive
which blocks the merge inheritance in receiving contexts when set to off.

The purpose of the added mechanics is to reduce repetition within the
nginx configuration for universally set (or boilerplate) request
headers, while maintaining flexibility to set additional headers for
specific paths.

There is no change in behavior for existing configurations.

Example below:

server {

    ...

    proxy_set_header Host $host inherit;
    proxy_set_header Connection "" inherit;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for inherit;

    location /1/ {
        #sets this header in addition to server context ones.
        proxy_set_header customHeader1 "customvalue1";
        proxy_pass http://backend1;
    }

    location /2/ {
        #sets this header in addition to server context ones.
        proxy_set_header customheader2 "customValue2";
        proxy_pass http://backend1;
    }

    location /3/ {
        #no location specific headers, only server context ones set.
        proxy_pass http://backend1;
    }

    location /special/ {
        #Blocks merge inheritance from server context.
        proxy_set_header_inherit off;
        proxy_set_header Host "notserverthost.co";
        proxy_set_header Connection "";
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://backend2;
    }

}

TODO:
- Repeat this implementation for grpc_set_header

diff -r 7ec761f0365f -r cc79903ca02e src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c	Thu Oct 26 23:35:09 2023 +0300
+++ b/src/http/modules/ngx_http_proxy_module.c	Thu Nov 23 14:50:16 2023 +0000
@@ -69,6 +69,11 @@
     ngx_str_t                      uri;
 } ngx_http_proxy_vars_t;
 
+typedef struct  {
+    ngx_str_t                  key;
+    ngx_str_t                  value;
+    ngx_uint_t                 inherit;  /* unsigned  inherit:1 */
+} ngx_http_proxy_header_src_t;
 
 typedef struct {
     ngx_array_t                   *flushes;
@@ -117,6 +122,8 @@
     ngx_uint_t                     headers_hash_max_size;
     ngx_uint_t                     headers_hash_bucket_size;
 
+    ngx_flag_t                     headers_inherit;
+
 #if (NGX_HTTP_SSL)
     ngx_uint_t                     ssl;
     ngx_uint_t                     ssl_protocols;
@@ -215,6 +222,8 @@
     void *conf);
 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd,
     void *conf);
+static char *ngx_http_proxy_set_header(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);
@@ -409,12 +418,19 @@
       NULL },
 
     { ngx_string("proxy_set_header"),
-      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
-      ngx_conf_set_keyval_slot,
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23,
+      ngx_http_proxy_set_header,
       NGX_HTTP_LOC_CONF_OFFSET,
       offsetof(ngx_http_proxy_loc_conf_t, headers_source),
       NULL },
 
+    { ngx_string("proxy_set_header_inherit"),
+      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_proxy_loc_conf_t, headers_inherit),
+      NULL },
+
     { ngx_string("proxy_headers_hash_max_size"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_num_slot,
@@ -3400,6 +3416,8 @@
 
     conf->upstream.intercept_errors = NGX_CONF_UNSET;
 
+    conf->headers_inherit = NGX_CONF_UNSET;
+
 #if (NGX_HTTP_SSL)
     conf->upstream.ssl_session_reuse = NGX_CONF_UNSET;
     conf->upstream.ssl_name = NGX_CONF_UNSET_PTR;
@@ -3444,13 +3462,15 @@
     ngx_http_proxy_loc_conf_t *prev = parent;
     ngx_http_proxy_loc_conf_t *conf = child;
 
-    u_char                     *p;
-    size_t                      size;
-    ngx_int_t                   rc;
-    ngx_hash_init_t             hash;
-    ngx_http_core_loc_conf_t   *clcf;
-    ngx_http_proxy_rewrite_t   *pr;
-    ngx_http_script_compile_t   sc;
+    u_char                       *p;
+    size_t                        size;
+    ngx_int_t                     rc;
+    ngx_uint_t                    i;
+    ngx_hash_init_t               hash;
+    ngx_http_core_loc_conf_t     *clcf;
+    ngx_http_proxy_rewrite_t     *pr;
+    ngx_http_script_compile_t     sc;
+    ngx_http_proxy_header_src_t  *phs, *pphs;
 
 #if (NGX_HTTP_CACHE)
 
@@ -3724,6 +3744,9 @@
     ngx_conf_merge_value(conf->upstream.intercept_errors,
                               prev->upstream.intercept_errors, 0);
 
+    ngx_conf_merge_value(conf->headers_inherit,
+                              prev->headers_inherit, 1);
+
 #if (NGX_HTTP_SSL)
 
     if (ngx_http_proxy_merge_ssl(cf, conf, prev) != NGX_OK) {
@@ -3905,8 +3928,25 @@
 #if (NGX_HTTP_CACHE)
         conf->headers_cache = prev->headers_cache;
 #endif
-    }
-
+    } else if (conf->headers_source
+               && prev->headers_source
+               && prev->headers_source != NGX_CONF_UNSET_PTR)
+    {
+        pphs = prev->headers_source->elts;
+
+        for (i = 0; i < prev->headers_source->nelts; i++) {
+            if (!conf->headers_inherit || !pphs[i].inherit) {
+                continue;
+            }
+
+            phs = ngx_array_push(conf->headers_source);
+            if (phs == NULL) {
+                return NGX_CONF_ERROR;
+            }
+
+            *phs = pphs[i];
+        }
+    }
     rc = ngx_http_proxy_init_headers(cf, conf, &conf->headers,
                                      ngx_http_proxy_headers);
     if (rc != NGX_OK) {
@@ -3957,6 +3997,7 @@
     ngx_hash_init_t               hash;
     ngx_http_script_compile_t     sc;
     ngx_http_script_copy_code_t  *copy;
+    ngx_http_proxy_header_src_t  *phs;
 
     if (headers->hash.buckets) {
         return NGX_OK;
@@ -3986,7 +4027,7 @@
 
     if (conf->headers_source) {
 
-        src = conf->headers_source->elts;
+        phs = conf->headers_source->elts;
         for (i = 0; i < conf->headers_source->nelts; i++) {
 
             s = ngx_array_push(&headers_merged);
@@ -3994,7 +4035,8 @@
                 return NGX_ERROR;
             }
 
-            *s = src[i];
+            s->key = phs[i].key;
+            s->value = phs[i].value;
         }
     }
 
@@ -4769,6 +4811,52 @@
 }
 
 
+static char *
+ngx_http_proxy_set_header(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+    ngx_http_proxy_loc_conf_t *plcf = conf;
+
+    ngx_str_t                          *value;
+    ngx_array_t                       **headers;
+    ngx_http_proxy_header_src_t        *phs;
+
+    value = cf->args->elts;
+
+    headers = (ngx_array_t **) ((char *) plcf + cmd->offset);
+
+    if (*headers == NGX_CONF_UNSET_PTR) {
+        *headers = ngx_array_create(cf->pool, 1,
+                                    sizeof(ngx_http_proxy_header_src_t));
+        if (*headers == NULL) {
+            return NGX_CONF_ERROR;
+        }
+    }
+
+    phs = ngx_array_push(*headers);
+    if (phs == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    phs->key = value[1];
+    phs->value = value[2];
+    phs->inherit = 0;
+
+    if (cf->args->nelts == 3) {
+        return NGX_CONF_OK;
+    }
+
+    if (ngx_strcmp(value[3].data, "inherit") != 0) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "invalid parameter \"%V\"", &value[3]);
+        return NGX_CONF_ERROR;
+    }
+
+    phs->inherit = 1;
+
+    return NGX_CONF_OK;
+}
+
+
 #if (NGX_HTTP_CACHE)
 
 static char *


More information about the nginx-devel mailing list