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 <cnew...@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 | cnew...@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>
_______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel