Bug Description
Undici explicitly supports headers passed as a Headers object, but the RedirectHandler does not account for this object type in its internal cleanRequestHeaders function.
Reproducible By
-
Configure global dispatcher to use redirect interceptor
-
Use undici.request to send a request with headers constructed via new Headers(...)
import { Headers, request } from 'undici';
await request( '/local/test/url', { headers: new Headers({ 'x-my-header': true }) } );
-
Your local test server should see 'x-my-header': 'true' in the request headers
-
Your local test server should respond with a 3xx statusCode and a location: '/local/test/alt-url' header
-
Undici should follow the redirect and make a request to the new location
-
Your local test server WILL NOT see 'x-my-header': 'true' in the request headers
Compare to:
-
same as above
-
Send the request this way instead:
await request( '/local/test/url', { headers: { 'x-my-header': true } } );
-
same as above
-
same as above
-
same as above
-
Your local test server WILL see 'x-my-header': 'true' in the request headers
Expected Behavior
- Headers on the initial request should be repeated on the redirect request(s) for all supported ways to pass headers
Logs & Screenshots
I believe I've tracked this down to this logic inside cleanRequestHeaders:
// ...
} else if (headers && typeof headers === 'object') {
for (const key of Object.keys(headers)) {
if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) {
ret.push(key, headers[key])
}
}
}
// ...
For headers constructed with new Headers(...), the typeof headers === 'object' condition will return true, but Object.keys(...) does not behave as expected on a Headers object. As a result, this for loop does not push any keys/values into ret.
Environment
- macOS 15.0.1 (current)
- Node v20.16.0 (LTS, but two minors behind)
Additional context
Bug Description
Undici explicitly supports headers passed as a Headers object, but the
RedirectHandlerdoes not account for this object type in its internal cleanRequestHeaders function.Reproducible By
Configure global dispatcher to use redirect interceptor
Use
undici.requestto send a request with headers constructed vianew Headers(...)Your local test server should see
'x-my-header': 'true'in the request headersYour local test server should respond with a
3xxstatusCode and alocation: '/local/test/alt-url'headerUndici should follow the redirect and make a request to the new location
Your local test server WILL NOT see
'x-my-header': 'true'in the request headersCompare to:
same as above
Send the request this way instead:
same as above
same as above
same as above
Your local test server WILL see
'x-my-header': 'true'in the request headersExpected Behavior
Logs & Screenshots
I believe I've tracked this down to this logic inside
cleanRequestHeaders:For
headersconstructed withnew Headers(...), thetypeof headers === 'object'condition will returntrue, butObject.keys(...)does not behave as expected on aHeadersobject. As a result, this for loop does not push any keys/values intoret.Environment
Additional context