From 21677bb0eeef79b05edff95555d4d16e79a057eb Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 16 Sep 2024 20:44:16 +0200 Subject: [PATCH] fix: skip content type for non-body methods (#954) --- .../src/internal/to-web-request.ts | 10 +- packages/uploadthing/test/adapters.test.ts | 160 +++++++++++++++++- 2 files changed, 167 insertions(+), 3 deletions(-) diff --git a/packages/uploadthing/src/internal/to-web-request.ts b/packages/uploadthing/src/internal/to-web-request.ts index 16e29a3eee..4a50ca025b 100644 --- a/packages/uploadthing/src/internal/to-web-request.ts +++ b/packages/uploadthing/src/internal/to-web-request.ts @@ -54,13 +54,19 @@ const parseURL = (req: IncomingMessageLike): Effect.Effect => { ); }; +const isBodyAllowed = (method: string) => + ["POST", "PUT", "PATCH"].includes(method); + export const getPostBody = (opts: { req: IncomingMessageLike & { on: (event: string, listener: (data: any) => void) => void; }; }) => - Effect.async((resume) => { + Effect.async((resume) => { const { req } = opts; + if (!req.method || !isBodyAllowed(req.method)) { + return resume(Effect.succeed(undefined)); + } const contentType = req.headers?.["content-type"]; if ("body" in req) { @@ -118,7 +124,7 @@ export const toWebRequest = ( body ??= req.body; const bodyStr = typeof body === "string" ? body : JSON.stringify(body); const method = req.method ?? "GET"; - const allowsBody = ["POST", "PUT", "PATCH"].includes(method); + const allowsBody = isBodyAllowed(method); const headers = new Headers(); for (const [key, value] of Object.entries(req.headers ?? [])) { diff --git a/packages/uploadthing/test/adapters.test.ts b/packages/uploadthing/test/adapters.test.ts index bce34b1113..03c4d0e27a 100644 --- a/packages/uploadthing/test/adapters.test.ts +++ b/packages/uploadthing/test/adapters.test.ts @@ -45,6 +45,28 @@ describe("adapters:h3", async () => { .onUploadComplete(uploadCompleteMock), }; + it("returns router config on GET requests", async ({ db }) => { + const eventHandler = createRouteHandler({ + router, + config: { token: testToken.encoded }, + }); + + const res = await toWebHandler(createApp().use(eventHandler))( + new Request("http://localhost:3000"), + ); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("application/json"); + + const json = await res.json(); + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets H3Event in middleware args", async ({ db }) => { const eventHandler = createRouteHandler({ router, @@ -134,6 +156,26 @@ describe("adapters:server", async () => { .onUploadComplete(uploadCompleteMock), }; + it("returns router config on GET requests", async ({ db }) => { + const eventHandler = createRouteHandler({ + router, + config: { token: testToken.encoded }, + }); + + const res = await eventHandler(new Request("http://localhost:3000")); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("application/json"); + + const json = await res.json(); + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets Request in middleware args", async ({ db }) => { const handler = createRouteHandler({ router, @@ -211,6 +253,28 @@ describe("adapters:next", async () => { .onUploadComplete(uploadCompleteMock), }; + it("returns router config on GET requests", async ({ db }) => { + const eventHandler = createRouteHandler({ + router, + config: { token: testToken.encoded }, + }); + + const res = await eventHandler.GET( + new NextRequest("http://localhost:3000"), + ); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("application/json"); + + const json = await res.json(); + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets NextRequest in middleware args", async ({ db }) => { const handlers = createRouteHandler({ router, @@ -291,7 +355,7 @@ describe("adapters:next-legacy", async () => { }; function mockReq(opts: { - query: Record; + query?: Record; method: string; body?: unknown; headers?: Record; @@ -324,6 +388,30 @@ describe("adapters:next-legacy", async () => { return { res, json, setHeader, status }; } + it("returns router config on GET requests", async ({ db }) => { + const eventHandler = createRouteHandler({ + router, + config: { token: testToken.encoded }, + }); + + const { req } = mockReq({ + method: "GET", + }); + const { res, json, status } = mockRes(); + + await eventHandler(req, res); + + expect(res.status).toHaveBeenCalledWith(200); + + const resJson = (json.mock.calls[0] as any[])[0]; + expect(resJson).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets NextApiRequest and NextApiResponse in middleware args", async ({ db, }) => { @@ -425,6 +513,24 @@ describe("adapters:express", async () => { return { url, close: () => server.close() }; }; + it("returns router config on GET requests", async ({ db }) => { + const server = startServer(); + + const url = `${server.url}/api/uploadthing/`; + const res = await fetch(url); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("application/json"); + + const json = await res.json(); + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets express.Request and express.Response in middleware args", async ({ db, }) => { @@ -563,6 +669,24 @@ describe("adapters:fastify", async () => { return { url, close: () => app.close() }; }; + it("returns router config on GET requests", async ({ db }) => { + const server = await startServer(); + + const url = `${server.url}api/uploadthing`; + const res = await fetch(url); + + expect(res.status).toBe(200); + expect(res.headers.get("content-type")).toBe("application/json"); + + const json = await res.json(); + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ blob: expect.objectContaining({}) }), + }, + ]); + }); + it("gets fastify.FastifyRequest and fastify.FastifyReply in middleware args", async ({ db, }) => { @@ -648,6 +772,40 @@ describe("adapters:effect-platform", async () => { .onUploadComplete(uploadCompleteMock), }; + it.effect("returns router config on GET requests", () => + Effect.gen(function* () { + const eventHandler = createRouteHandler({ + router, + config: { token: testToken.encoded }, + }).pipe(Effect.provide(HttpClient.layer)); + + const serverRequest = HttpServerRequest.fromWeb( + new Request("http://localhost:3000"), + ); + const response = yield* eventHandler.pipe( + Effect.provideService( + HttpServerRequest.HttpServerRequest, + serverRequest, + ), + ); + expect(response.status).toBe(200); + expect(response.headers["content-type"]).toBe("application/json"); + + const json = yield* Effect.promise(() => + HttpServerResponse.toWeb(response).json(), + ); + + expect(json).toEqual([ + { + slug: "middleware", + config: expect.objectContaining({ + blob: expect.objectContaining({}), + }), + }, + ]); + }), + ); + it.effect("gets HttpServerRequest in middleware args", () => Effect.gen(function* () { const handler = createRouteHandler({