diff --git a/src/node/proxy.ts b/src/node/proxy.ts index 2d9056996..1377048b9 100644 --- a/src/node/proxy.ts +++ b/src/node/proxy.ts @@ -1,5 +1,6 @@ import * as cookie from "cookie" import type { Request } from "express" +import http from "http" import proxyServer from "http-proxy" import { getCookieSessionName, HttpCode } from "../common/http" @@ -26,7 +27,7 @@ function identity(val: T): T { // Strip the code-server cookie if it exists to avoid transmitting the cookie // to potentially malicious local ports. -proxy.on("proxyReq", (preq, req) => { +function stripCookie(preq: http.ClientRequest, req: http.IncomingMessage) { if (req.headers.cookie) { const cookieSessionName = getCookieSessionName((req as Request).args["cookie-suffix"]) // Encoding and decoding are no-ops; we just want to remove the token @@ -45,7 +46,10 @@ proxy.on("proxyReq", (preq, req) => { ), ) } -}) +} + +proxy.on("proxyReq", stripCookie) +proxy.on("proxyReqWs", stripCookie) // Intercept the response to rewrite absolute redirects against the base path. // Is disabled when the request has no base path which means /absproxy is in use. diff --git a/test/unit/node/proxy.test.ts b/test/unit/node/proxy.test.ts index 4c3320a07..3807fe77e 100644 --- a/test/unit/node/proxy.test.ts +++ b/test/unit/node/proxy.test.ts @@ -303,6 +303,13 @@ describe("proxy", () => { res.end(req.headers.cookie) }) + wsRouter.ws("/wsup/cookies", async (req) => { + wss.handleUpgrade(req, req.ws, req.head, (ws) => { + ws.on("message", () => ws.send(req.headers.cookie || "")) + req.ws.resume() + }) + }) + const cookies = [ "cookie2=hello", // Cookies should pass through unchanged, neither encoded nor decoded. @@ -316,13 +323,22 @@ describe("proxy", () => { for (let i = 0; i <= cookies.length; ++i) { const left = cookies.slice(0, i) const right = cookies.slice(i) - const resp = await codeServer.fetch(proxyPath + "/cookies", { - headers: { - cookie: [...left, `code-server-session=${token}`, ...right].join("; "), - }, - }) + const expected = cookies.join("; ") + const headers = { + cookie: [...left, `code-server-session=${token}`, ...right].join("; "), + } + // Regular HTTP request. + const resp = await codeServer.fetch(proxyPath + "/cookies", { headers }) expect(resp.status).toBe(200) - expect(await resp.text()).toBe(cookies.join("; ")) + expect(await resp.text()).toBe(expected) + // Web socket request. + const ws = await codeServer.wsWait(proxyPath + "/cookies", { headers }) + const got = await new Promise((resolve) => { + ws.send("init") + ws.on("message", (msg) => resolve(msg)) + }) + ws.terminate() + expect(got).toBe(expected) } })