[njs] HTTP: fixed setting of Location header.
Dmitry Volyntsev
xeioex at nginx.com
Tue Jun 6 01:31:41 UTC 2023
details: https://hg.nginx.org/njs/rev/f357972b28e3
branches:
changeset: 2149:f357972b28e3
user: Dmitry Volyntsev <xeioex at nginx.com>
date: Mon Jun 05 18:21:06 2023 -0700
description:
HTTP: fixed setting of Location header.
Previously, r.headersOut['Location'] setter did not update
r->headers_out.location. As a result a client might get two
Location headers.
This fixes #648 issue on Github.
diffstat:
nginx/ngx_http_js_module.c | 38 ++++++++++++++++++++++++++++++++++-
nginx/t/js_headers.t | 48 ++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 82 insertions(+), 4 deletions(-)
diffs (166 lines):
diff -r a5affeb25558 -r f357972b28e3 nginx/ngx_http_js_module.c
--- a/nginx/ngx_http_js_module.c Mon Jun 05 18:21:06 2023 -0700
+++ b/nginx/ngx_http_js_module.c Mon Jun 05 18:21:06 2023 -0700
@@ -125,6 +125,9 @@ static njs_int_t ngx_http_js_content_len
static njs_int_t ngx_http_js_content_type122(njs_vm_t *vm,
ngx_http_request_t *r, ngx_list_t *headers, njs_str_t *name,
njs_value_t *setval, njs_value_t *retval);
+static njs_int_t ngx_http_js_location122(njs_vm_t *vm, ngx_http_request_t *r,
+ ngx_list_t *headers, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
#endif
static njs_int_t ngx_http_js_ext_keys_header_out(njs_vm_t *vm,
njs_value_t *value, njs_value_t *keys);
@@ -219,6 +222,9 @@ static njs_int_t ngx_http_js_content_len
static njs_int_t ngx_http_js_content_type(njs_vm_t *vm, ngx_http_request_t *r,
unsigned flags, njs_str_t *name, njs_value_t *setval,
njs_value_t *retval);
+static njs_int_t ngx_http_js_location(njs_vm_t *vm, ngx_http_request_t *r,
+ unsigned flags, njs_str_t *name, njs_value_t *setval,
+ njs_value_t *retval);
static njs_host_event_t ngx_http_js_set_timer(njs_external_ptr_t external,
uint64_t delay, njs_vm_event_t vm_event);
@@ -1482,7 +1488,7 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
{ njs_str("Etag"), ngx_http_js_header_single },
{ njs_str("Expires"), ngx_http_js_header_single },
{ njs_str("Last-Modified"), ngx_http_js_header_single },
- { njs_str("Location"), ngx_http_js_header_single },
+ { njs_str("Location"), ngx_http_js_location122 },
{ njs_str("Set-Cookie"), ngx_http_js_header_array },
{ njs_str("Retry-After"), ngx_http_js_header_single },
{ njs_str(""), ngx_http_js_header_generic },
@@ -1494,7 +1500,7 @@ ngx_http_js_ext_header_out(njs_vm_t *vm,
{ njs_str("Etag"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
{ njs_str("Expires"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
{ njs_str("Last-Modified"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
- { njs_str("Location"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
+ { njs_str("Location"), 0, ngx_http_js_location },
{ njs_str("Set-Cookie"), NJS_HEADER_ARRAY, ngx_http_js_header_out },
{ njs_str("Retry-After"), NJS_HEADER_SINGLE, ngx_http_js_header_out },
{ njs_str(""), 0, ngx_http_js_header_out },
@@ -1905,6 +1911,14 @@ ngx_http_js_content_type122(njs_vm_t *vm
{
return ngx_http_js_content_type(vm, r, 0, v, setval, retval);
}
+
+
+static njs_int_t
+ngx_http_js_location122(njs_vm_t *vm, ngx_http_request_t *r,
+ ngx_list_t *headers, njs_str_t *v, njs_value_t *setval, njs_value_t *retval)
+{
+ return ngx_http_js_location(vm, r, 0, v, setval, retval);
+}
#endif
@@ -3905,6 +3919,26 @@ ngx_http_js_content_type(njs_vm_t *vm, n
}
+static njs_int_t
+ngx_http_js_location(njs_vm_t *vm, ngx_http_request_t *r, unsigned flags,
+ njs_str_t *v, njs_value_t *setval, njs_value_t *retval)
+{
+ njs_int_t rc;
+ ngx_table_elt_t *h;
+
+ rc = ngx_http_js_header_out_special(vm, r, v, setval, retval, &h);
+ if (rc == NJS_ERROR) {
+ return NJS_ERROR;
+ }
+
+ if (setval != NULL || retval == NULL) {
+ r->headers_out.location = h;
+ }
+
+ return NJS_OK;
+}
+
+
static njs_host_event_t
ngx_http_js_set_timer(njs_external_ptr_t external, uint64_t delay,
njs_vm_event_t vm_event)
diff -r a5affeb25558 -r f357972b28e3 nginx/t/js_headers.t
--- a/nginx/t/js_headers.t Mon Jun 05 18:21:06 2023 -0700
+++ b/nginx/t/js_headers.t Mon Jun 05 18:21:06 2023 -0700
@@ -84,6 +84,18 @@ http {
js_content test.content_encoding_arr;
}
+ location /location {
+ js_content test.location;
+ }
+
+ location /location_sr {
+ js_content test.location_sr;
+ }
+
+ location /_redirect {
+ return 307 $request_uri;
+ }
+
location /headers_list {
js_content test.headers_list;
}
@@ -233,6 +245,29 @@ EOF
r.return(200);
}
+ function location(r) {
+ if (njs.version_number >= 0x000705) {
+ var lc = r.headersOut['Location'];
+ if (lc !== undefined) {
+ r.return(500, `Location "\${lc}" is not empty`);
+ return;
+ }
+ }
+
+ delete r.headersOut['Location'];
+ r.headersOut['Location'] = '';
+ r.headersOut['Location'] = 'test';
+ delete r.headersOut['Location'];
+ r.headersOut['Location'] = 'loc';
+ r.return(200);
+ }
+
+ async function location_sr(r) {
+ let resp = await r.subrequest('/_redirect');
+ r.headersOut['Location'] = resp.headersOut['Location'];
+ r.return(resp.status, 'loc');
+ }
+
function content_encoding_arr(r) {
r.headersOut['Content-Encoding'] = 'test';
r.headersOut['Content-Encoding'] = [];
@@ -402,12 +437,12 @@ EOF
hdr_in, raw_hdr_in, hdr_sorted_keys, foo_in, ifoo_in,
hdr_out, raw_hdr_out, hdr_out_array, hdr_out_single,
hdr_out_set_cookie, ihdr_out, hdr_out_special_set,
- copy_subrequest_hdrs, subrequest};
+ copy_subrequest_hdrs, subrequest, location, location_sr};
EOF
-$t->try_run('no njs')->plan(42);
+$t->try_run('no njs')->plan(44);
###############################################################################
@@ -546,6 +581,15 @@ like(http_get('/copy_subrequest_hdrs'),
}
+TODO: {
+local $TODO = 'not yet' unless has_version('0.8.0');
+
+like(http_get('/location'), qr/Location: loc/, 'set location');
+unlike(http_get('/location_sr'), qr/Location: \/location_sr/,
+ 'location redirect');
+
+}
+
###############################################################################
sub has_version {
More information about the nginx-devel
mailing list