177 lines
No EOL
7.6 KiB
JavaScript
177 lines
No EOL
7.6 KiB
JavaScript
import chalk from "chalk";
|
|
import { isHttpUrl } from "../../core/utils/net.js";
|
|
import { logger } from "../../core/utils/logger.js";
|
|
import { isSWAConfigFileUrl } from "../../core/utils/user-config.js";
|
|
import { IS_APP_DEV_SERVER } from "../../core/constants.js";
|
|
import { handleDataApiRequest } from "../handlers/dab.handler.js";
|
|
import { handleErrorPage } from "../handlers/error-page.handler.js";
|
|
import { handleFunctionRequest, isFunctionRequest } from "../handlers/function.handler.js";
|
|
import { applyRedirectResponse, tryFindFileForRequest } from "../routes-engine/rules/routes.js";
|
|
import { getHeadersForRoute, updateResponseHeaders } from "../routes-engine/rules/headers.js";
|
|
import { getMimeTypeForExtension } from "../routes-engine/rules/mime-types.js";
|
|
import { isRequestPathExcludedFromNavigationFallback } from "../routes-engine/rules/navigation-fallback.js";
|
|
import { parseQueryParams } from "../routes-engine/route-processor.js";
|
|
export function getResponse(req, res, matchedRoute, userConfig, isFunctionRequest, isDataApiRequest) {
|
|
const statusCodeToServe = parseInt(`${matchedRoute?.statusCode}`, 10);
|
|
const redirect = matchedRoute?.redirect;
|
|
const rewrite = matchedRoute?.rewrite;
|
|
logger.silly(`using userConfig`);
|
|
logger.silly({ userConfig });
|
|
if (redirect) {
|
|
logger.silly(` - redirect rule detected. Exit`);
|
|
applyRedirectResponse(req, res, matchedRoute);
|
|
return false;
|
|
}
|
|
// We should always set the x-ms-original-url to be the full request URL.
|
|
req.headers["x-ms-original-url"] = new URL(req.url, `http://${req.headers.host}`).href;
|
|
if (rewrite) {
|
|
req.url = rewrite;
|
|
}
|
|
if ([403, 401].includes(statusCodeToServe)) {
|
|
logger.silly(` - ${statusCodeToServe} code detected. Exit`);
|
|
handleErrorPage(req, res, statusCodeToServe, userConfig?.responseOverrides);
|
|
return false;
|
|
}
|
|
if (isFunctionRequest) {
|
|
handleFunctionRequest(req, res);
|
|
return true;
|
|
}
|
|
if (isDataApiRequest) {
|
|
if (req.url?.startsWith("/data-api/")) {
|
|
req.url = req.url?.replace("/data-api", "");
|
|
}
|
|
handleDataApiRequest(req, res);
|
|
return true;
|
|
}
|
|
const storageResult = getStorageContent(req, res, rewrite, matchedRoute, userConfig?.responseOverrides, userConfig?.navigationFallback, userConfig?.mimeTypes, matchedRoute?.headers, userConfig?.globalHeaders);
|
|
if (storageResult.isFunctionFallbackRequest) {
|
|
req.url = userConfig?.navigationFallback.rewrite;
|
|
handleFunctionRequest(req, res);
|
|
return true;
|
|
}
|
|
if (statusCodeToServe) {
|
|
res.statusCode = statusCodeToServe;
|
|
}
|
|
return false;
|
|
}
|
|
export function getStorageContent(req, res, pathToServe, matchedRoute, responseOverridesRule, navigationFallbackRule, mimeTypeRule, routeHeaders, globalHeaders) {
|
|
logger.silly(`checking storage content`);
|
|
// don't serve staticwebapp.config.json / routes.json
|
|
if (isSWAConfigFileUrl(req)) {
|
|
logger.silly(` - request to config file detected. Exit`);
|
|
handleErrorPage(req, res, 404, responseOverridesRule);
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: false,
|
|
};
|
|
}
|
|
let requestPath = req.url;
|
|
let filePathFromRequest = null;
|
|
let decodedRequestPath = req.url;
|
|
const { urlPathnameWithoutQueryParams } = parseQueryParams(req, matchedRoute);
|
|
// we only process if the user is NOT connecting to a remote dev server.
|
|
// if the user is connecting to a remote dev server, we skip the following logic.
|
|
if (IS_APP_DEV_SERVER()) {
|
|
logger.silly(`remote dev server detected.`);
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: true,
|
|
};
|
|
}
|
|
else {
|
|
requestPath = urlPathnameWithoutQueryParams;
|
|
decodedRequestPath = urlPathnameWithoutQueryParams;
|
|
if (pathToServe) {
|
|
requestPath = pathToServe;
|
|
decodedRequestPath = decodeURI(pathToServe);
|
|
}
|
|
filePathFromRequest = tryFindFileForRequest(requestPath);
|
|
}
|
|
if (!filePathFromRequest) {
|
|
let shouldDisplayNotFoundPage = true;
|
|
if (navigationFallbackRule?.rewrite) {
|
|
const isFunctionFallback = isFunctionRequest(req, navigationFallbackRule.rewrite);
|
|
logger.silly(` - isFunctionFallback: ${chalk.yellow(isFunctionFallback)}`);
|
|
if (isFunctionFallback) {
|
|
return {
|
|
isFunctionFallbackRequest: true,
|
|
isSuccessfulSiteHit: false,
|
|
};
|
|
}
|
|
else {
|
|
const navigationFallbackRewrite = navigationFallbackRule.rewrite;
|
|
logger.silly(`validating navigation fallback rewrite rule`);
|
|
logger.silly(` - rewrite: ${chalk.yellow(navigationFallbackRewrite)}`);
|
|
const isNavigationFallbackWritePathExists = tryFindFileForRequest(navigationFallbackRewrite);
|
|
if (isNavigationFallbackWritePathExists &&
|
|
!isRequestPathExcludedFromNavigationFallback(decodedRequestPath, navigationFallbackRule, matchedRoute)) {
|
|
shouldDisplayNotFoundPage = false;
|
|
}
|
|
if (navigationFallbackRewrite) {
|
|
filePathFromRequest = navigationFallbackRewrite;
|
|
if (!shouldDisplayNotFoundPage) {
|
|
logger.silly(`rewrite request to ${chalk.yellow(filePathFromRequest)}`);
|
|
req.url = filePathFromRequest;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
logger.silly(` - shouldDisplayNotFoundPage: ${chalk.yellow(shouldDisplayNotFoundPage)}`);
|
|
if (shouldDisplayNotFoundPage) {
|
|
handleErrorPage(req, res, 404, responseOverridesRule);
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: false,
|
|
};
|
|
}
|
|
}
|
|
if (!filePathFromRequest) {
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: false,
|
|
};
|
|
}
|
|
// if the file path is a remote HTTP request, this means we are connecting to a dev server.
|
|
// exist here and let the remote server handle the request.
|
|
if (isHttpUrl(filePathFromRequest)) {
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: true,
|
|
};
|
|
}
|
|
// mime type
|
|
const mimeType = getMimeTypeForExtension(filePathFromRequest, mimeTypeRule);
|
|
res.setHeader("Content-Type", mimeType);
|
|
// compute both global and route headers
|
|
const matchingRouteHeaders = getHeadersForRoute(routeHeaders, globalHeaders);
|
|
if (responseOverridesRule) {
|
|
// Handle HEAD request
|
|
if (req.method === "HEAD") {
|
|
updateResponseHeaders(res, matchingRouteHeaders);
|
|
res.statusCode = 200;
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: true,
|
|
};
|
|
}
|
|
// Handle OPTIONS request
|
|
if (req.method === "OPTIONS") {
|
|
updateResponseHeaders(res, matchingRouteHeaders);
|
|
const allowStr = "GET, HEAD, OPTIONS";
|
|
res.setHeader("Allow", allowStr);
|
|
res.statusCode = 204; // No Content
|
|
return {
|
|
isFunctionFallbackRequest: false,
|
|
isSuccessfulSiteHit: true,
|
|
};
|
|
}
|
|
}
|
|
// Handle GET request
|
|
updateResponseHeaders(res, matchingRouteHeaders);
|
|
req.url = filePathFromRequest;
|
|
return {
|
|
isSuccessfulSiteHit: true,
|
|
isFunctionFallbackRequest: false,
|
|
};
|
|
}
|
|
//# sourceMappingURL=response.middleware.js.map
|