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