astro
Version:
Astro is a modern site builder with web best practices, performance, and DX front-of-mind.
62 lines (61 loc) • 2.71 kB
JavaScript
import { prependForwardSlash, stripRequestBase } from "@astrojs/internal-helpers/path";
import { computePathnameFromDomain } from "../i18n/domain.js";
import { AstroIntegrationLogger } from "../logger/core.js";
import { getLogger } from "../logger/manifest-logger.js";
import { validateAndDecodePathname } from "../util/pathname.js";
import { matchAllRoutes, matchRoute } from "./route-table.js";
/**
* Fully decodes a pathname, falling back to a single decode and then the raw pathname
* when validation fails. Matching runs before `render()`, so it must not throw for
* request input that render-time validation handles.
*/
function safeDecodePathname(manifest, pathname) {
try {
return validateAndDecodePathname(pathname);
} catch (e) {
// Path decoding failures are request input rather than a server fault. Log at
// `debug` so they stay diagnosable without flooding error logs. The logger is
// allocated lazily with the same options and label as the facade's `adapterLogger`.
new AstroIntegrationLogger(getLogger(manifest).options, manifest.adapterName).debug(e.toString());
try {
return decodeURI(pathname);
} catch {
return pathname;
}
}
}
/**
* Given a `Request`, returns the `RouteData` that matches its pathname — the
* appless, purely functional body of `BaseApp.match()`. By default, prerendered
* routes aren't returned, even if they are matched; when
* `allowPrerenderedRoutes` is `true`, matched prerendered routes are returned
* too.
*/
export function matchRequest(manifest, request, allowPrerenderedRoutes = false) {
const url = new URL(request.url);
// ignore requests matching public assets
if (manifest.assets.has(url.pathname)) return undefined;
let pathname = computePathnameFromDomain(request, url, manifest.i18n, manifest.base, manifest.trailingSlash, manifest.allowedDomains, getLogger(manifest));
if (!pathname) {
pathname = prependForwardSlash(stripRequestBase(url.pathname, manifest.base));
}
pathname = safeDecodePathname(manifest, pathname);
const routeData = matchRoute(manifest, pathname);
if (!routeData) return undefined;
if (allowPrerenderedRoutes) {
return routeData;
}
// Prerendered routes are served as static files by the hosting layer.
// When the first match is a prerendered *dynamic* route, try to find
// a non-prerendered route that can serve this path. Dynamic prerendered
// routes only cover their specific static paths, so an SSR route with
// the same pattern should handle all other URLs.
if (routeData.prerender) {
if (routeData.params.length > 0) {
const allMatches = matchAllRoutes(manifest, pathname);
return allMatches.find((r) => !r.prerender);
}
return undefined;
}
return routeData;
}