Closed
Description
Describe the bug
If the HTTP(S) URL requested through ngx.fetch
returns a reply that contains HTTP headers with underscores in their name, ngx.fetch
breaks.
Reproducible with njs 0.8.9
- The bug is reproducible with the latest version of njs.
- I minimized the code and NGINX configuration to the smallest possible to reproduce the issue.
To reproduce
Steps to reproduce the behavior:
- Define a test "backend" server on NGINX:
server {
server_name vm-test.ie.ff.lan;
listen 80;
location / {
limit_except GET POST {
allow all;
}
add_header DUMMY_HEADER_WITH_UNDERSCORES "blahblah";
return 200 '{"dummy":123}';
}
}
- Define the "main" NGINX server that uses the njs function with
ngx.fetch()
js_import lab from conf.d/lab.js;
server {
listen 80;
server_name sms.nginx.lab;
location /get_token_fetch {
js_content lab.getAccessTokenFetch;
}
}
- Define the njs function
export default {
getAccessTokenFetch
};
async function getAccessTokenFetch(r) {
ngx.log(ngx.INFO, '--- getAccessTokenFetch');
var accessTokenReply = await ngx.fetch('http://vm-test.ie.ff.lan',
{
verify: false,
method: 'POST',
headers:
{
'Authorization': 'Basic SUtJQTc1MTRDMjg4MENEOTc1QjkwMTA2Mjc1QTRERDM1QjVGOTVBQ0FERDc6MUYyMzhCRDAwRjgwMERERkY3RkY1NEFCNDk5RjZDRUMxMkU2ODU5MQ==',
'Content-Type': 'application/x-www-form-urlencoded'
},
body: 'scope=profile&grant_type=client_credentials'
});
var accessTokenPayload = await accessTokenReply.text();
ngx.log(ngx.INFO,'.. AccessTokenPayload [' + accessTokenPayload + ']');
var accessTokenJson = JSON.parse(accessTokenPayload);
var accessTokenStatus = accessTokenReply.status;
ngx.log(ngx.INFO,'.. AccessToken [' + accessTokenStatus + '] [' + accessTokenPayload + ']');
r.status = 200;
r.sendHeader();
r.send(accessTokenPayload);
r.finish();
}
- Trigger the issue:
$ curl -i sms.nginx.lab/get_token_fetch
HTTP/1.1 500 Internal Server Error
Server: nginx/1.27.2
Date: Wed, 12 Feb 2025 10:52:01 GMT
Content-Type: text/html
Content-Length: 177
Connection: close
<html>
<head><title>500 Internal Server Error</title></head>
<body>
<center><h1>500 Internal Server Error</h1></center>
<hr><center>nginx/1.27.2</center>
</body>
</html>
The NGINX error log reports:
2025/02/12 10:50:53 [info] 380702#380702: *319 client 192.168.2.18 closed keepalive connection
2025/02/12 10:52:01 [info] 380702#380702: *321 js: --- getAccessTokenFetch
Removing the HTTP header with underscores and testing the "working" case:
- Comment out the line
add_header DUMMY_HEADER_WITH_UNDERSCORES "blahblah";
in the "backend" server at step 1 above - Reload the NGINX configuration using
nginx -s reload
- Send the request again
curl .i sms.nginx.lab/get_token_fetch
The response is now correct:
HTTP/1.1 200 OK
Server: nginx/1.27.2
Date: Wed, 12 Feb 2025 10:50:53 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
{"dummy":123}
Expected behavior
When the line add_header DUMMY_HEADER_WITH_UNDERSCORES "blahblah";
is uncommented, the request:
curl .i sms.nginx.lab/get_token_fetch
Should return:
HTTP/1.1 200 OK
Server: nginx/1.27.2
Date: Wed, 12 Feb 2025 10:50:53 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
{"dummy":123}
Your environment
- njs 0.8.9
- NGINX Plus R33-p2
- the only enabled NGINX module is
modules/ngx_http_js_module.so
; - OS: irrelevant, but tested on Ubuntu 22.04
- Note:
vm-test.ie.ff.lan
andsms.nginx.lab
both resolve to the IP address of the NGINX instance