in src/msha/middlewares/request.middleware.ts [73:207]
async function serveStaticOrProxyResponse(req: http.IncomingMessage, res: http.ServerResponse, proxyApp: httpProxy, target: string | undefined) {
if ([301, 302].includes(res.statusCode)) {
res.end();
return;
}
const customUrl = isCustomUrl(req);
logger.silly(`customUrl: ${chalk.yellow(customUrl)}`);
if (req.url?.includes("index.html") || customUrl) {
// serve index.html or custom pages from user's `outputLocation`
logger.silly(`custom page or index.html detected`);
// extract user custom page filename
req.url = req.url?.replace(CUSTOM_URL_SCHEME, "");
target = DEFAULT_CONFIG.outputLocation;
logger.silly(` - url: ${chalk.yellow(req.url)}`);
logger.silly(` - statusCode: ${chalk.yellow(res.statusCode)}`);
logger.silly(` - target: ${chalk.yellow(target)}`);
}
const is4xx = res.statusCode >= 400 && res.statusCode < 500;
logger.silly(`is4xx: ${is4xx}`);
// if the static app is served by a dev server, forward all requests to it.
if (IS_APP_DEV_SERVER() && (!is4xx || customUrl)) {
logger.silly(`remote dev server detected. Proxying request`);
logger.silly(` - url: ${chalk.yellow(req.url)}`);
logger.silly(` - code: ${chalk.yellow(res.statusCode)}`);
target = DEFAULT_CONFIG.outputLocation;
logRequest(req, target);
let { protocol, hostname, port } = parseUrl(target);
if (hostname === "localhost") {
let waitOnOneOfResources = [`tcp:127.0.0.1:${port}`, `tcp:localhost:${port}`];
let promises = waitOnOneOfResources.map((resource) => {
return waitOn({
resources: [resource],
interval: 100, // poll interval in ms, default 250ms
simultaneous: 1, // limit to 1 connection per resource at a time
timeout: 60000, // timeout in ms, default Infinity
strictSSL: false,
verbose: false, // force disable verbose logs even if SWA_CLI_DEBUG is enabled
})
.then(() => {
logger.silly(`Connected to ${resource} successfully`);
return resource;
})
.catch((err) => {
logger.silly(`Could not connect to ${resource}`);
throw err;
});
});
try {
const availableUrl = await Promise.any(promises);
logger.silly(`${target} validated successfully`);
target = protocol + "//" + availableUrl.slice(4);
} catch {
logger.error(`Could not connect to "${target}". Is the server up and running?`);
}
}
proxyApp.web(
req,
res,
{
target,
secure: false,
toProxy: true,
},
onConnectionLost(req, res, target)
);
proxyApp.once("proxyRes", (proxyRes: http.IncomingMessage) => {
logger.silly(`getting response from dev server`);
logRequest(req, target, proxyRes.statusCode);
});
} else {
// not a dev server
// run one last check before serving the page:
// if the requested file is not found on disk
// send our SWA 404 default page instead of serve-static's one.
let file = null;
let fileInOutputLocation = null;
let existsInOutputLocation = false;
target = DEFAULT_CONFIG.outputLocation as string;
if (target) {
fileInOutputLocation = path.join(target, req.url!);
existsInOutputLocation = fs.existsSync(fileInOutputLocation);
logger.silly(`checking if file exists in user's output location`);
logger.silly(` - file: ${chalk.yellow(fileInOutputLocation)}`);
logger.silly(` - exists: ${chalk.yellow(existsInOutputLocation)}`);
}
if (existsInOutputLocation === false) {
// file doesn't exist in the user's `outputLocation`
// check in the cli public dir
target = SWA_PUBLIC_DIR;
logger.silly(`checking if file exists in CLI public dir`);
const fileInCliPublicDir = path.join(target, req.url!);
const existsInCliPublicDir = fs.existsSync(fileInCliPublicDir);
logger.silly(` - file: ${chalk.yellow(fileInCliPublicDir)}`);
logger.silly(` - exists: ${chalk.yellow(existsInCliPublicDir)}`);
if (existsInCliPublicDir === false) {
req.url = "/404.html";
res.statusCode = 404;
target = SWA_PUBLIC_DIR;
} else {
file = fileInCliPublicDir;
}
} else {
file = fileInOutputLocation;
}
logger.silly(`serving static content`);
logger.silly({ file, url: req.url, code: res.statusCode });
const onerror = (err: any) => console.error(err);
const done = finalhandler(req, res, { onerror }) as any;
// serving static content is only possible for GET requests
req.method = "GET";
serveStatic(target, { extensions: ["html"] })(req, res, done);
}
}