'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,}/;
function getPaths(publicPath, compiler, url) {
const compilers = compiler && compiler.compilers;
if (Array.isArray(compilers)) {
let 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 : parse(compilerPublicPath).pathname;
if (url.indexOf(compilerPublicPathBase) === 0) {
return {
publicPath: compilerPublicPath,
outputPath: compilers[i].outputPath,
};
}
}
}
}
return {
publicPath,
outputPath: compiler.outputPath,
};
}
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);
const localPrefix = parse(publicPath || '/', false, true);
const urlObject = parse(url);
let filename;
const hostNameIsTheSame = localPrefix.hostname === urlObject.hostname;
if (
localPrefix.hostname !== null &&
urlObject.hostname !== null &&
!hostNameIsTheSame
) {
return false;
}
if (publicPath && hostNameIsTheSame && url.indexOf(publicPath) !== 0) {
return false;
}
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;
if (process.platform === 'win32') {
if (filename) {
uri = path.posix.join(outputPath || '', querystring.unescape(filename));
if (!path.win32.isAbsolute(uri)) {
uri = `/${uri}`;
}
}
return uri;
}
if (filename) {
uri = path.posix.join(outputPath || '', filename);
if (!path.posix.isAbsolute(uri)) {
uri = `/${uri}`;
}
}
return querystring.unescape(uri);
},
handleRangeHeaders(content, req, res) {
res.setHeader('Accept-Ranges', 'bytes');
if (req.headers.range) {
const ranges = parseRange(content.length, req.headers.range);
if (ranges === -1) {
res.setHeader('Content-Range', `bytes */${content.length}`);
res.statusCode = 416;
}
if (ranges !== -2 && ranges.length === 1) {
const { length } = content;
res.statusCode = 206;
res.setHeader(
'Content-Range',
`bytes ${ranges[0].start}-${ranges[0].end}/${length}`
);
content = content.slice(ranges[0].start, ranges[0].end + 1);
}
}
return content;
},
handleRequest(context, filename, processRequest, req) {
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) {
}
}
ready(context, processRequest, req);
},
noop: () => {},
ready,
};