|
|
- '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,
- };
|