Skip to content

Commit 1ec6270

Browse files
marco-ippolitoruyadorno
authored andcommitted
http: res.setHeaders first implementation
Backport-PR-URL: #46272 PR-URL: #46109 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Paolo Insogna <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]>
1 parent e0fddab commit 1ec6270

File tree

3 files changed

+197
-0
lines changed

3 files changed

+197
-0
lines changed

doc/api/http.md

+44
Original file line numberDiff line numberDiff line change
@@ -2969,6 +2969,48 @@ Sets a single header value. If the header already exists in the to-be-sent
29692969
headers, its value will be replaced. Use an array of strings to send multiple
29702970
headers with the same name.
29712971

2972+
### `outgoingMessage.setHeaders(headers)`
2973+
2974+
<!-- YAML
2975+
added: REPLACEME
2976+
-->
2977+
2978+
* `headers` {Headers|Map}
2979+
* Returns: {http.ServerResponse}
2980+
2981+
Returns the response object.
2982+
2983+
Sets multiple header values for implicit headers.
2984+
`headers` must be an instance of [`Headers`][] or `Map`,
2985+
if a header already exists in the to-be-sent headers,
2986+
its value will be replaced.
2987+
2988+
```js
2989+
const headers = new Headers({ foo: 'bar' });
2990+
response.setHeaders(headers);
2991+
```
2992+
2993+
or
2994+
2995+
```js
2996+
const headers = new Map([['foo', 'bar']]);
2997+
res.setHeaders(headers);
2998+
```
2999+
3000+
When headers have been set with [`outgoingMessage.setHeaders()`][],
3001+
they will be merged with any headers passed to [`response.writeHead()`][],
3002+
with the headers passed to [`response.writeHead()`][] given precedence.
3003+
3004+
```js
3005+
// Returns content-type = text/plain
3006+
const server = http.createServer((req, res) => {
3007+
const headers = new Headers({ 'Content-Type': 'text/html' });
3008+
res.setHeaders(headers);
3009+
res.writeHead(200, { 'Content-Type': 'text/plain' });
3010+
res.end('ok');
3011+
});
3012+
```
3013+
29723014
### `outgoingMessage.setTimeout(msesc[, callback])`
29733015

29743016
<!-- YAML
@@ -3761,6 +3803,7 @@ Set the maximum number of idle HTTP parsers.
37613803
[`Buffer.byteLength()`]: buffer.md#static-method-bufferbytelengthstring-encoding
37623804
[`Duplex`]: stream.md#class-streamduplex
37633805
[`HPE_HEADER_OVERFLOW`]: errors.md#hpe_header_overflow
3806+
[`Headers`]: globals.md#class-headers
37643807
[`TypeError`]: errors.md#class-typeerror
37653808
[`URL`]: url.md#the-whatwg-url-api
37663809
[`agent.createConnection()`]: #agentcreateconnectionoptions-callback
@@ -3787,6 +3830,7 @@ Set the maximum number of idle HTTP parsers.
37873830
[`net.createConnection()`]: net.md#netcreateconnectionoptions-connectlistener
37883831
[`new URL()`]: url.md#new-urlinput-base
37893832
[`outgoingMessage.setHeader(name, value)`]: #outgoingmessagesetheadername-value
3833+
[`outgoingMessage.setHeaders()`]: #outgoingmessagesetheadersheaders
37903834
[`outgoingMessage.socket`]: #outgoingmessagesocket
37913835
[`removeHeader(name)`]: #requestremoveheadername
37923836
[`request.destroy()`]: #requestdestroyerror

lib/_http_outgoing.js

+22
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,28 @@ OutgoingMessage.prototype.setHeader = function setHeader(name, value) {
672672
return this;
673673
};
674674

675+
OutgoingMessage.prototype.setHeaders = function setHeaders(headers) {
676+
if (this._header) {
677+
throw new ERR_HTTP_HEADERS_SENT('set');
678+
}
679+
680+
681+
if (
682+
!headers ||
683+
ArrayIsArray(headers) ||
684+
typeof headers.keys !== 'function' ||
685+
typeof headers.get !== 'function'
686+
) {
687+
throw new ERR_INVALID_ARG_TYPE('headers', ['Headers', 'Map'], headers);
688+
}
689+
690+
for (const key of headers.keys()) {
691+
this.setHeader(key, headers.get(key));
692+
}
693+
694+
return this;
695+
};
696+
675697
OutgoingMessage.prototype.appendHeader = function appendHeader(name, value) {
676698
if (this._header) {
677699
throw new ERR_HTTP_HEADERS_SENT('append');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
'use strict';
2+
const common = require('../common');
3+
const http = require('http');
4+
const assert = require('assert');
5+
6+
{
7+
const server = http.createServer(common.mustCall((req, res) => {
8+
res.writeHead(200); // Headers already sent
9+
const headers = new globalThis.Headers({ foo: '1' });
10+
assert.throws(() => {
11+
res.setHeaders(headers);
12+
}, {
13+
code: 'ERR_HTTP_HEADERS_SENT'
14+
});
15+
res.end();
16+
}));
17+
18+
server.listen(0, common.mustCall(() => {
19+
http.get({ port: server.address().port }, (res) => {
20+
assert.strictEqual(res.headers.foo, undefined);
21+
res.resume().on('end', common.mustCall(() => {
22+
server.close();
23+
}));
24+
});
25+
}));
26+
}
27+
28+
{
29+
const server = http.createServer(common.mustCall((req, res) => {
30+
assert.throws(() => {
31+
res.setHeaders(['foo', '1']);
32+
}, {
33+
code: 'ERR_INVALID_ARG_TYPE'
34+
});
35+
assert.throws(() => {
36+
res.setHeaders({ foo: '1' });
37+
}, {
38+
code: 'ERR_INVALID_ARG_TYPE'
39+
});
40+
assert.throws(() => {
41+
res.setHeaders(null);
42+
}, {
43+
code: 'ERR_INVALID_ARG_TYPE'
44+
});
45+
assert.throws(() => {
46+
res.setHeaders(undefined);
47+
}, {
48+
code: 'ERR_INVALID_ARG_TYPE'
49+
});
50+
assert.throws(() => {
51+
res.setHeaders('test');
52+
}, {
53+
code: 'ERR_INVALID_ARG_TYPE'
54+
});
55+
assert.throws(() => {
56+
res.setHeaders(1);
57+
}, {
58+
code: 'ERR_INVALID_ARG_TYPE'
59+
});
60+
res.end();
61+
}));
62+
63+
server.listen(0, common.mustCall(() => {
64+
http.get({ port: server.address().port }, (res) => {
65+
assert.strictEqual(res.headers.foo, undefined);
66+
res.resume().on('end', common.mustCall(() => {
67+
server.close();
68+
}));
69+
});
70+
}));
71+
}
72+
73+
{
74+
const server = http.createServer(common.mustCall((req, res) => {
75+
const headers = new globalThis.Headers({ foo: '1', bar: '2' });
76+
res.setHeaders(headers);
77+
res.writeHead(200);
78+
res.end();
79+
}));
80+
81+
server.listen(0, common.mustCall(() => {
82+
http.get({ port: server.address().port }, (res) => {
83+
assert.strictEqual(res.statusCode, 200);
84+
assert.strictEqual(res.headers.foo, '1');
85+
assert.strictEqual(res.headers.bar, '2');
86+
res.resume().on('end', common.mustCall(() => {
87+
server.close();
88+
}));
89+
});
90+
}));
91+
}
92+
93+
{
94+
const server = http.createServer(common.mustCall((req, res) => {
95+
const headers = new globalThis.Headers({ foo: '1', bar: '2' });
96+
res.setHeaders(headers);
97+
res.writeHead(200, ['foo', '3']);
98+
res.end();
99+
}));
100+
101+
server.listen(0, common.mustCall(() => {
102+
http.get({ port: server.address().port }, (res) => {
103+
assert.strictEqual(res.statusCode, 200);
104+
assert.strictEqual(res.headers.foo, '3'); // Override by writeHead
105+
assert.strictEqual(res.headers.bar, '2');
106+
res.resume().on('end', common.mustCall(() => {
107+
server.close();
108+
}));
109+
});
110+
}));
111+
}
112+
113+
{
114+
const server = http.createServer(common.mustCall((req, res) => {
115+
const headers = new Map([['foo', '1'], ['bar', '2']]);
116+
res.setHeaders(headers);
117+
res.writeHead(200);
118+
res.end();
119+
}));
120+
121+
server.listen(0, common.mustCall(() => {
122+
http.get({ port: server.address().port }, (res) => {
123+
assert.strictEqual(res.statusCode, 200);
124+
assert.strictEqual(res.headers.foo, '1');
125+
assert.strictEqual(res.headers.bar, '2');
126+
res.resume().on('end', common.mustCall(() => {
127+
server.close();
128+
}));
129+
});
130+
}));
131+
}

0 commit comments

Comments
 (0)