8000 fix(service-worker): update service worker to handle seeking better f… · angular/angular@9743bd1 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9743bd1

Browse files
Beanminchildkirjs
authored andcommitted
fix(service-worker): update service worker to handle seeking better for videos (#60029)
This update ensures that the service worker can handle range requests, allowing video seeking to work correctly when videos are delivered by the service worker. PR Close #60029
1 parent 661b58c commit 9743bd1

File tree

2 files changed

+64
-1
lines changed

2 files changed

+64
-1
lines changed

packages/examples/service-worker/push/ngsw-worker.js

Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Copyright Google LLC All Rights Reserved.
44
*
55
* Use of this source code is governed by an MIT-style license that can be
6-
* found in the LICENSE file at https://angular.dev/license
6+
* found in the LICENSE file at https://angular.dev/license.
77
*/
88

99
// Mock `ngsw-worker.js` used for testing the examples.

packages/service-worker/worker/src/driver.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,12 @@ export class Driver implements Debuggable, UpdateSource {
209209
return;
210210
}
211211

212+
// Calls range request handler
213+
if (req.headers.has('range')) {
214+
event.respondWith(this.handleRangeRequest(req));
215+
return;
216+
}
217+
212218
// The only thing that is served unconditionally is the debug page.
213219
if (requestUrlObj.path === this.ngswStatePath) {
214220
// Allow the debugger to handle the request, but don't affect SW state in any other way.
@@ -262,6 +268,63 @@ export class Driver implements Debuggable, UpdateSource {
262268
event.respondWith(this.handleFetch(event));
263269
}
264270

271+
// function to handle Range requests
272+
private async handleRangeRequest(req: Request): Promise<Response> {
273+
try {
274+
const response = await fetch(req);
275+
const contentType = response.headers.get('Content-Type');
276+
277+
// Only apply logic to content that is a video
278+
if (!contentType || !contentType.startsWith('video/')) {
279+
return response;
280+
}
281+
282+
< 10000 span class=pl-k>const rangeHeader = req.headers.get('range');
283+
if (!rangeHeader) {
284+
return new Response(null, {
285+
status: 416,
286+
statusText: 'Range Not Satisfiable',
287+
});
288+
}
289+
290+
const rangeMatch = /bytes=(\d+)-(\d+)?/.exec(rangeHeader);
291+
if (!rangeMatch) {
292+
return new Response(null, {
293+
status: 416,
294+
statusText: 'Range Not Satisfiable',
295+
});
296+
}
297+
298+
const start = Number(rangeMatch[1]);
299+
const end = rangeMatch[2] ? Number(rangeMatch[2]) : undefined;
300+
301+
const buffer = await response.arrayBuffer();
302+
const contentLength = buffer.byteLength;
303+
304+
const chunk = buffer.slice(start, end ? end + 1 : contentLength);
305+
const chunkLength = chunk.byteLength;
306+
307+
const headers = new Headers(response.headers);
308+
headers.set(
309+
'Content-Range',
310+
`bytes ${start}-${end ? end : contentLength - 1}/${contentLength}`,
311+
);
312+
headers.set('Content-Length', chunkLength.toString());
313+
headers.set('Accept-Ranges', 'bytes');
314+
315+
return new Response(chunk, {
316+
status: 206,
317+
statusText: 'Partial Content',
318+
headers: headers,
319+
});
320+
} catch (error) {
321+
return new Response(null, {
322+
status: 500,
323+
statusText: 'Internal Server Error',
324+
});
325+
}
326+
}
327+
265328
/**
266329
* The handler for message events.
267330
*/

0 commit comments

Comments
 (0)
0