details: https://hg.nginx.org/njs/rev/f357972b28e3 branches: changeset: 2149:f357972b28e3 user: Dmitry Volyntsev <xei...@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 { _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel