From aca72c57a26a6228348b9551182929a7abd173bd Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Thu, 4 Jan 2024 11:05:00 -0500 Subject: [PATCH 1/3] Do not attempt to deserialize empty json responses --- .changeset/unlucky-planets-repeat.md | 5 +++++ packages/router/__tests__/navigation-test.ts | 19 +++++++++++++++++++ packages/router/router.ts | 7 ++++++- 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .changeset/unlucky-planets-repeat.md diff --git a/.changeset/unlucky-planets-repeat.md b/.changeset/unlucky-planets-repeat.md new file mode 100644 index 0000000000..68cbf9ae6a --- /dev/null +++ b/.changeset/unlucky-planets-repeat.md @@ -0,0 +1,5 @@ +--- +"@remix-run/router": patch +--- + +Do not attempt to deserialize empty JSON responses diff --git a/packages/router/__tests__/navigation-test.ts b/packages/router/__tests__/navigation-test.ts index f4bffc592e..3c85134cff 100644 --- a/packages/router/__tests__/navigation-test.ts +++ b/packages/router/__tests__/navigation-test.ts @@ -114,6 +114,25 @@ describe("navigations", () => { }); }); + // See: https://github.com/remix-run/react-router/issues/11145 + it("does not attempt to deserialize empty json responses", async () => { + let t = initializeTest(); + let A = await t.navigate("/foo"); + await A.loaders.foo.resolve( + new Response(null, { + headers: { + "Content-Type": "application/json", + "Content-Length": "0", + }, + }) + ); + expect(t.router.state.errors).toBeNull(); + expect(t.router.state.loaderData).toMatchObject({ + root: "ROOT", + foo: null, + }); + }); + it("unwraps non-redirect text Responses", async () => { let t = initializeTest(); let A = await t.navigate("/foo"); diff --git a/packages/router/router.ts b/packages/router/router.ts index 0280cd48ca..d935305f5a 100644 --- a/packages/router/router.ts +++ b/packages/router/router.ts @@ -4098,7 +4098,12 @@ async function callLoaderOrAction( // Check between word boundaries instead of startsWith() due to the last // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type if (contentType && /\bapplication\/json\b/.test(contentType)) { - data = await result.json(); + let contentLength = result.headers.get("Content-Length"); + if (contentLength === "0") { + data = null; + } else { + data = await result.json(); + } } else { data = await result.text(); } From 648ceb972e875f3832a9b4c2c906993c2510e5d7 Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Fri, 5 Jan 2024 09:59:21 -0500 Subject: [PATCH 2/3] Check for null body instead of content length --- packages/router/router.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/router/router.ts b/packages/router/router.ts index d935305f5a..447b12214d 100644 --- a/packages/router/router.ts +++ b/packages/router/router.ts @@ -4098,8 +4098,7 @@ async function callLoaderOrAction( // Check between word boundaries instead of startsWith() due to the last // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type if (contentType && /\bapplication\/json\b/.test(contentType)) { - let contentLength = result.headers.get("Content-Length"); - if (contentLength === "0") { + if (result.body == null) { data = null; } else { data = await result.json(); From 34c34af9af72ef81d90a2098432fe408450d240f Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 9 Jan 2024 10:49:17 -0500 Subject: [PATCH 3/3] Update test --- packages/router/__tests__/navigation-test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/router/__tests__/navigation-test.ts b/packages/router/__tests__/navigation-test.ts index 3c85134cff..894da06535 100644 --- a/packages/router/__tests__/navigation-test.ts +++ b/packages/router/__tests__/navigation-test.ts @@ -122,7 +122,6 @@ describe("navigations", () => { new Response(null, { headers: { "Content-Type": "application/json", - "Content-Length": "0", }, }) );