Skip to content

Commit

Permalink
fix(fetch): fix headers.entries/values/forEach iteration for `S…
Browse files Browse the repository at this point in the history
…et-Cookie` headers (#89)

* Fix headers.entries/values/forEach handling of setCookie

* Fix headers.entries/values/forEach handling of setCookie

* Add changeset

* chore: fix changeset

---------

Co-authored-by: Matt Brophy <[email protected]>
  • Loading branch information
MichaelDeBoey and brophdawg11 authored Aug 28, 2023
1 parent ace4223 commit 3c20536
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 3 deletions.
5 changes: 5 additions & 0 deletions .changeset/good-badgers-sleep.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@web-std/fetch": patch
---

Fix `headers.entries`/`values`/`forEach` iteration for `Set-Cookie` headers
27 changes: 24 additions & 3 deletions packages/fetch/src/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,14 @@ export default class Headers extends URLSearchParams {
*/
forEach(callback, thisArg = undefined) {
for (const name of this.keys()) {
Reflect.apply(callback, thisArg, [this.get(name), name, this]);
if (name.toLowerCase() === 'set-cookie') {
let cookies = this.getAll(name);
while (cookies.length > 0) {
Reflect.apply(callback, thisArg, [cookies.shift(), name, this])
}
} else {
Reflect.apply(callback, thisArg, [this.get(name), name, this]);
}
}
}

Expand All @@ -199,7 +206,14 @@ export default class Headers extends URLSearchParams {
*/
* values() {
for (const name of this.keys()) {
yield /** @type {string} */(this.get(name));
if (name.toLowerCase() === 'set-cookie') {
let cookies = this.getAll(name);
while (cookies.length > 0) {
yield /** @type {string} */(cookies.shift());
}
} else {
yield /** @type {string} */(this.get(name));
}
}
}

Expand All @@ -208,7 +222,14 @@ export default class Headers extends URLSearchParams {
*/
* entries() {
for (const name of this.keys()) {
yield [name, /** @type {string} */(this.get(name))];
if (name.toLowerCase() === 'set-cookie') {
let cookies = this.getAll(name);
while (cookies.length > 0) {
yield [name, /** @type {string} */(cookies.shift())];
}
} else {
yield [name, /** @type {string} */(this.get(name))];
}
}
}

Expand Down
57 changes: 57 additions & 0 deletions packages/fetch/test/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ describe('Headers', () => {
expect({key: 'content-type', value: 'text/html', object: headers}).to.deep.equal(results[1]);
});

it('should allow iterating through multiple set-cookie headers with forEach', () => {
let headers = new Headers([
['a', '1'],
['Set-Cookie', 'b=2']
]);
headers.append('Set-Cookie', 'c=3');
expect(headers.entries()).to.be.iterable;

const results = [];
headers.forEach((value, key, object) => {
results.push({value, key, object});
});

expect(results).to.deep.equal([
{ value: '1', key: 'a', object: headers },
{ value: 'b=2', key: 'set-cookie', object: headers },
{ value: 'c=3', key: 'set-cookie', object: headers },
]);
})

it('should set "this" to undefined by default on forEach', () => {
const headers = new Headers({Accept: 'application/json'});
headers.forEach(function () {
Expand Down Expand Up @@ -103,8 +123,25 @@ describe('Headers', () => {
['b', '2, 3'],
['c', '4']
]);

});

it('should allow iterating through multiple set-cookie headers with for-of loop', () => {
let headers = new Headers([
['a', '1'],
['Set-Cookie', 'b=2']
]);
headers.append('Set-Cookie', 'c=3');
expect(headers.entries()).to.be.iterable;

const result = [];
for (const pair of headers) {
result.push(pair);
}

expect(result).to.deep.equal([['a', '1'], ['set-cookie', 'b=2'], ['set-cookie', 'c=3']]);
})

it('should allow iterating through all headers with entries()', () => {
const headers = new Headers([
['b', '2'],
Expand All @@ -121,6 +158,16 @@ describe('Headers', () => {
]);
});

it('should allow iterating through multiple set-cookie headers with entries()', ()=> {
let headers = new Headers([
['a', '1'],
['Set-Cookie', 'b=2']
]);
headers.append('Set-Cookie', 'c=3');
expect(headers.entries()).to.be.iterable
.and.to.deep.iterate.over([['a', '1'], ['set-cookie', 'b=2'], ['set-cookie', 'c=3']]);
})

it('should allow iterating through all headers with keys()', () => {
const headers = new Headers([
['b', '2'],
Expand All @@ -145,6 +192,16 @@ describe('Headers', () => {
.and.to.iterate.over(['1', '2, 3', '4']);
});

it('should allow iterating through multiple set-cookie headers with values()', ()=> {
let headers = new Headers([
['a', '1'],
['Set-Cookie', 'b=2']
]);
headers.append('Set-Cookie', 'c=3');
expect(headers.values()).to.be.iterable
.and.to.iterate.over(['1', 'b=2', 'c=3']);
})

it('should reject illegal header', () => {
const headers = new Headers();
expect(() => new Headers({'He y': 'ok'})).to.throw(TypeError);
Expand Down

0 comments on commit 3c20536

Please sign in to comment.