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

Lines changed: 1 addition & 1 deletion
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+
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy