Skip to content

Commit ee69cd7

Browse files
authored
Fix HttpServerResponse.fromWeb losing Content-Type header (#5940)
1 parent 72f61be commit ee69cd7

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
"@effect/platform": patch
3+
---
4+
5+
HttpServerResponse: fix `fromWeb` to preserve Content-Type header when response has a body
6+
7+
Previously, when converting a web `Response` to an `HttpServerResponse` via `fromWeb`, the `Content-Type` header was not passed to `Body.stream()`, causing it to default to `application/octet-stream`. This affected any code using `HttpApp.fromWebHandler` to wrap web handlers, as JSON responses would incorrectly have their Content-Type set to `application/octet-stream` instead of `application/json`.

packages/platform/src/HttpServerResponse.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -410,12 +410,16 @@ export const fromWeb = (response: Response): HttpServerResponse => {
410410
cookies: Cookies.fromSetCookie(setCookieHeaders)
411411
})
412412
if (response.body) {
413+
const contentType = headers.get("content-type")
413414
self = setBody(
414415
self,
415-
Body.stream(Stream.fromReadableStream({
416-
evaluate: () => response.body!,
417-
onError: (e) => e
418-
}))
416+
Body.stream(
417+
Stream.fromReadableStream({
418+
evaluate: () => response.body!,
419+
onError: (e) => e
420+
}),
421+
contentType ?? undefined
422+
)
419423
)
420424
}
421425
return self

packages/platform/test/HttpApp.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ describe("Http/App", () => {
1414
})
1515
})
1616

17+
test("json preserves content-type", async () => {
18+
const handler = HttpApp.toWebHandler(HttpServerResponse.json({ foo: "bar" }))
19+
const response = await handler(new Request("http://localhost:3000/"))
20+
strictEqual(response.headers.get("Content-Type"), "application/json")
21+
})
22+
1723
test("cookies", async () => {
1824
const handler = HttpApp.toWebHandler(
1925
HttpServerResponse.unsafeJson({ foo: "bar" }).pipe(
@@ -186,5 +192,28 @@ describe("Http/App", () => {
186192
const response = await finalHandler(new Request("http://localhost:3000/"))
187193
deepStrictEqual(await response.json(), { source: "effect" })
188194
})
195+
196+
test("preserves response content-type header", async () => {
197+
const webHandler = async (_request: Request) => {
198+
return Response.json({ message: "hello" })
199+
}
200+
const app = HttpApp.fromWebHandler(webHandler)
201+
const handler = HttpApp.toWebHandler(app)
202+
const response = await handler(new Request("http://localhost:3000/"))
203+
strictEqual(response.headers.get("Content-Type"), "application/json")
204+
deepStrictEqual(await response.json(), { message: "hello" })
205+
})
206+
207+
test("preserves custom content-type header", async () => {
208+
const webHandler = async (_request: Request) => {
209+
return new Response("<html></html>", {
210+
headers: { "Content-Type": "text/html; charset=utf-8" }
211+
})
212+
}
213+
const app = HttpApp.fromWebHandler(webHandler)
214+
const handler = HttpApp.toWebHandler(app)
215+
const response = await handler(new Request("http://localhost:3000/"))
216+
strictEqual(response.headers.get("Content-Type"), "text/html; charset=utf-8")
217+
})
189218
})
190219
})

0 commit comments

Comments
 (0)