From e962f48aa9332e411bee182e61967e55af511c30 Mon Sep 17 00:00:00 2001 From: Tataihono Nikora Date: Fri, 22 May 2026 07:27:47 +0000 Subject: [PATCH] fix(mastra): normalize Studio proxy encoding --- .../src/lib/mastra-proxy.test.ts | 55 +++++++++++++++++++ apps/mastra-gateway/src/lib/mastra-proxy.ts | 5 ++ 2 files changed, 60 insertions(+) create mode 100644 apps/mastra-gateway/src/lib/mastra-proxy.test.ts diff --git a/apps/mastra-gateway/src/lib/mastra-proxy.test.ts b/apps/mastra-gateway/src/lib/mastra-proxy.test.ts new file mode 100644 index 00000000..0c38f339 --- /dev/null +++ b/apps/mastra-gateway/src/lib/mastra-proxy.test.ts @@ -0,0 +1,55 @@ +import { afterEach, describe, expect, it, vi } from "vitest" + +describe("Mastra proxy", () => { + afterEach(() => { + vi.restoreAllMocks() + vi.unstubAllEnvs() + vi.resetModules() + }) + + it("requests identity encoding and strips stale response encoding headers", async () => { + vi.stubEnv("MASTRA_GATEWAY_BASE_URL", "https://gateway.example.com") + vi.stubEnv( + "MASTRA_GATEWAY_SESSION_SECRET", + "test-secret-test-secret-test-secret-32", + ) + vi.stubEnv("MASTRA_INTERNAL_BASE_URL", "https://mastra.internal") + vi.stubEnv("MASTRA_INTERNAL_API_KEY", "internal-key") + + const { createGatewaySessionCookie, GATEWAY_SESSION_COOKIE } = + await import("./gateway-session") + const { proxyMastraRequest } = await import("./mastra-proxy") + + const token = await createGatewaySessionCookie({ + subject: "user-1", + email: "user@example.com", + role: "admin", + }) + const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValue( + new Response("body{}", { + headers: { + "content-encoding": "gzip", + "content-length": "1024", + "content-type": "application/javascript", + }, + }), + ) + + const response = await proxyMastraRequest( + new Request("https://gateway.example.com/studio/assets/index.js", { + headers: { + "accept-encoding": "gzip, br", + cookie: `${GATEWAY_SESSION_COOKIE}=${encodeURIComponent(token)}`, + }, + }), + "/studio/assets/index.js", + ) + + const [, init] = fetchMock.mock.calls[0] + const upstreamHeaders = init?.headers as Headers + expect(upstreamHeaders.get("accept-encoding")).toBe("identity") + expect(response.headers.get("content-encoding")).toBeNull() + expect(response.headers.get("content-length")).toBeNull() + expect(response.headers.get("content-type")).toBe("application/javascript") + }) +}) diff --git a/apps/mastra-gateway/src/lib/mastra-proxy.ts b/apps/mastra-gateway/src/lib/mastra-proxy.ts index 0de249cb..69c5f377 100644 --- a/apps/mastra-gateway/src/lib/mastra-proxy.ts +++ b/apps/mastra-gateway/src/lib/mastra-proxy.ts @@ -17,6 +17,8 @@ const hopByHopHeaders = new Set([ "upgrade", ]) +const bodyEncodingHeaders = new Set(["content-encoding", "content-length"]) + export async function proxyMastraRequest( request: Request, upstreamPath: string, @@ -44,8 +46,10 @@ export async function proxyMastraRequest( const headers = new Headers(request.headers) for (const header of hopByHopHeaders) headers.delete(header) + headers.delete("accept-encoding") headers.delete("cookie") headers.delete("host") + headers.set("accept-encoding", "identity") headers.set("authorization", `Bearer ${env.MASTRA_INTERNAL_API_KEY}`) headers.set("x-forge-user-subject", session.subject) if (session.email) headers.set("x-forge-user-email", session.email) @@ -61,6 +65,7 @@ export async function proxyMastraRequest( const responseHeaders = new Headers(response.headers) for (const header of hopByHopHeaders) responseHeaders.delete(header) + for (const header of bodyEncodingHeaders) responseHeaders.delete(header) return new Response(response.body, { status: response.status,