Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions apps/tests/src/e2e/api-call.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,18 @@ test.describe("api calls", () => {
const response = await fetch("http://localhost:3000/api/text-plain");
expect(await response.text()).toBe("test");
});

test("should include headers from both event and returned request", async () => {
const okResp = await fetch("http://localhost:3000/api/header-merging?status=ok");
expect(okResp.headers.get("Set-Cookie")).toBeTruthy();
expect(okResp.headers.get("x-event-header")).toBe("value");
expect(okResp.headers.get("x-return-header")).toBe("value");
expect(okResp.headers.get("x-shared-header")).toBe("event");

const redirectResp = await fetch("http://localhost:3000/api/header-merging?status=redirect", { redirect: "manual" });
expect(redirectResp.headers.get("Set-Cookie")).toBeTruthy();
expect(redirectResp.headers.get("x-event-header")).toBe("value");
expect(redirectResp.headers.get("x-return-header")).toBe("value");
expect(redirectResp.headers.get("x-shared-header")).toBe("event");
})
});
29 changes: 29 additions & 0 deletions apps/tests/src/routes/api/header-merging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getRequestURL, setHeader, useSession } from "@solidjs/start/http";

export async function GET() {
const url = getRequestURL();

const s = await useSession({ password: "0".repeat(32) });
await s.update(d => ({count: (d.count || 0) + 1}))

setHeader("x-event-header", "value");
setHeader("x-shared-header", "event");

if(url.searchParams.get("status") === "redirect") {
return new Response(null, {
status: 301,
headers: {
location: "http://::/abc",
"x-return-header": "value",
"x-shared-header": "return"
}
})
} else {
return new Response(null, {
headers: {
"x-return-header": "value",
"x-shared-header": "return"
}
})
}
}
32 changes: 29 additions & 3 deletions packages/start/src/server/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export function createBaseHandler(
if (pathname.startsWith(serverFunctionTest)) {
const serverFnResponse = await handleServerFunction(e);

if (serverFnResponse instanceof Response) return serverFnResponse;
if (serverFnResponse instanceof Response)
return produceResponseWithEventHeaders(serverFnResponse);

return new Response(serverFnResponse as any, {
headers: e.res.headers,
Expand All @@ -56,7 +57,11 @@ export function createBaseHandler(
// @ts-expect-error
sharedConfig.context = { event };
const res = await fn!(event);
if (res !== undefined) return res;
if (res !== undefined) {
if(res instanceof Response) return produceResponseWithEventHeaders(res)

return res;
}
if (event.request.method !== "GET") {
throw new Error(
`API handler for ${event.request.method} "${event.request.url}" did not return a response.`,
Expand Down Expand Up @@ -130,7 +135,7 @@ export function createBaseHandler(

const app = new H3();

app.use(handler);
app.use(handler);

return app;
}
Expand Down Expand Up @@ -222,3 +227,24 @@ function handleStreamCompleteRedirect(context: PageEvent) {
to && write(`<script>window.location="${to}"</script>`);
};
}

function produceResponseWithEventHeaders(res: Response) {
const event = getRequestEvent()!;

let ret = res;

// Response.redirect returns an immutable value, so we clone on any redirect just in case
if(300 <= res.status && res.status < 400) {
ret = new Response(res.body, {
status: res.status,
statusText: res.statusText,
headers: Object.fromEntries(res.headers.entries())
});
}

for(const [name, value] of event.response.headers) {
ret.headers.set(name, value);
}

return ret
}
Loading