I use service worker to modify the fetch response with below code,
JavaScript
x
33
33
1
self.addEventListener('install', function(event) {
2
console.log('install');
3
});
4
5
self.addEventListener('activate', function(event) {
6
console.log('Claiming control');
7
return self.clients.claim();
8
});
9
10
self.addEventListener('fetch', function(event) {
11
console.log("fetch event")
12
event.respondWith(
13
fetch(event.request).then(function (response) {
14
if(response.url.match('.mp4')){
15
console.log(event);
16
response.arrayBuffer().then(
17
buffer =>{
18
let length = 100
19
view = new Uint8Array(buffer,0,length)
20
for(i=0,j=length - 1; i<j; i++,j--){
21
view[i] = view[i] ^ view[j]
22
view[j] = view[j] ^ view[i]
23
view[i] = view[i] ^ view[j]
24
}
25
}
26
)
27
}
28
return response.clone();
29
})
30
);
31
});
32
33
Whichi will lead to this warning and error,
The FetchEvent for “” resulted in a network error response: the promise was rejected.
sw.js:60 Uncaught (in promise) TypeError: Failed to execute ‘clone’ on ‘Response’: Response body is already used at sw.js:60
If I put the clone()
before arrayBuffer()
like below,
JavaScript
1
34
34
1
self.addEventListener('install', function(event) {
2
console.log('install');
3
});
4
5
self.addEventListener('activate', function(event) {
6
console.log('Claiming control');
7
return self.clients.claim();
8
});
9
10
self.addEventListener('fetch', function(event) {
11
console.log("fetch event")
12
event.respondWith(
13
fetch(event.request).then(function (response) {
14
if(response.url.match('.mp4')){
15
console.log(event);
16
responseCloned = response.clone();
17
responseCloned.arrayBuffer().then(
18
buffer =>{
19
let length = 100
20
view = new Uint8Array(buffer,0,length)
21
for(i=0,j=length - 1; i<j; i++,j--){
22
view[i] = view[i] ^ view[j]
23
view[j] = view[j] ^ view[i]
24
view[i] = view[i] ^ view[j]
25
}
26
}
27
)
28
}
29
return responseCloned;
30
})
31
);
32
});
33
34
It will lead to below warning and error,
The FetchEvent for “” resulted in a network error response: a Response whose “body” is locked cannot be used to respond to a request.
GET http://localhost/web/357765_decrypted.mp4 net::ERR_FAILED
Advertisement
Answer
Try instantiating and returning a new Response()
with the decrypted bytes:
JavaScript
1
18
18
1
self.addEventListener('fetch', event => {
2
if (event.request.url.endsWith('.mp4') {
3
event.respondWith(getDecryptedResponse(event.request))
4
}
5
})
6
7
async function getDecryptedResponse(request) {
8
const response = await fetch(request)
9
const bytes = new Uint8Array(await response.arrayBuffer())
10
11
return new Response(
12
new Blob([ decryptMp4Bytes(bytes) ], { type: 'application/mp4' }),
13
{
14
headers: response.headers, // possibly required for this case
15
}
16
)
17
}
18