[nginx] Location header escaping in redirects (ticket #882).

Ruslan Ermilov ru at nginx.com
Mon May 24 18:57:10 UTC 2021


details:   https://hg.nginx.org/nginx/rev/1bde031b59ff
branches:  
changeset: 7848:1bde031b59ff
user:      Ruslan Ermilov <ru at nginx.com>
date:      Mon May 24 21:55:20 2021 +0300
description:
Location header escaping in redirects (ticket #882).

The header is escaped in redirects based on request URI or
location name (auto redirect).

diffstat:

 src/http/modules/ngx_http_dav_module.c    |  25 ++++++++++++++++++++-
 src/http/modules/ngx_http_static_module.c |  17 +++++++++++--
 src/http/ngx_http.c                       |  37 +++++++++++++++++++++++++++++++
 src/http/ngx_http_core_module.c           |   7 +++--
 src/http/ngx_http_core_module.h           |   1 +
 5 files changed, 80 insertions(+), 7 deletions(-)

diffs (187 lines):

diff -r 1336a33cff33 -r 1bde031b59ff src/http/modules/ngx_http_dav_module.c
--- a/src/http/modules/ngx_http_dav_module.c	Mon May 24 18:23:42 2021 +0300
+++ b/src/http/modules/ngx_http_dav_module.c	Mon May 24 21:55:20 2021 +0300
@@ -1072,6 +1072,10 @@ ngx_http_dav_error(ngx_log_t *log, ngx_e
 static ngx_int_t
 ngx_http_dav_location(ngx_http_request_t *r)
 {
+    u_char     *p;
+    size_t      len;
+    uintptr_t   escape;
+
     r->headers_out.location = ngx_list_push(&r->headers_out.headers);
     if (r->headers_out.location == NULL) {
         return NGX_ERROR;
@@ -1079,7 +1083,26 @@ ngx_http_dav_location(ngx_http_request_t
 
     r->headers_out.location->hash = 1;
     ngx_str_set(&r->headers_out.location->key, "Location");
-    r->headers_out.location->value = r->uri;
+
+    escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len, NGX_ESCAPE_URI);
+
+    if (escape) {
+        len = r->uri.len + escape;
+
+        p = ngx_pnalloc(r->pool, len);
+        if (p == NULL) {
+            ngx_http_clear_location(r);
+            return NGX_ERROR;
+        }
+
+        r->headers_out.location->value.len = len;
+        r->headers_out.location->value.data = p;
+
+        ngx_escape_uri(p, r->uri.data, r->uri.len, NGX_ESCAPE_URI);
+
+    } else {
+        r->headers_out.location->value = r->uri;
+    }
 
     return NGX_OK;
 }
diff -r 1336a33cff33 -r 1bde031b59ff src/http/modules/ngx_http_static_module.c
--- a/src/http/modules/ngx_http_static_module.c	Mon May 24 18:23:42 2021 +0300
+++ b/src/http/modules/ngx_http_static_module.c	Mon May 24 21:55:20 2021 +0300
@@ -50,6 +50,7 @@ ngx_http_static_handler(ngx_http_request
 {
     u_char                    *last, *location;
     size_t                     root, len;
+    uintptr_t                  escape;
     ngx_str_t                  path;
     ngx_int_t                  rc;
     ngx_uint_t                 level;
@@ -155,14 +156,18 @@ ngx_http_static_handler(ngx_http_request
             return NGX_HTTP_INTERNAL_SERVER_ERROR;
         }
 
-        len = r->uri.len + 1;
+        escape = 2 * ngx_escape_uri(NULL, r->uri.data, r->uri.len,
+                                    NGX_ESCAPE_URI);
 
-        if (!clcf->alias && r->args.len == 0) {
+        if (!clcf->alias && r->args.len == 0 && escape == 0) {
+            len = r->uri.len + 1;
             location = path.data + root;
 
             *last = '/';
 
         } else {
+            len = r->uri.len + escape + 1;
+
             if (r->args.len) {
                 len += r->args.len + 1;
             }
@@ -173,7 +178,13 @@ ngx_http_static_handler(ngx_http_request
                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
             }
 
-            last = ngx_copy(location, r->uri.data, r->uri.len);
+            if (escape) {
+                last = (u_char *) ngx_escape_uri(location, r->uri.data,
+                                                 r->uri.len, NGX_ESCAPE_URI);
+
+            } else {
+                last = ngx_copy(location, r->uri.data, r->uri.len);
+            }
 
             *last = '/';
 
diff -r 1336a33cff33 -r 1bde031b59ff src/http/ngx_http.c
--- a/src/http/ngx_http.c	Mon May 24 18:23:42 2021 +0300
+++ b/src/http/ngx_http.c	Mon May 24 21:55:20 2021 +0300
@@ -37,6 +37,8 @@ static ngx_int_t ngx_http_init_locations
     ngx_http_core_srv_conf_t *cscf, ngx_http_core_loc_conf_t *pclcf);
 static ngx_int_t ngx_http_init_static_location_trees(ngx_conf_t *cf,
     ngx_http_core_loc_conf_t *pclcf);
+static ngx_int_t ngx_http_escape_location_name(ngx_conf_t *cf,
+    ngx_http_core_loc_conf_t *clcf);
 static ngx_int_t ngx_http_cmp_locations(const ngx_queue_t *one,
     const ngx_queue_t *two);
 static ngx_int_t ngx_http_join_exact_locations(ngx_conf_t *cf,
@@ -882,6 +884,41 @@ ngx_http_add_location(ngx_conf_t *cf, ng
 
     ngx_queue_insert_tail(*locations, &lq->queue);
 
+    if (ngx_http_escape_location_name(cf, clcf) != NGX_OK) {
+        return NGX_ERROR;
+    }
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_escape_location_name(ngx_conf_t *cf, ngx_http_core_loc_conf_t *clcf)
+{
+    u_char     *p;
+    size_t      len;
+    uintptr_t   escape;
+
+    escape = 2 * ngx_escape_uri(NULL, clcf->name.data, clcf->name.len,
+                                NGX_ESCAPE_URI);
+
+    if (escape) {
+        len = clcf->name.len + escape;
+
+        p = ngx_pnalloc(cf->pool, len);
+        if (p == NULL) {
+            return NGX_ERROR;
+        }
+
+        clcf->escaped_name.len = len;
+        clcf->escaped_name.data = p;
+
+        ngx_escape_uri(p, clcf->name.data, clcf->name.len, NGX_ESCAPE_URI);
+
+    } else {
+        clcf->escaped_name = clcf->name;
+    }
+
     return NGX_OK;
 }
 
diff -r 1336a33cff33 -r 1bde031b59ff src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c	Mon May 24 18:23:42 2021 +0300
+++ b/src/http/ngx_http_core_module.c	Mon May 24 21:55:20 2021 +0300
@@ -1010,10 +1010,10 @@ ngx_http_core_find_config_phase(ngx_http
         ngx_str_set(&r->headers_out.location->key, "Location");
 
         if (r->args.len == 0) {
-            r->headers_out.location->value = clcf->name;
+            r->headers_out.location->value = clcf->escaped_name;
 
         } else {
-            len = clcf->name.len + 1 + r->args.len;
+            len = clcf->escaped_name.len + 1 + r->args.len;
             p = ngx_pnalloc(r->pool, len);
 
             if (p == NULL) {
@@ -1025,7 +1025,7 @@ ngx_http_core_find_config_phase(ngx_http
             r->headers_out.location->value.len = len;
             r->headers_out.location->value.data = p;
 
-            p = ngx_cpymem(p, clcf->name.data, clcf->name.len);
+            p = ngx_cpymem(p, clcf->escaped_name.data, clcf->escaped_name.len);
             *p++ = '?';
             ngx_memcpy(p, r->args.data, r->args.len);
         }
@@ -3467,6 +3467,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t
     /*
      * set by ngx_pcalloc():
      *
+     *     clcf->escaped_name = { 0, NULL };
      *     clcf->root = { 0, NULL };
      *     clcf->limit_except = 0;
      *     clcf->post_action = { 0, NULL };
diff -r 1336a33cff33 -r 1bde031b59ff src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h	Mon May 24 18:23:42 2021 +0300
+++ b/src/http/ngx_http_core_module.h	Mon May 24 21:55:20 2021 +0300
@@ -299,6 +299,7 @@ typedef struct {
 
 struct ngx_http_core_loc_conf_s {
     ngx_str_t     name;          /* location name */
+    ngx_str_t     escaped_name;
 
 #if (NGX_PCRE)
     ngx_http_regex_t  *regex;


More information about the nginx-devel mailing list