1 | 'use strict';
|
2 |
|
3 | const { parse } = require('url');
|
4 | const querystring = require('querystring');
|
5 | const MemoryFileSystem = require('memory-fs');
|
6 | const pathabs = require('path-is-absolute');
|
7 | const parseRange = require('range-parser');
|
8 | const urlJoin = require('url-join');
|
9 |
|
10 | const HASH_REGEXP = /[0-9a-f]{10,}/;
|
11 |
|
12 |
|
13 |
|
14 | function getPaths(publicPath, compiler, url) {
|
15 | const compilers = compiler && compiler.compilers;
|
16 | if (Array.isArray(compilers)) {
|
17 | let compilerPublicPath;
|
18 | for (let i = 0; i < compilers.length; i++) {
|
19 | compilerPublicPath = compilers[i].options
|
20 | && compilers[i].options.output
|
21 | && compilers[i].options.output.publicPath;
|
22 | if (url.indexOf(compilerPublicPath) === 0) {
|
23 | return {
|
24 | publicPath: compilerPublicPath,
|
25 | outputPath: compilers[i].outputPath
|
26 | };
|
27 | }
|
28 | }
|
29 | }
|
30 | return {
|
31 | publicPath,
|
32 | outputPath: compiler.outputPath
|
33 | };
|
34 | }
|
35 |
|
36 | function ready(context, fn, req) {
|
37 | if (context.state) {
|
38 | return fn(context.webpackStats);
|
39 | }
|
40 |
|
41 | context.log.info(`wait until bundle finished: ${req.url || fn.name}`);
|
42 | context.callbacks.push(fn);
|
43 | }
|
44 |
|
45 | module.exports = {
|
46 | getFilenameFromUrl(pubPath, compiler, url) {
|
47 | const { outputPath, publicPath } = getPaths(pubPath, compiler, url);
|
48 |
|
49 | const localPrefix = parse(publicPath || '/', false, true);
|
50 | const urlObject = parse(url);
|
51 | let filename;
|
52 |
|
53 |
|
54 | if (localPrefix.hostname !== null && urlObject.hostname !== null &&
|
55 | localPrefix.hostname !== urlObject.hostname) {
|
56 | return false;
|
57 | }
|
58 |
|
59 |
|
60 | if (publicPath && localPrefix.hostname === urlObject.hostname &&
|
61 | url.indexOf(publicPath) !== 0) {
|
62 | return false;
|
63 | }
|
64 |
|
65 |
|
66 | if (urlObject.pathname.indexOf(localPrefix.pathname) === 0) {
|
67 | filename = urlObject.pathname.substr(localPrefix.pathname.length);
|
68 | }
|
69 |
|
70 | if (!urlObject.hostname && localPrefix.hostname &&
|
71 | url.indexOf(localPrefix.path) !== 0) {
|
72 | return false;
|
73 | }
|
74 |
|
75 | let uri = outputPath;
|
76 |
|
77 | if (filename) {
|
78 | uri = urlJoin((outputPath || '').replace(/\/$/, ''), filename);
|
79 | }
|
80 |
|
81 |
|
82 | return querystring.unescape(uri);
|
83 | },
|
84 |
|
85 | handleRangeHeaders(content, req, res) {
|
86 |
|
87 |
|
88 | res.setHeader('Accept-Ranges', 'bytes');
|
89 |
|
90 | if (req.headers.range) {
|
91 | const ranges = parseRange(content.length, req.headers.range);
|
92 |
|
93 |
|
94 | if (ranges === -1) {
|
95 | res.setHeader('Content-Range', `bytes */${content.length}`);
|
96 | res.statusCode = 416;
|
97 | }
|
98 |
|
99 |
|
100 |
|
101 | if (ranges !== -2 && ranges.length === 1) {
|
102 | const { length } = content;
|
103 |
|
104 |
|
105 | res.statusCode = 206;
|
106 | res.setHeader(
|
107 | 'Content-Range',
|
108 | `bytes ${ranges[0].start}-${ranges[0].end}/${length}`
|
109 | );
|
110 |
|
111 | content = content.slice(ranges[0].start, ranges[0].end + 1);
|
112 | }
|
113 | }
|
114 |
|
115 | return content;
|
116 | },
|
117 |
|
118 | handleRequest(context, filename, processRequest, req) {
|
119 |
|
120 | if (context.options.lazy && (!context.options.filename || context.options.filename.test(filename))) {
|
121 | context.rebuild();
|
122 | }
|
123 |
|
124 | if (HASH_REGEXP.test(filename)) {
|
125 | try {
|
126 | if (context.fs.statSync(filename).isFile()) {
|
127 | processRequest();
|
128 | return;
|
129 | }
|
130 | } catch (e) {
|
131 |
|
132 | }
|
133 | }
|
134 |
|
135 | ready(context, processRequest, req);
|
136 | },
|
137 |
|
138 | noop: () => {},
|
139 |
|
140 | ready,
|
141 |
|
142 | setFs(context, compiler) {
|
143 | if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
|
144 | throw new Error('`output.path` needs to be an absolute path or `/`.');
|
145 | }
|
146 |
|
147 | let fs;
|
148 |
|
149 | const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;
|
150 |
|
151 | if (isMemoryFs) {
|
152 | fs = compiler.outputFileSystem;
|
153 | } else {
|
154 | fs = new MemoryFileSystem();
|
155 | compiler.outputFileSystem = fs;
|
156 | }
|
157 |
|
158 | context.fs = fs;
|
159 | }
|
160 | };
|