Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ClientRequest): preserve headers type when recording raw headers #660

Merged
merged 3 commits into from
Oct 16, 2024

Conversation

paoloricciuti
Copy link
Contributor

Closes #651

Basically when defining the header property on the original init request or the original init headers we were assigning the value of kRawHeaders but that's just a string array. So if that Request is then used again trying to read the headers with req.headers.get it will fail since there's no get method in the array of strings.

Also i've noticed

if (inferRawHeaders.length > 0) {
    defineRawHeadersSymbol(request.headers, inferredRawHeaders)
}

which is a classic TS mystake: you were checking if that function had more than one argument but that's always true so i switched to what i think you actually wanted to check.

I've added a couple of test to check this that fails before this PR.

@carpie
Copy link

carpie commented Oct 15, 2024

I think the Response proxy needs this treatment as well. Creating HttpResponse objects after these proxies are installed will throw TypeError: init.headers.get is not a function. The following small script can demonstrate:

const { setupServer } = require('msw/node');
let s = setupServer();
s.listen();

const { HttpResponse } = require('msw');
HttpResponse.json('{}', { status: 200, statusText: 'OK' });

I was able to "fix" it locally by wrapping the right hand side of the assignment in

args[1].headers = args[1].headers[kRawHeaders]
with a new Headers() after finding this PR.

@paoloricciuti
Copy link
Contributor Author

I think the Response proxy needs this treatment as well. Creating HttpResponse objects after these proxies are installed will throw TypeError: init.headers.get is not a function. The following small script can demonstrate:

const { setupServer } = require('msw/node');
let s = setupServer();
s.listen();

const { HttpResponse } = require('msw');
HttpResponse.json('{}', { status: 200, statusText: 'OK' });

I was able to "fix" it locally by wrapping the right hand side of the assignment in

args[1].headers = args[1].headers[kRawHeaders]

with a new Headers() after finding this PR.

You are absolutely right...i missed this because the way to trigger it is a bit weird. Pushed the fix now.

@carpie
Copy link

carpie commented Oct 15, 2024

You are absolutely right...i missed this because the way to trigger it is a bit weird. Pushed the fix now.

Awesome! Thank you!

@@ -126,6 +126,28 @@ it('records raw headers (Reqest / Request as init)', () => {
expect(getRawFetchHeaders(request.headers)).toEqual([['X-My-Header', '1']])
})

it("doesn't change the init headers instanceof (Request / Request as init)", () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe let's rephrase it to "preserves the original headers instance"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well it's not technically the same header instance...however if you think it's important we could rework this whole thing by pushing looping over the raw headers and set the on the original instance

@kettanaito
Copy link
Member

Thanks for opening this, @paoloricciuti.

I believe those 3 if checks were left incorrectly. They aren't needed anymore. We don't need to modify the init in any way. The raw headers inference was achieved later on, by these blocks:

if (typeof args[0] === 'object' && args[0].headers != null) {
inferredRawHeaders.push(...inferRawHeaders(args[0].headers))
}
// Infer raw headers from the "headers" init argument.
if (typeof args[1] === 'object' && args[1].headers != null) {
inferredRawHeaders.push(...inferRawHeaders(args[1].headers))
}
if (inferRawHeaders.length > 0) {
defineRawHeadersSymbol(request.headers, inferredRawHeaders)
}

if (typeof args[1] === 'object' && args[1].headers != null) {
ensureRawHeadersSymbol(
response.headers,
inferRawHeaders(args[1].headers)
)
}

I've removed the if checks, and the tests are still passing. Let me test these changes in MSW as well, as it may have unique use cases we are not considering here.

@@ -225,8 +188,8 @@ export function recordRawFetchHeaders() {
inferredRawHeaders.push(...inferRawHeaders(args[1].headers))
}

if (inferRawHeaders.length > 0) {
defineRawHeadersSymbol(request.headers, inferredRawHeaders)
if (inferredRawHeaders.length > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a typo ✅

if (inferRawHeaders.length > 0) {
defineRawHeadersSymbol(request.headers, inferredRawHeaders)
if (inferredRawHeaders.length > 0) {
ensureRawHeadersSymbol(request.headers, inferredRawHeaders)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I'm using ensure to prevent the raw headers symbol from being re-defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh i don't remember changing this line...weird.

@kettanaito kettanaito changed the title fix: define property in original init Headers as Headers instead of string[] fix(ClientRequest): preserve headers identity when recording raw headers Oct 16, 2024
@kettanaito kettanaito changed the title fix(ClientRequest): preserve headers identity when recording raw headers fix(ClientRequest): preserve headers type when recording raw headers Oct 16, 2024
@kettanaito
Copy link
Member

Both interceptors and MSW test suites have passed with these changes. Let's get this out.

@kettanaito kettanaito merged commit 2f6106c into mswjs:main Oct 16, 2024
2 checks passed
@kettanaito
Copy link
Member

@paoloricciuti, welcome to contributors! 🎉

@kettanaito
Copy link
Member

Released: v0.36.5 🎉

This has been released in v0.36.5!

Make sure to always update to the latest version (npm i @mswjs/interceptors@latest) to get the newest features and bug fixes.


Predictable release automation by @ossjs/release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants