proxy-util.test.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. import { describe, expect, test } from "bun:test"
  2. import { ProxyUtil } from "../../src/server/proxy-util"
  3. describe("ProxyUtil", () => {
  4. describe("websocketTargetURL", () => {
  5. test("converts http to ws", () => {
  6. expect(ProxyUtil.websocketTargetURL("http://example.com/path")).toBe("ws://example.com/path")
  7. })
  8. test("converts https to wss", () => {
  9. expect(ProxyUtil.websocketTargetURL("https://example.com/path")).toBe("wss://example.com/path")
  10. })
  11. test("preserves query params", () => {
  12. expect(ProxyUtil.websocketTargetURL("http://example.com/path?foo=bar")).toBe("ws://example.com/path?foo=bar")
  13. })
  14. test("accepts URL objects", () => {
  15. expect(ProxyUtil.websocketTargetURL(new URL("http://localhost:3000/ws"))).toBe("ws://localhost:3000/ws")
  16. })
  17. })
  18. describe("websocketProtocols", () => {
  19. test("returns empty array when no header", () => {
  20. const req = new Request("http://localhost")
  21. expect(ProxyUtil.websocketProtocols(req)).toEqual([])
  22. })
  23. test("parses single protocol", () => {
  24. const req = new Request("http://localhost", {
  25. headers: { "sec-websocket-protocol": "graphql-ws" },
  26. })
  27. expect(ProxyUtil.websocketProtocols(req)).toEqual(["graphql-ws"])
  28. })
  29. test("parses multiple protocols", () => {
  30. const req = new Request("http://localhost", {
  31. headers: { "sec-websocket-protocol": "graphql-ws, graphql-transport-ws" },
  32. })
  33. expect(ProxyUtil.websocketProtocols(req)).toEqual(["graphql-ws", "graphql-transport-ws"])
  34. })
  35. test("trims whitespace and filters empty", () => {
  36. const req = new Request("http://localhost", {
  37. headers: { "sec-websocket-protocol": " proto1 , , proto2 " },
  38. })
  39. expect(ProxyUtil.websocketProtocols(req)).toEqual(["proto1", "proto2"])
  40. })
  41. })
  42. describe("headers", () => {
  43. test("strips hop-by-hop headers", () => {
  44. const req = new Request("http://localhost", {
  45. headers: {
  46. connection: "keep-alive",
  47. "keep-alive": "timeout=5",
  48. "transfer-encoding": "chunked",
  49. "content-type": "application/json",
  50. },
  51. })
  52. const result = ProxyUtil.headers(req)
  53. expect(result.get("connection")).toBeNull()
  54. expect(result.get("keep-alive")).toBeNull()
  55. expect(result.get("transfer-encoding")).toBeNull()
  56. expect(result.get("content-type")).toBe("application/json")
  57. })
  58. test("strips opencode-specific headers", () => {
  59. const req = new Request("http://localhost", {
  60. headers: {
  61. "x-opencode-directory": "/home/user/project",
  62. "x-opencode-workspace": "ws_123",
  63. "accept-encoding": "gzip",
  64. "x-custom": "keep",
  65. },
  66. })
  67. const result = ProxyUtil.headers(req)
  68. expect(result.get("x-opencode-directory")).toBeNull()
  69. expect(result.get("x-opencode-workspace")).toBeNull()
  70. expect(result.get("accept-encoding")).toBeNull()
  71. expect(result.get("x-custom")).toBe("keep")
  72. })
  73. test("merges extra headers", () => {
  74. const req = new Request("http://localhost", {
  75. headers: { "content-type": "application/json" },
  76. })
  77. const result = ProxyUtil.headers(req, { "x-auth": "token", "content-type": "text/plain" })
  78. expect(result.get("x-auth")).toBe("token")
  79. expect(result.get("content-type")).toBe("text/plain")
  80. })
  81. test("returns original headers when no extra", () => {
  82. const req = new Request("http://localhost", {
  83. headers: { "content-type": "application/json", "x-foo": "bar" },
  84. })
  85. const result = ProxyUtil.headers(req)
  86. expect(result.get("content-type")).toBe("application/json")
  87. expect(result.get("x-foo")).toBe("bar")
  88. })
  89. test("accepts plain object (HeadersInit) as input", () => {
  90. const result = ProxyUtil.headers(
  91. { "content-type": "application/json", connection: "keep-alive", "x-custom": "val" },
  92. { "x-extra": "added" },
  93. )
  94. expect(result.get("connection")).toBeNull()
  95. expect(result.get("content-type")).toBe("application/json")
  96. expect(result.get("x-custom")).toBe("val")
  97. expect(result.get("x-extra")).toBe("added")
  98. })
  99. })
  100. })