util.js
4.97 KB
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
'use strict';
const path = require('path');
const { parse } = require('url');
const querystring = require('querystring');
const parseRange = require('range-parser');
const HASH_REGEXP = /[0-9a-f]{10,}/;
// support for multi-compiler configuration
// see: https://github.com/webpack/webpack-dev-server/issues/641
function getPaths(publicPath, compiler, url) {
const compilers = compiler && compiler.compilers;
if (Array.isArray(compilers)) {
let compilerPublicPath;
// the path portion of compilerPublicPath
let compilerPublicPathBase;
for (let i = 0; i < compilers.length; i++) {
compilerPublicPath =
compilers[i].options &&
compilers[i].options.output &&
compilers[i].options.output.publicPath;
if (compilerPublicPath) {
compilerPublicPathBase =
compilerPublicPath.indexOf('/') === 0
? compilerPublicPath // eslint-disable-next-line
: // handle the case where compilerPublicPath is a URL with hostname
parse(compilerPublicPath).pathname;
// check the url vs the path part of the compilerPublicPath
if (url.indexOf(compilerPublicPathBase) === 0) {
return {
publicPath: compilerPublicPath,
outputPath: compilers[i].outputPath,
};
}
}
}
}
return {
publicPath,
outputPath: compiler.outputPath,
};
}
// eslint-disable-next-line consistent-return
function ready(context, fn, req) {
if (context.state) {
return fn(context.webpackStats);
}
context.log.info(`wait until bundle finished: ${req.url || fn.name}`);
context.callbacks.push(fn);
}
module.exports = {
getFilenameFromUrl(pubPath, compiler, url) {
const { outputPath, publicPath } = getPaths(pubPath, compiler, url);
// localPrefix is the folder our bundle should be in
const localPrefix = parse(publicPath || '/', false, true);
const urlObject = parse(url);
let filename;
const hostNameIsTheSame = localPrefix.hostname === urlObject.hostname;
// publicPath has the hostname that is not the same as request url's, should fail
if (
localPrefix.hostname !== null &&
urlObject.hostname !== null &&
!hostNameIsTheSame
) {
return false;
}
// publicPath is not in url, so it should fail
if (publicPath && hostNameIsTheSame && url.indexOf(publicPath) !== 0) {
return false;
}
// strip localPrefix from the start of url
if (urlObject.pathname.indexOf(localPrefix.pathname) === 0) {
filename = urlObject.pathname.substr(localPrefix.pathname.length);
}
if (
!urlObject.hostname &&
localPrefix.hostname &&
url.indexOf(localPrefix.path) !== 0
) {
return false;
}
let uri = outputPath;
/* istanbul ignore if */
if (process.platform === 'win32') {
// Path Handling for Microsoft Windows
if (filename) {
uri = path.posix.join(outputPath || '', querystring.unescape(filename));
if (!path.win32.isAbsolute(uri)) {
uri = `/${uri}`;
}
}
return uri;
}
// Path Handling for all other operating systems
if (filename) {
uri = path.posix.join(outputPath || '', filename);
if (!path.posix.isAbsolute(uri)) {
uri = `/${uri}`;
}
}
// if no matches, use outputPath as filename
return querystring.unescape(uri);
},
handleRangeHeaders(content, req, res) {
// assumes express API. For other servers, need to add logic to access
// alternative header APIs
res.setHeader('Accept-Ranges', 'bytes');
if (req.headers.range) {
const ranges = parseRange(content.length, req.headers.range);
// unsatisfiable
if (ranges === -1) {
res.setHeader('Content-Range', `bytes */${content.length}`);
// eslint-disable-next-line no-param-reassign
res.statusCode = 416;
}
// valid (syntactically invalid/multiple ranges are treated as a
// regular response)
if (ranges !== -2 && ranges.length === 1) {
const { length } = content;
// Content-Range
// eslint-disable-next-line no-param-reassign
res.statusCode = 206;
res.setHeader(
'Content-Range',
`bytes ${ranges[0].start}-${ranges[0].end}/${length}`
);
// eslint-disable-next-line no-param-reassign
content = content.slice(ranges[0].start, ranges[0].end + 1);
}
}
return content;
},
handleRequest(context, filename, processRequest, req) {
// in lazy mode, rebuild on bundle request
if (
context.options.lazy &&
(!context.options.filename || context.options.filename.test(filename))
) {
context.rebuild();
}
if (HASH_REGEXP.test(filename)) {
try {
if (context.fs.statSync(filename).isFile()) {
processRequest();
return;
}
} catch (e) {
// eslint-disable-line
}
}
ready(context, processRequest, req);
},
noop: () => {},
ready,
};