Location header escaping in redirects (ticket #882).
The header is escaped in redirects based on request URI or
location name (auto redirect).
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 8b69e6f..0cc9ae1 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -1072,6 +1072,10 @@
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 @@
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 --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c
index 282d6ee..cf29d5a 100644
--- a/src/http/modules/ngx_http_static_module.c
+++ b/src/http/modules/ngx_http_static_module.c
@@ -50,6 +50,7 @@
{
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 @@
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 @@
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 --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index e1d3d00..3d5c4ac 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -37,6 +37,8 @@
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_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 --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 96a945b..bad43ea 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1010,10 +1010,10 @@
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 @@
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 @@
/*
* set by ngx_pcalloc():
*
+ * clcf->escaped_name = { 0, NULL };
* clcf->root = { 0, NULL };
* clcf->limit_except = 0;
* clcf->post_action = { 0, NULL };
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index 2341fd4..002d419 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -299,6 +299,7 @@
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;