mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 10:28:47 +00:00
fix: test-http-response-setheaders.js
This commit is contained in:
@@ -16,9 +16,9 @@ const enum NodeHTTPIncomingRequestType {
|
||||
NodeHTTPResponse,
|
||||
}
|
||||
const enum NodeHTTPHeaderState {
|
||||
none,
|
||||
assigned,
|
||||
sent,
|
||||
none = 0,
|
||||
assigned = 1 << 0,
|
||||
sent = 1 << 1,
|
||||
}
|
||||
const enum NodeHTTPBodyReadState {
|
||||
none,
|
||||
@@ -198,7 +198,7 @@ function validateMsecs(numberlike: any, field: string) {
|
||||
if (numberlike > TIMEOUT_MAX) {
|
||||
process.emitWarning(
|
||||
`${numberlike} does not fit into a 32-bit signed integer.` + `\nTimer duration was truncated to ${TIMEOUT_MAX}.`,
|
||||
"TimeoutOverflowWarning"
|
||||
"TimeoutOverflowWarning",
|
||||
);
|
||||
return TIMEOUT_MAX;
|
||||
}
|
||||
@@ -1668,7 +1668,7 @@ const OutgoingMessagePrototype = {
|
||||
},
|
||||
|
||||
removeHeader(name) {
|
||||
if (this[headerStateSymbol] === NodeHTTPHeaderState.sent) {
|
||||
if (this[headerStateSymbol] >= NodeHTTPHeaderState.assigned) {
|
||||
throw $ERR_HTTP_HEADERS_SENT("Cannot remove header after headers have been sent.");
|
||||
}
|
||||
const headers = this[headersSymbol];
|
||||
@@ -1683,6 +1683,41 @@ const OutgoingMessagePrototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
setHeaders(headers) {
|
||||
if (this[headerStateSymbol] >= NodeHTTPHeaderState.assigned) {
|
||||
throw $ERR_HTTP_HEADERS_SENT("set");
|
||||
}
|
||||
|
||||
if (!headers || Array.isArray(headers) || typeof headers.keys !== "function" || typeof headers.get !== "function") {
|
||||
throw $ERR_INVALID_ARG_TYPE("headers", ["Headers", "Map"], headers);
|
||||
}
|
||||
|
||||
// Headers object joins multiple cookies with a comma when using
|
||||
// the getter to retrieve the value,
|
||||
// unless iterating over the headers directly.
|
||||
// We also cannot safely split by comma.
|
||||
// To avoid setHeader overwriting the previous value we push
|
||||
// set-cookie values in array and set them all at once.
|
||||
const cookies = [];
|
||||
|
||||
for (const [key, value] of headers) {
|
||||
if (key === "set-cookie") {
|
||||
if (Array.isArray(value)) {
|
||||
cookies.push(...value);
|
||||
} else {
|
||||
cookies.push(value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this.setHeader(key, value);
|
||||
}
|
||||
if (cookies.length) {
|
||||
this.setHeader("set-cookie", cookies);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
hasHeader(name) {
|
||||
const headers = this[headersSymbol];
|
||||
if (!headers) return false;
|
||||
@@ -1930,9 +1965,7 @@ const ServerResponsePrototype = {
|
||||
_removedContLen: false,
|
||||
_hasBody: true,
|
||||
get headersSent() {
|
||||
return (
|
||||
this[headerStateSymbol] === NodeHTTPHeaderState.sent || this[headerStateSymbol] === NodeHTTPHeaderState.assigned
|
||||
);
|
||||
return this[headerStateSymbol] >= NodeHTTPHeaderState.assigned;
|
||||
},
|
||||
set headersSent(value) {
|
||||
this[headerStateSymbol] = value ? NodeHTTPHeaderState.sent : NodeHTTPHeaderState.none;
|
||||
@@ -2208,6 +2241,41 @@ const ServerResponsePrototype = {
|
||||
return this;
|
||||
},
|
||||
|
||||
setHeaders(headers) {
|
||||
if (this[headerStateSymbol] >= NodeHTTPHeaderState.assigned) {
|
||||
throw $ERR_HTTP_HEADERS_SENT("set");
|
||||
}
|
||||
|
||||
if (!headers || Array.isArray(headers) || typeof headers.keys !== "function" || typeof headers.get !== "function") {
|
||||
throw $ERR_INVALID_ARG_TYPE("headers", ["Headers", "Map"], headers);
|
||||
}
|
||||
|
||||
// Headers object joins multiple cookies with a comma when using
|
||||
// the getter to retrieve the value,
|
||||
// unless iterating over the headers directly.
|
||||
// We also cannot safely split by comma.
|
||||
// To avoid setHeader overwriting the previous value we push
|
||||
// set-cookie values in array and set them all at once.
|
||||
const cookies = [];
|
||||
|
||||
for (const [key, value] of headers) {
|
||||
if (key === "set-cookie") {
|
||||
if (Array.isArray(value)) {
|
||||
cookies.push(...value);
|
||||
} else {
|
||||
cookies.push(value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
this.setHeader(key, value);
|
||||
}
|
||||
if (cookies.length) {
|
||||
this.setHeader("set-cookie", cookies);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
assignSocket(socket) {
|
||||
if (socket._httpMessage) {
|
||||
throw ERR_HTTP_SOCKET_ASSIGNED();
|
||||
|
||||
174
test/js/node/test/parallel/test-http-response-setheaders.js
Normal file
174
test/js/node/test/parallel/test-http-response-setheaders.js
Normal file
@@ -0,0 +1,174 @@
|
||||
'use strict';
|
||||
const common = require('../common');
|
||||
const http = require('http');
|
||||
const assert = require('assert');
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
res.writeHead(200); // Headers already sent
|
||||
const headers = new globalThis.Headers({ foo: '1' });
|
||||
assert.throws(() => {
|
||||
res.setHeaders(headers);
|
||||
}, {
|
||||
code: 'ERR_HTTP_HEADERS_SENT'
|
||||
});
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert.strictEqual(res.headers.foo, undefined);
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
assert.throws(() => {
|
||||
res.setHeaders(['foo', '1']);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
assert.throws(() => {
|
||||
res.setHeaders({ foo: '1' });
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
assert.throws(() => {
|
||||
res.setHeaders(null);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
assert.throws(() => {
|
||||
res.setHeaders(undefined);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
assert.throws(() => {
|
||||
res.setHeaders('test');
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
assert.throws(() => {
|
||||
res.setHeaders(1);
|
||||
}, {
|
||||
code: 'ERR_INVALID_ARG_TYPE'
|
||||
});
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert.strictEqual(res.headers.foo, undefined);
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
const headers = new globalThis.Headers({ foo: '1', bar: '2' });
|
||||
res.setHeaders(headers);
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
assert.strictEqual(res.headers.foo, '1');
|
||||
assert.strictEqual(res.headers.bar, '2');
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
const headers = new globalThis.Headers({ foo: '1', bar: '2' });
|
||||
res.setHeaders(headers);
|
||||
res.writeHead(200, ['foo', '3']);
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
assert.strictEqual(res.headers.foo, '3'); // Override by writeHead
|
||||
assert.strictEqual(res.headers.bar, '2');
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
const headers = new Map([['foo', '1'], ['bar', '2']]);
|
||||
res.setHeaders(headers);
|
||||
res.writeHead(200);
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert.strictEqual(res.statusCode, 200);
|
||||
assert.strictEqual(res.headers.foo, '1');
|
||||
assert.strictEqual(res.headers.bar, '2');
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
const headers = new Headers();
|
||||
headers.append('Set-Cookie', 'a=b');
|
||||
headers.append('Set-Cookie', 'c=d');
|
||||
res.setHeaders(headers);
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert(Array.isArray(res.headers['set-cookie']));
|
||||
assert.strictEqual(res.headers['set-cookie'].length, 2);
|
||||
assert.strictEqual(res.headers['set-cookie'][0], 'a=b');
|
||||
assert.strictEqual(res.headers['set-cookie'][1], 'c=d');
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
{
|
||||
const server = http.createServer({ requireHostHeader: false }, common.mustCall((req, res) => {
|
||||
const headers = new Map();
|
||||
headers.set('Set-Cookie', ['a=b', 'c=d']);
|
||||
res.setHeaders(headers);
|
||||
res.end();
|
||||
}));
|
||||
|
||||
server.listen(0, common.mustCall(() => {
|
||||
http.get({ port: server.address().port }, (res) => {
|
||||
assert(Array.isArray(res.headers['set-cookie']));
|
||||
assert.strictEqual(res.headers['set-cookie'].length, 2);
|
||||
assert.strictEqual(res.headers['set-cookie'][0], 'a=b');
|
||||
assert.strictEqual(res.headers['set-cookie'][1], 'c=d');
|
||||
res.resume().on('end', common.mustCall(() => {
|
||||
server.close();
|
||||
}));
|
||||
});
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user