httpapi-cors-vary.test.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. import { afterEach, describe, expect, test } from "bun:test"
  2. import { Server } from "../../src/server/server"
  3. import { resetDatabase } from "../fixture/db"
  4. import { disposeAllInstances } from "../fixture/fixture"
  5. afterEach(async () => {
  6. await disposeAllInstances()
  7. await resetDatabase()
  8. })
  9. function app() {
  10. return Server.Default().app
  11. }
  12. const PREFLIGHT_HEADERS = {
  13. origin: "http://localhost:3000",
  14. "access-control-request-method": "POST",
  15. "access-control-request-headers": "content-type, x-opencode-directory",
  16. }
  17. // effect-smol's HttpMiddleware.cors overwrites `Vary: Origin` with
  18. // `Vary: Access-Control-Request-Headers` on OPTIONS preflight responses
  19. // (the two share the same record key during the spread). With dynamic
  20. // origin echoing, missing Vary: Origin lets shared caches serve a preflight
  21. // cached for one origin against a different origin. corsVaryFixLayer
  22. // restores the merged form.
  23. describe("CORS preflight Vary header", () => {
  24. test("HTTP API backend preflight Vary contains Origin", async () => {
  25. const response = await app().request("/global/config", {
  26. method: "OPTIONS",
  27. headers: PREFLIGHT_HEADERS,
  28. })
  29. expect([200, 204]).toContain(response.status)
  30. expect(response.headers.get("access-control-allow-origin")).toBe("http://localhost:3000")
  31. expect((response.headers.get("vary") ?? "").toLowerCase()).toContain("origin")
  32. })
  33. test("HTTP API backend preflight Vary still preserves Access-Control-Request-Headers", async () => {
  34. const response = await app().request("/global/config", {
  35. method: "OPTIONS",
  36. headers: PREFLIGHT_HEADERS,
  37. })
  38. const vary = (response.headers.get("vary") ?? "").toLowerCase()
  39. expect(vary).toContain("origin")
  40. expect(vary).toContain("access-control-request-headers")
  41. })
  42. test("HTTP API backend does not duplicate Origin in Vary", async () => {
  43. const response = await app().request("/global/config", {
  44. method: "OPTIONS",
  45. headers: PREFLIGHT_HEADERS,
  46. })
  47. const vary = response.headers.get("vary") ?? ""
  48. const originCount = vary
  49. .split(",")
  50. .map((s: string) => s.trim().toLowerCase())
  51. .filter((s: string) => s === "origin").length
  52. expect(originCount).toBe(1)
  53. })
  54. })