Skip to content

Commit 9350ddf

Browse files
authored
Do not treat Content-Length=0 as empty when Transfer-Encoding is chunked (#2572)
* fix(response): handle zero Content-Length correctly for chunked and non-chunked responses Some HTTP servers incorrectly send `Content-Length: 0` together with `Transfer-Encoding: chunked`. According to RFC 7230, chunked transfer encoding overrides Content-Length and the body may still contain data. Previously, the client treated any response with Content-Length=0 as having an empty body, which caused valid chunked responses to be discarded. This change only treats Content-Length=0 as empty when the response is not chunked, preserving correct behavior for misconfigured servers. * chore: fix linting errors * chore: revert accidental line changes * chore: added changeset * Resolve merge conflicts * Properly check if content length is zero
1 parent a690e52 commit 9350ddf

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

.changeset/empty-ghosts-sip.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"openapi-fetch": minor
3+
---
4+
5+
Do not treat Content-Length=0 as empty when Transfer-Encoding is chunked

packages/openapi-fetch/src/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,11 @@ export default function createClient(clientOptions) {
237237

238238
const contentLength = response.headers.get("Content-Length");
239239
// handle empty content
240-
if (response.status === 204 || request.method === "HEAD" || contentLength === "0") {
240+
if (
241+
response.status === 204 ||
242+
request.method === "HEAD" ||
243+
(contentLength === "0" && !response.headers.get("Transfer-Encoding")?.includes("chunked"))
244+
) {
241245
return response.ok ? { data: undefined, response } : { error: undefined, response };
242246
}
243247

packages/openapi-fetch/test/common/response.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,36 @@ describe("response", () => {
204204
}
205205
});
206206
});
207+
208+
describe("chunked transfer with zero Content-Length", () => {
209+
test("does not treat chunked body with Content-Length: 0 as empty", async () => {
210+
const mock = [{ id: 1 }];
211+
const client = createObservedClient<paths>({}, async () =>
212+
Response.json(mock, {
213+
status: 200,
214+
headers: { "Content-Length": "0", "Transfer-Encoding": "chunked" },
215+
}),
216+
);
217+
218+
const { data, error, response } = await client.GET("/resources");
219+
expect(response.status).toBe(200);
220+
expect(error).toBeUndefined();
221+
expect(data).toEqual(mock);
222+
});
223+
});
224+
describe("Content-Length: 0 without chunked", () => {
225+
test("treats as empty when not chunked", async () => {
226+
const client = createObservedClient<paths>({}, async () =>
227+
Response.json([{ id: 1 }], {
228+
status: 200,
229+
headers: { "Content-Length": "0" },
230+
}),
231+
);
232+
233+
const { data, error, response } = await client.GET("/resources");
234+
expect(response.status).toBe(200);
235+
expect(error).toBeUndefined();
236+
expect(data).toBeUndefined();
237+
});
238+
});
207239
});

0 commit comments

Comments
 (0)