extension to server_name directive - include top-level directory in search

Chris Newton cnewton at netflix.com
Tue Jul 25 14:56:50 UTC 2023


The server_name directive allows for selecting which "server" block should
be used to process a request; a "server" being a very convenient way to
group a set of directives and location blocks into a separate and distinct
configuration entity. Currently, server_name selects the server based on
the value of the Host: header alone, which can be overly constraining.

The attached patch extends server_name to allow the first directory element
to be used as part of the selection process. When there is at least one
server_name with a '/' character, at ngx_http_find_virtual_server() time an
initial lookup into the virtual_names hash is made using a combination of
hostname/topleveldirectory - if no match is found, the hostname only lookup
is performed (as before), thereby allowing for specific directories to be
broken out into their own server blocks

>From a01fd492fb8935e9c9e0f4c703b9430c83c12590 Mon Sep 17 00:00:00 2001

From: Chris Newton <cnewton at netflix.com>

Date: Mon, 24 Jul 2023 19:32:03 +0000

Subject: [PATCH] virtual aliases


---

 src/http/ngx_http.c             |  2 ++

 src/http/ngx_http.h             |  1 +

 src/http/ngx_http_core_module.c |  4 +--

 src/http/ngx_http_request.c     | 54 ++++++++++++++++++++++++++++-----

 4 files changed, 51 insertions(+), 10 deletions(-)


diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c

index d835f896e..54ad9cb9e 100644

--- a/src/http/ngx_http.c

+++ b/src/http/ngx_http.c

@@ -70,6 +70,7 @@ static ngx_int_t ngx_http_add_addrs6(ngx_conf_t *cf,
ngx_http_port_t *hport,



 ngx_uint_t   ngx_http_max_module;



+ngx_uint_t  ngx_http_uses_complete_alias;



 ngx_http_output_header_filter_pt  ngx_http_top_header_filter;

 ngx_http_output_body_filter_pt    ngx_http_top_body_filter;

@@ -148,6 +149,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void
*conf)



     ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);



+    ngx_http_uses_complete_alias = 0;



     /* the http main_conf context, it is the same in the all http contexts
*/



diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h

index e06464ebd..935cecc0f 100644

--- a/src/http/ngx_http.h

+++ b/src/http/ngx_http.h

@@ -189,6 +189,7 @@ extern ngx_module_t  ngx_http_module;



 extern ngx_str_t  ngx_http_html_default_types[];



+extern ngx_uint_t  ngx_http_uses_complete_alias;



 extern ngx_http_output_header_filter_pt  ngx_http_top_header_filter;

 extern ngx_http_output_body_filter_pt    ngx_http_top_body_filter;

diff --git a/src/http/ngx_http_core_module.c
b/src/http/ngx_http_core_module.c

index 97a91aee2..3179d65a1 100644

--- a/src/http/ngx_http_core_module.c

+++ b/src/http/ngx_http_core_module.c

@@ -4380,9 +4380,7 @@ ngx_http_core_server_name(ngx_conf_t *cf,
ngx_command_t *cmd, void *conf)

         }



         if (ngx_strchr(value[i].data, '/')) {

-            ngx_conf_log_error(NGX_LOG_WARN, cf, 0,

-                               "server name \"%V\" has suspicious symbols",

-                               &value[i]);

+            ngx_http_uses_complete_alias = 1;

         }



         sn = ngx_array_push(&cscf->server_names);

diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c

index bd2be5eac..189500885 100644

--- a/src/http/ngx_http_request.c

+++ b/src/http/ngx_http_request.c

@@ -2227,6 +2227,7 @@ ngx_http_set_virtual_server(ngx_http_request_t *r,
ngx_str_t *host)

     ngx_http_connection_t     *hc;

     ngx_http_core_loc_conf_t  *clcf;

     ngx_http_core_srv_conf_t  *cscf;

+    ngx_str_t                 *find_host = host;



 #if (NGX_SUPPRESS_WARN)

     cscf = NULL;

@@ -2250,7 +2251,11 @@ ngx_http_set_virtual_server(ngx_http_request_t *r,
ngx_str_t *host)

                 return NGX_ERROR;

             }

 #endif

-            return NGX_OK;

+            if (ngx_http_uses_complete_alias) {

+                find_host = hc->ssl_servername;

+            } else {

+                return NGX_OK;

+            }

         }

     }



@@ -2258,7 +2263,7 @@ ngx_http_set_virtual_server(ngx_http_request_t *r,
ngx_str_t *host)



     rc = ngx_http_find_virtual_server(r->connection,

                                       hc->addr_conf->virtual_names,

-                                      host, r, &cscf);

+                                      find_host, r, &cscf);



     if (rc == NGX_ERROR) {

         ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);

@@ -2275,14 +2280,19 @@ ngx_http_set_virtual_server(ngx_http_request_t *r,
ngx_str_t *host)

             rc = NGX_OK;

         }



-        sscf = ngx_http_get_module_srv_conf(cscf->ctx,
ngx_http_ssl_module);

+        if (!ngx_http_uses_complete_alias

+            || hc->ssl_servername->len != host->len

+            || ngx_strncmp(hc->ssl_servername->data,

+                           host->data, host->len) != 0) {

+            sscf = ngx_http_get_module_srv_conf(cscf->ctx,
ngx_http_ssl_module);



-        if (sscf->verify) {

-            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,

+            if (sscf->verify) {

+                ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,

                           "client attempted to request the server name "

                           "different from the one that was negotiated");

-            ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST);

-            return NGX_ERROR;

+                ngx_http_finalize_request(r, NGX_HTTP_MISDIRECTED_REQUEST);

+                return NGX_ERROR;

+            }

         }

     }



@@ -2314,6 +2324,36 @@ ngx_http_find_virtual_server(ngx_connection_t *c,

         return NGX_DECLINED;

     }



+    if (r && r->uri.len > 1 && r->pool) {

+        ngx_str_t   combined;

+        u_char     *p;

+

+        p = (u_char *)ngx_strchr(&r->uri.data[1], '/');

+        if (p) {

+            ngx_uint_t alias_len = p - r->uri.data;

+            if (alias_len > r->uri.len) {

+                /* No '/' in the path, so use entire thing */

+                alias_len = r->uri.len;

+            }

+            combined.len = host->len + alias_len;

+

+            combined.data = ngx_pnalloc(r->pool, combined.len);

+            if (combined.data == NULL) {

+                return NGX_ERROR;

+            }

+            ngx_memcpy(&combined.data[0], host->data, host->len);

+            ngx_memcpy(&combined.data[host->len], r->uri.data, alias_len);

+

+            cscf = ngx_hash_find_combined(&virtual_names->names,

+                                  ngx_hash_key(combined.data,
combined.len),

+                                  combined.data, combined.len);

+            if (cscf) {

+                *cscfp = cscf;

+                return NGX_OK;

+            }

+        }

+    }

+

     cscf = ngx_hash_find_combined(&virtual_names->names,

                                   ngx_hash_key(host->data, host->len),

                                   host->data, host->len);

-- 

2.40.1




*Chris Newton* (he/him/his)
Open Connect | Content Delivery Architecture M: 805.444.0573 |
cnewton at netflix.com
111 Albright Way | Los Gatos, CA 95032
<https://maps.google.com/?q=111+Albright+Way%C2%A0%7C++Los+Gatos,+CA+95032&entry=gmail&source=g>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20230725/c1f74120/attachment-0001.htm>


More information about the nginx-devel mailing list