diff --git a/src/lib/browser-routing.ts b/src/lib/browser-routing.ts index b01f8c81..7c5f0480 100644 --- a/src/lib/browser-routing.ts +++ b/src/lib/browser-routing.ts @@ -262,10 +262,11 @@ async function routeRequest( const headers = new Headers(request.headers); headers.delete('authorization'); - return innerFetch(target.toString(), buildRoutedInit(request, init, headers)); + return innerFetch(target.toString(), buildRoutedInit(input, request, init, headers)); } function buildRoutedInit( + input: RequestInfo, request: Request, originalInit: RequestInit | undefined, headers: Headers, @@ -276,7 +277,7 @@ function buildRoutedInit( method, headers, redirect: request.redirect, - signal: request.signal, + signal: originalInit?.signal ?? (input instanceof Request ? input.signal : undefined), } as RequestInit & Record; delete routedInit['body']; diff --git a/tests/lib/browser-routing.test.ts b/tests/lib/browser-routing.test.ts index 53d0ba46..d6d6521e 100644 --- a/tests/lib/browser-routing.test.ts +++ b/tests/lib/browser-routing.test.ts @@ -188,6 +188,42 @@ describe('browser routing', () => { }); }); + test('preserves the caller abort signal for routed requests', async () => { + const controller = new AbortController(); + const cache = new BrowserRouteCache(); + cache.set({ + sessionId: 'sess-1', + baseURL: 'http://browser-session.test/browser/kernel', + jwt: 'token-abc', + }); + + let routedSignal: AbortSignal | null | undefined; + const wrappedFetch = createRoutingFetch( + async (_input, init) => { + routedSignal = init?.signal; + return new Response(null, { status: 204 }); + }, + { + apiBaseURL: 'https://api.example/', + subresources: ['telemetry/stream'], + cache, + }, + ); + + await wrappedFetch('https://api.example/browsers/sess-1/telemetry/stream', { + signal: controller.signal, + }); + + expect(routedSignal === controller.signal).toBe(true); + + const request = new Request('https://api.example/browsers/sess-1/telemetry/stream', { + signal: controller.signal, + }); + await wrappedFetch(request); + + expect(routedSignal === request.signal).toBe(true); + }); + test('ignores browser responses that do not include a usable jwt', async () => { await withBrowserRoutingEnv('process', async () => { const kernel = new Kernel({