广丰卷烟厂数采质量分析系统
zhuguifei
2026-03-02 80ff784bf60637cd348ae665fc907f7b1e527dd8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/* eslint-disable */
/* global self ReadableStream Response */
 
self.addEventListener('install', () => {
  self.skipWaiting();
});
 
self.addEventListener('activate', event => {
  event.waitUntil(self.clients.claim());
});
 
const map = new Map();
 
// This should be called once per download
// Each event has a dataChannel that the data will be piped through
self.onmessage = event => {
  // We send a heartbeat every x second to keep the
  // service worker alive if a transferable stream is not sent
  if (event.data === 'ping') {
    return;
  }
 
  const data = event.data;
  const downloadUrl =
    data.url || `${self.registration.scope + Math.random()}/${typeof data === 'string' ? data : data.filename}`;
  const port = event.ports[0];
  const metadata = Array.from({ length: 3 }); // [stream, data, port]
 
  metadata[1] = data;
  metadata[2] = port;
 
  // Note to self:
  // old streamsaver v1.2.0 might still use `readableStream`...
  // but v2.0.0 will always transfer the stream through MessageChannel #94
  if (event.data.readableStream) {
    metadata[0] = event.data.readableStream;
  } else if (event.data.transferringReadable) {
    port.onmessage = evt => {
      port.onmessage = null;
      metadata[0] = evt.data.readableStream;
    };
  } else {
    metadata[0] = createStream(port);
  }
 
  map.set(downloadUrl, metadata);
  port.postMessage({ download: downloadUrl });
};
 
function createStream(port) {
  // ReadableStream is only supported by chrome 52
  return new ReadableStream({
    start(controller) {
      // When we receive data on the messageChannel, we write
      port.onmessage = ({ data }) => {
        if (data === 'end') {
          return controller.close();
        }
 
        if (data === 'abort') {
          controller.error('Aborted the download');
          return;
        }
 
        controller.enqueue(data);
      };
    },
    cancel(reason) {
      console.log('user aborted', reason);
      port.postMessage({ abort: true });
    }
  });
}
 
self.onfetch = event => {
  const url = event.request.url;
 
  // this only works for Firefox
  if (url.endsWith('/ping')) {
    return event.respondWith(new Response('pong'));
  }
 
  const hijacke = map.get(url);
 
  if (!hijacke) return null;
 
  const [stream, data, port] = hijacke;
 
  map.delete(url);
 
  // Not comfortable letting any user control all headers
  // so we only copy over the length & disposition
  const responseHeaders = new Headers({
    'Content-Type': 'application/octet-stream; charset=utf-8',
 
    // To be on the safe side, The link can be opened in a iframe.
    // but octet-stream should stop it.
    'Content-Security-Policy': "default-src 'none'",
    'X-Content-Security-Policy': "default-src 'none'",
    'X-WebKit-CSP': "default-src 'none'",
    'X-XSS-Protection': '1; mode=block',
    'Cross-Origin-Embedder-Policy': 'require-corp'
  });
 
  const headers = new Headers(data.headers || {});
 
  if (headers.has('Content-Length')) {
    responseHeaders.set('Content-Length', headers.get('Content-Length'));
  }
 
  if (headers.has('Content-Disposition')) {
    responseHeaders.set('Content-Disposition', headers.get('Content-Disposition'));
  }
 
  // data, data.filename and size should not be used anymore
  if (data.size) {
    console.warn('Depricated');
    responseHeaders.set('Content-Length', data.size);
  }
 
  let fileName = typeof data === 'string' ? data : data.filename;
  if (fileName) {
    console.warn('Depricated');
    // Make filename RFC5987 compatible
    fileName = encodeURIComponent(fileName).replace(/['()]/g, escape).replace(/\*/g, '%2A');
    responseHeaders.set('Content-Disposition', `attachment; filename*=UTF-8''${fileName}`);
  }
 
  event.respondWith(new Response(stream, { headers: responseHeaders }));
 
  port.postMessage({ debug: 'Download started' });
};