Skip to content

Commit cd89e07

Browse files
authored
[feature] Add option to support late addition of headers (#2123)
This supports the use-case where headers need to be added that depend on the socket connection (e.g. for TLS channel binding).
1 parent b4b9d5a commit cd89e07

File tree

3 files changed

+49
-2
lines changed

3 files changed

+49
-2
lines changed

doc/ws.md

+15-1
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,8 @@ This class represents a WebSocket. It extends the `EventEmitter`.
293293
- `address` {String|url.URL} The URL to which to connect.
294294
- `protocols` {String|Array} The list of subprotocols.
295295
- `options` {Object}
296+
- `finishRequest` {Function} A function which can be used to customize the
297+
headers of each http request before it is sent. See description below.
296298
- `followRedirects` {Boolean} Whether or not to follow redirects. Defaults to
297299
`false`.
298300
- `generateMask` {Function} The function used to generate the masking key. It
@@ -316,12 +318,24 @@ This class represents a WebSocket. It extends the `EventEmitter`.
316318
Options given do not have any effect if parsed from the URL given with the
317319
`address` parameter.
318320

321+
Create a new WebSocket instance.
322+
319323
`perMessageDeflate` default value is `true`. When using an object, parameters
320324
are the same of the server. The only difference is the direction of requests.
321325
For example, `serverNoContextTakeover` can be used to ask the server to disable
322326
context takeover.
323327

324-
Create a new WebSocket instance.
328+
`finishRequest` is called with arguments
329+
330+
- `request` {http.ClientRequest}
331+
- `websocket` {WebSocket}
332+
333+
for each HTTP GET request (the initial one and any caused by redirects) when it
334+
is ready to be sent, to allow for last minute customization of the headers. If
335+
`finishRequest` is set then it has the responsibility to call `request.end()`
336+
once it is done setting request headers. This is intended for niche use-cases
337+
where some headers can't be provided in advance e.g. because they depend on the
338+
underlying socket.
325339

326340
#### IPC connections
327341

lib/websocket.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -989,7 +989,11 @@ function initAsClient(websocket, address, protocols, options) {
989989
});
990990
});
991991

992-
req.end();
992+
if (opts.finishRequest) {
993+
opts.finishRequest(req, websocket);
994+
} else {
995+
req.end();
996+
}
993997
}
994998

995999
/**

test/websocket.test.js

+29
Original file line numberDiff line numberDiff line change
@@ -3857,6 +3857,35 @@ describe('WebSocket', () => {
38573857
agent
38583858
});
38593859
});
3860+
3861+
it('honors the `finishRequest` option', (done) => {
3862+
const wss = new WebSocket.Server({ port: 0 }, () => {
3863+
const ws = new WebSocket(`ws://localhost:${wss.address().port}`, {
3864+
finishRequest(request, websocket) {
3865+
process.nextTick(() => {
3866+
assert.strictEqual(request, ws._req);
3867+
assert.strictEqual(websocket, ws);
3868+
});
3869+
request.on('socket', (socket) => {
3870+
socket.on('connect', () => {
3871+
request.setHeader('Cookie', 'foo=bar');
3872+
request.end();
3873+
});
3874+
});
3875+
}
3876+
});
3877+
3878+
ws.on('close', (code) => {
3879+
assert.strictEqual(code, 1005);
3880+
wss.close(done);
3881+
});
3882+
});
3883+
3884+
wss.on('connection', (ws, req) => {
3885+
assert.strictEqual(req.headers.cookie, 'foo=bar');
3886+
ws.close();
3887+
});
3888+
});
38603889
});
38613890

38623891
describe('permessage-deflate', () => {

0 commit comments

Comments
 (0)