Skip to content

Commit a3545bc

Browse files
committed
fix(node-fetch): respect set-cookies given in HeadersInit
1 parent 14cd02a commit a3545bc

File tree

3 files changed

+33
-10
lines changed

3 files changed

+33
-10
lines changed

.changeset/curvy-insects-cheer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@whatwg-node/node-fetch': patch
3+
---
4+
5+
Fix the bug when `set-cookies` given is ignored in `HeadersInit`

packages/node-fetch/src/Headers.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ export class PonyfillHeaders implements Headers {
1111
private _map: Map<string, string> | undefined;
1212
private objectNormalizedKeysOfHeadersInit: string[] = [];
1313
private objectOriginalKeysOfHeadersInit: string[] = [];
14-
private _setCookies: string[] = [];
14+
private _setCookies?: string[];
1515

1616
constructor(private headersInit?: PonyfillHeadersInit) {}
1717

1818
// perf: we don't need to build `this.map` for Requests, as we can access the headers directly
1919
private _get(key: string) {
2020
const normalized = key.toLowerCase();
21-
if (normalized === 'set-cookie') {
21+
if (normalized === 'set-cookie' && this._setCookies?.length) {
2222
return this._setCookies.join(', ');
2323
}
2424
// If the map is built, reuse it
@@ -67,6 +67,7 @@ export class PonyfillHeaders implements Headers {
6767
this.headersInit.forEach(([key, value]) => {
6868
const normalizedKey = key.toLowerCase();
6969
if (normalizedKey === 'set-cookie') {
70+
this._setCookies ||= [];
7071
this._setCookies.push(value);
7172
return;
7273
}
@@ -76,6 +77,7 @@ export class PonyfillHeaders implements Headers {
7677
this._map = new Map();
7778
this.headersInit.forEach((value, key) => {
7879
if (key === 'set-cookie') {
80+
this._setCookies ||= [];
7981
this._setCookies.push(value);
8082
return;
8183
}
@@ -88,6 +90,7 @@ export class PonyfillHeaders implements Headers {
8890
if (initValue != null) {
8991
const normalizedKey = initKey.toLowerCase();
9092
if (normalizedKey === 'set-cookie') {
93+
this._setCookies ||= [];
9194
this._setCookies.push(initValue);
9295
continue;
9396
}
@@ -106,6 +109,7 @@ export class PonyfillHeaders implements Headers {
106109
append(name: string, value: string): void {
107110
const key = name.toLowerCase();
108111
if (key === 'set-cookie') {
112+
this._setCookies ||= [];
109113
this._setCookies.push(value);
110114
return;
111115
}
@@ -121,12 +125,12 @@ export class PonyfillHeaders implements Headers {
121125
return null;
122126
}
123127

124-
return value;
128+
return value.toString();
125129
}
126130

127131
has(name: string): boolean {
128132
if (name === 'set-cookie') {
129-
return this._setCookies.length > 0;
133+
return !!this._setCookies?.length;
130134
}
131135
return !!this._get(name); // we might need to check if header exists and not just check if it's not nullable
132136
}
@@ -150,7 +154,7 @@ export class PonyfillHeaders implements Headers {
150154
}
151155

152156
forEach(callback: (value: string, key: string, parent: Headers) => void): void {
153-
this._setCookies.forEach(setCookie => {
157+
this._setCookies?.forEach(setCookie => {
154158
callback(setCookie, 'set-cookie', this);
155159
});
156160
if (!this._map) {
@@ -179,7 +183,7 @@ export class PonyfillHeaders implements Headers {
179183
}
180184

181185
*_keys(): IterableIterator<string> {
182-
if (this._setCookies.length) {
186+
if (this._setCookies?.length) {
183187
yield 'set-cookie';
184188
}
185189
if (!this._map) {
@@ -204,7 +208,9 @@ export class PonyfillHeaders implements Headers {
204208
}
205209

206210
*_values(): IterableIterator<string> {
207-
yield* this._setCookies;
211+
if (this._setCookies?.length) {
212+
yield* this._setCookies;
213+
}
208214
if (!this._map) {
209215
if (this.headersInit) {
210216
if (Array.isArray(this.headersInit)) {
@@ -227,7 +233,9 @@ export class PonyfillHeaders implements Headers {
227233
}
228234

229235
*_entries(): IterableIterator<[string, string]> {
230-
yield* this._setCookies.map(cookie => ['set-cookie', cookie] as [string, string]);
236+
if (this._setCookies?.length) {
237+
yield* this._setCookies.map(cookie => ['set-cookie', cookie] as [string, string]);
238+
}
231239
if (!this._map) {
232240
if (this.headersInit) {
233241
if (Array.isArray(this.headersInit)) {
@@ -250,7 +258,7 @@ export class PonyfillHeaders implements Headers {
250258
}
251259

252260
getSetCookie() {
253-
return this._setCookies;
261+
return this._setCookies || [];
254262
}
255263

256264
[Symbol.iterator](): HeadersIterator<[string, string]> {
@@ -261,7 +269,7 @@ export class PonyfillHeaders implements Headers {
261269
const record: Record<string, string[] | string> = {};
262270
this.forEach((value, key) => {
263271
if (key === 'set-cookie') {
264-
record['set-cookie'] = this._setCookies;
272+
record['set-cookie'] = this._setCookies || [];
265273
} else {
266274
record[key] = value?.includes(',') ? value.split(',').map(el => el.trim()) : value;
267275
}

packages/node-fetch/tests/Headers.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,14 @@ describe('Headers', () => {
6161
headers.set('X-Header', null!);
6262
expect(inspect(headers)).toBe("Headers { 'x-header': null }");
6363
});
64+
describe('Set-Cookie', () => {
65+
it('handles values in the given map', () => {
66+
const init = {
67+
// Record<string, string[]> is not a HeadersInit actually
68+
'set-cookie': ['a=b', 'c=d'],
69+
} as any;
70+
const headers = new PonyfillHeaders(init);
71+
expect(headers.get('Set-Cookie')).toBe('a=b,c=d');
72+
});
73+
});
6474
});

0 commit comments

Comments
 (0)