Read API paths and forwarded requests as the router does

The router reads an absolute-form target's path without resolving dot
segments, so a target such as http://host/api/../x still reaches /api
middleware. Take that path the same way when deciding whether the API
response headers apply.

The Street View fallback now treats any forwarding header as forwarded, even
an empty one, before it spends the key.
This commit is contained in:
Sameh Khamis committed 2026-10-21 15:43:29 -07:00
1 parent afe05454d9
commit b75db874c6
5 files changed
+32 -8

No files matched your search

+11 -5
View File
@@ -62,19 +62,25 @@ export const API_HEADERS = Object.freeze({
/**
* Whether a request reaches an `/api` mount, by the router's own rule: the
* prefix compared without case and followed by the end, `/` or `.`. Both the
* raw path and the parsed one (which also covers an absolute-form target) are
* checked, so no spelling the router mounts can miss the headers.
* prefix compared without case and followed by the end, `/` or `.`. The router
* reads an absolute-form target's path without resolving dot segments, so the
* path is taken here the same way (scheme and authority dropped, backslashes as
* slashes), alongside the raw and the fully parsed path; any match counts.
*/
function isApiPath(url) {
const raw = String(url || '/');
const target = raw
.trim()
.split(/[?#]/, 1)[0]
.replace(/\\/g, '/')
.replace(/^[a-z][a-z0-9+.-]*:(?:\/\/[^/]*)?/i, '');
let parsed = '';
try {
parsed = new URL(raw, 'http://localhost').pathname;
} catch {
/* the raw path still decides */
/* the unparsed paths still decide */
}
return [raw.split(/[?#]/, 1)[0], parsed].some((path) =>
return [raw.split(/[?#]/, 1)[0], target, parsed].some((path) =>
/^\/api(?:$|[/.])/i.test(path),
);
}