Skip to content

Commit 5019b54

Browse files
marco-ippolitojuanarbol
authored andcommitted
http: res.setHeaders first implementation
PR-URL: #46109 Backport-PR-URL: #46365 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Paolo Insogna <paolo@cowtech.it> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent 3ea53c5 commit 5019b54

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
@@ -2950,6 +2950,48 @@ Sets a single header value. If the header already exists in the to-be-sent
29502950
headers, its value will be replaced. Use an array of strings to send multiple
29512951
headers with the same name.
29522952

2953+
### `outgoingMessage.setHeaders(headers)`
2954+
2955+
<!-- YAML
2956+
added: REPLACEME
2957+
-->
2958+
2959+
* `headers` {Headers|Map}
2960+
* Returns: {http.ServerResponse}
2961+
2962+
Returns the response object.
2963+
2964+
Sets multiple header values for implicit headers.
2965+
`headers` must be an instance of [`Headers`][] or `Map`,
2966+
if a header already exists in the to-be-sent headers,
2967+
its value will be replaced.
2968+
2969+
```js
2970+
const headers = new Headers({ foo: 'bar' });
2971+
response.setHeaders(headers);
2972+
```
2973+
2974+
or
2975+
2976+
```js
2977+
const headers = new Map([['foo', 'bar']]);
2978+
res.setHeaders(headers);
2979+
```
2980+
2981+
When headers have been set with [`outgoingMessage.setHeaders()`][],
2982+
they will be merged with any headers passed to [`response.writeHead()`][],
2983+
with the headers passed to [`response.writeHead()`][] given precedence.
2984+
2985+
```js
2986+
// Returns content-type = text/plain
2987+
const server = http.createServer((req, res) => {
2988+
const headers = new Headers({ 'Content-Type': 'text/html' });
2989+
res.setHeaders(headers);
2990+
res.writeHead(200, { 'Content-Type': 'text/plain' });
2991+
res.end('ok');
2992+
});
2993+
```
2994+
29532995
### `outgoingMessage.setTimeout(msesc[, callback])`
29542996

29552997
<!-- YAML
@@ -3721,6 +3763,7 @@ Set the maximum number of idle HTTP parsers.
37213763
[`Buffer.byteLength()`]: buffer.md#static-method-bufferbytelengthstring-encoding
37223764
[`Duplex`]: stream.md#class-streamduplex
37233765
[`HPE_HEADER_OVERFLOW`]: errors.md#hpe_header_overflow
3766+
[`Headers`]: globals.md#class-headers
37243767
[`TypeError`]: errors.md#class-typeerror
37253768
[`URL`]: url.md#the-whatwg-url-api
37263769
[`agent.createConnection()`]: #agentcreateconnectionoptions-callback
@@ -3747,6 +3790,7 @@ Set the maximum number of idle HTTP parsers.
37473790
[`net.createConnection()`]: net.md#netcreateconnectionoptions-connectlistener
37483791
[`new URL()`]: url.md#new-urlinput-base
37493792
[`outgoingMessage.setHeader(name, value)`]: #outgoingmessagesetheadername-value
3793+
[`outgoingMessage.setHeaders()`]: #outgoingmessagesetheadersheaders
37503794
[`outgoingMessage.socket`]: #outgoingmessagesocket
37513795
[`removeHeader(name)`]: #requestremoveheadername
37523796
[`request.destroy()`]: #requestdestroyerror

lib/_http_outgoing.js

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

676+
OutgoingMessage.prototype.setHeaders = function setHeaders(headers) {
677+
if (this._header) {
678+
throw new ERR_HTTP_HEADERS_SENT('set');
679+
}
680+
681+
682+
if (
683+
!headers ||
684+
ArrayIsArray(headers) ||
685+
typeof headers.keys !== 'function' ||
686+
typeof headers.get !== 'function'
687+
) {
688+
throw new ERR_INVALID_ARG_TYPE('headers', ['Headers', 'Map'], headers);
689+
}
690+
691+
for (const key of headers.keys()) {
692+
this.setHeader(key, headers.get(key));
693+
}
694+
695+
return this;
696+
};
697+
676698
OutgoingMessage.prototype.appendHeader = function appendHeader(name, value) {
677699
if (this._header) {
678700
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({ requireHostHeader: false }, 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({ requireHostHeader: false }, 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({ requireHostHeader: false }, 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({ requireHostHeader: false }, 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({ requireHostHeader: false }, 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)