Skip to content

Commit c5ff0a5

Browse files
authored
Merge pull request #160 from kernel/hypeship/preserve-routing-abort
fix: preserve abort signals in browser routing
2 parents ad161fc + 2eec02c commit c5ff0a5

2 files changed

Lines changed: 39 additions & 2 deletions

File tree

src/lib/browser-routing.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,11 @@ async function routeRequest(
262262

263263
const headers = new Headers(request.headers);
264264
headers.delete('authorization');
265-
return innerFetch(target.toString(), buildRoutedInit(request, init, headers));
265+
return innerFetch(target.toString(), buildRoutedInit(input, request, init, headers));
266266
}
267267

268268
function buildRoutedInit(
269+
input: RequestInfo,
269270
request: Request,
270271
originalInit: RequestInit | undefined,
271272
headers: Headers,
@@ -276,7 +277,7 @@ function buildRoutedInit(
276277
method,
277278
headers,
278279
redirect: request.redirect,
279-
signal: request.signal,
280+
signal: originalInit?.signal ?? (input instanceof Request ? input.signal : undefined),
280281
} as RequestInit & Record<string, unknown>;
281282

282283
delete routedInit['body'];

tests/lib/browser-routing.test.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,42 @@ describe('browser routing', () => {
188188
});
189189
});
190190

191+
test('preserves the caller abort signal for routed requests', async () => {
192+
const controller = new AbortController();
193+
const cache = new BrowserRouteCache();
194+
cache.set({
195+
sessionId: 'sess-1',
196+
baseURL: 'http://browser-session.test/browser/kernel',
197+
jwt: 'token-abc',
198+
});
199+
200+
let routedSignal: AbortSignal | null | undefined;
201+
const wrappedFetch = createRoutingFetch(
202+
async (_input, init) => {
203+
routedSignal = init?.signal;
204+
return new Response(null, { status: 204 });
205+
},
206+
{
207+
apiBaseURL: 'https://api.example/',
208+
subresources: ['telemetry/stream'],
209+
cache,
210+
},
211+
);
212+
213+
await wrappedFetch('https://api.example/browsers/sess-1/telemetry/stream', {
214+
signal: controller.signal,
215+
});
216+
217+
expect(routedSignal === controller.signal).toBe(true);
218+
219+
const request = new Request('https://api.example/browsers/sess-1/telemetry/stream', {
220+
signal: controller.signal,
221+
});
222+
await wrappedFetch(request);
223+
224+
expect(routedSignal === request.signal).toBe(true);
225+
});
226+
191227
test('ignores browser responses that do not include a usable jwt', async () => {
192228
await withBrowserRoutingEnv('process', async () => {
193229
const kernel = new Kernel({

0 commit comments

Comments
 (0)