Browse Source

dupe network request bug

Emily 6 years ago
parent
commit
921df9e1aa
4 changed files with 96 additions and 15 deletions
  1. 3 4
      app/api.js
  2. 47 6
      app/fileReceiver.js
  3. 45 5
      app/serviceWorker.js
  4. 1 0
      app/templates/downloadButton/index.js

+ 3 - 4
app/api.js

@@ -13,7 +13,7 @@ function post(obj) {
   };
 }
 
-function parseNonce(header) {
+export function parseNonce(header) {
   header = header || '';
   return header.split(' ')[1];
 }
@@ -162,8 +162,8 @@ async function upload(
 
       ws.send(buf);
 
-      onprogress([Math.min(streamInfo.fileSize, size), streamInfo.fileSize]);
-      size += streamInfo.recordSize;
+      onprogress([size, streamInfo.fileSize]);
+      size += buf.length;
       state = await reader.read();
       while (ws.bufferedAmount > streamInfo.recordSize * 2) {
         await delay();
@@ -205,7 +205,6 @@ export function uploadWs(encrypted, info, metadata, verifierB64, onprogress) {
 async function downloadS(id, keychain, signal) {
   const auth = await keychain.authHeader();
 
-  //this will be already funneled through serviceworker
   const response = await fetch(`/api/download/${id}`, {
     signal: signal,
     method: 'GET',

+ 47 - 6
app/fileReceiver.js

@@ -1,7 +1,7 @@
 import Nanobus from 'nanobus';
 import Keychain from './keychain';
-import { bytes } from './utils';
-import { metadata } from './api';
+import { delay, bytes } from './utils';
+import { parseNonce, metadata } from './api';
 
 export default class FileReceiver extends Nanobus {
   constructor(fileInfo) {
@@ -67,12 +67,34 @@ export default class FileReceiver extends Nanobus {
     return result.slice(0, offset).buffer;
   }
 
+  sendMessageToSw(msg) {
+    return new Promise( (resolve, reject) => {
+      const channel = new MessageChannel();
+
+      channel.port1.onmessage = function(event) {
+        if(event.data.error !== undefined) {
+          reject(event.data.error);
+        } else {
+          resolve(event.data);
+        }
+      }
+     navigator.serviceWorker.controller.postMessage(msg, [channel.port2]);
+    });
+  }
+
   async download(noSave = false) {
     const onprogress = p => {
       this.progress = p;
       this.emit('progress');
     };
 
+    this.downloadRequest = {
+      cancel: () => {
+        this.sendMessageToSw('cancel');
+        //throw new Error(0);
+      }
+    }
+
     try {
       this.state = 'downloading';
 
@@ -83,9 +105,9 @@ export default class FileReceiver extends Nanobus {
         filename: this.fileInfo.name,
         auth: auth
       };
-      navigator.serviceWorker.controller.postMessage(info);
+      await this.sendMessageToSw(info);
 
-      onprogress([0, this.fileInfo.size]);
+      console.log("SENDING REQUEST FROM PAGE ONCE")
 
       if (!noSave) {
         const downloadUrl = `${location.protocol}//${
@@ -96,12 +118,31 @@ export default class FileReceiver extends Nanobus {
         document.body.appendChild(a);
         a.click();
         URL.revokeObjectURL(downloadUrl);
+
+        /*
+        const auth = await this.sendMessageToSw('authHeader');
+        if (auth) {
+          this.keychain.nonce = parseNonce(auth);
+        }
+        */
+
+        let prog = 0;
+        while (prog < this.fileInfo.size) {
+          prog = await this.sendMessageToSw('progress');
+          onprogress([prog, this.fileInfo.size]);
+          await delay();
+        }
       }
 
-      //this.msg = 'downloadFinish';
-      //this.state = 'complete';
+      this.downloadRequest = null;
+      this.msg = 'downloadFinish';
+      this.state = 'complete';
+
     } catch (e) {
       this.downloadRequest = null;
+      if (e === 'cancelled') {
+        throw new Error(0);
+      }
       throw e;
     }
   }

+ 45 - 5
app/serviceWorker.js

@@ -5,17 +5,33 @@ self.addEventListener('install', event => {
 });
 
 async function decryptStream(request) {
+  self.controller = new AbortController();
+  console.log("SW INTERCEPTED DOWNLOAD")
+  console.log(request)
   const response = await fetch(request.url, {
     method: 'GET',
-    headers: { Authorization: self.auth }
+    headers: { Authorization: self.auth },
+    signal: controller.signal
   });
 
   if (response.status !== 200) {
+    console.log(response.status);
     return response;
   }
 
+  self.authHeader = response.headers.get('WWW-Authenticate');
+
+
   const body = response.body; //stream
-  const decrypted = self.keychain.decryptStream(body);
+
+  const progStream = new TransformStream({
+    transform: (chunk, controller) => {
+      self.progress += chunk.length;
+      controller.enqueue(chunk);
+    }
+  });
+
+  const decrypted = self.keychain.decryptStream(body.pipeThrough(progStream));
 
   const headers = {
     headers: {
@@ -35,7 +51,31 @@ self.onfetch = event => {
 };
 
 self.onmessage = event => {
-  self.keychain = new Keychain(event.data.key, event.data.nonce);
-  self.filename = event.data.filename;
-  self.auth = event.data.auth;
+  if (event.data.key) {
+    if (!self.keychain) {
+      self.keychain = new Keychain(event.data.key, event.data.nonce);
+    }
+    self.filename = event.data.filename;
+    self.auth = event.data.auth;
+    self.progress = 0;
+    self.cancelled = false;
+    event.ports[0].postMessage("file info received");
+
+  } else if (event.data === "progress") {
+    if (self.cancelled) {
+      event.ports[0].postMessage({error: "cancelled"});
+    } else {
+      event.ports[0].postMessage(self.progress);
+    }
+
+  } else if (event.data === "authHeader") {
+      event.ports[0].postMessage(self.authHeader);
+
+  } else if (event.data === "cancel") {
+    self.cancelled = true;
+    if (self.controller) {
+      self.controller.abort();
+    }
+    event.ports[0].postMessage("download cancelled");
+  }
 };

+ 1 - 0
app/templates/downloadButton/index.js

@@ -8,6 +8,7 @@ module.exports = function(state, emit) {
 
   function download(event) {
     event.preventDefault();
+    console.log("DOWNLOAD FIRE")
     emit('download', state.fileInfo);
   }
 };