@timber-js/app 0.2.0-alpha.133 → 0.2.0-alpha.135
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{actions-BNhpxrnV.js → actions-CHFblsdT.js} +62 -19
- package/dist/_chunks/actions-CHFblsdT.js.map +1 -0
- package/dist/_chunks/{build-output-helper-K7oUCRqU.js → build-output-helper-CfBfOU9m.js} +1 -1
- package/dist/_chunks/{build-output-helper-K7oUCRqU.js.map → build-output-helper-CfBfOU9m.js.map} +1 -1
- package/dist/_chunks/cli-schema-sync-q-Ce6-iG.js.map +1 -1
- package/dist/_chunks/{codec-registry-DqkeAydt.js → codec-registry-G9hD5LOq.js} +1 -1
- package/dist/_chunks/{codec-registry-DqkeAydt.js.map → codec-registry-G9hD5LOq.js.map} +1 -1
- package/dist/_chunks/{define-jeHDXZGq.js → define-DXWUJb-K.js} +3 -3
- package/dist/_chunks/{define-jeHDXZGq.js.map → define-DXWUJb-K.js.map} +1 -1
- package/dist/_chunks/{define-DMq-Yjp7.js → define-Dp-qu3ql.js} +3 -3
- package/dist/_chunks/{define-DMq-Yjp7.js.map → define-Dp-qu3ql.js.map} +1 -1
- package/dist/_chunks/fast-hash-DXZ7S2D5.js +36 -0
- package/dist/_chunks/fast-hash-DXZ7S2D5.js.map +1 -0
- package/dist/_chunks/{format-BjN9HLu9.js → format-CR6v1pWE.js} +1 -1
- package/dist/_chunks/{format-BjN9HLu9.js.map → format-CR6v1pWE.js.map} +1 -1
- package/dist/_chunks/{handler-store-bIAstrxQ.js → handler-store-aQMpqPe7.js} +1 -1
- package/dist/_chunks/{handler-store-bIAstrxQ.js.map → handler-store-aQMpqPe7.js.map} +1 -1
- package/dist/_chunks/href-validation-2G-HZaQ8.js +124 -0
- package/dist/_chunks/href-validation-2G-HZaQ8.js.map +1 -0
- package/dist/_chunks/logger-CMd9P1xQ.js.map +1 -1
- package/dist/_chunks/metadata-routes-DESG8uk5.js.map +1 -1
- package/dist/_chunks/{navigation-root-B5-RmsPi.js → navigation-root-BQqFQI-n.js} +3 -3
- package/dist/_chunks/{navigation-root-B5-RmsPi.js.map → navigation-root-BQqFQI-n.js.map} +1 -1
- package/dist/_chunks/{registry-BI9cgCt7.js → registry-Dp_hJL4s.js} +1 -1
- package/dist/_chunks/{registry-BI9cgCt7.js.map → registry-Dp_hJL4s.js.map} +1 -1
- package/dist/_chunks/{resolve-schema-DU2nbVOi.js → resolve-schema-D3CbcdCW.js} +2 -2
- package/dist/_chunks/{resolve-schema-DU2nbVOi.js.map → resolve-schema-D3CbcdCW.js.map} +1 -1
- package/dist/_chunks/{router-ref-B2-2kIIC.js → router-ref-B50j42zB.js} +2 -2
- package/dist/_chunks/{router-ref-B2-2kIIC.js.map → router-ref-B50j42zB.js.map} +1 -1
- package/dist/_chunks/{schema-bridge-o0SwFtXW.js → schema-bridge-Cuy8BaYu.js} +2 -2
- package/dist/_chunks/{schema-bridge-o0SwFtXW.js.map → schema-bridge-Cuy8BaYu.js.map} +1 -1
- package/dist/_chunks/segment-classify-BjfuctV2.js.map +1 -1
- package/dist/_chunks/{segment-context-Bg0pFbLT.js → segment-context-BnxoPSFQ.js} +1 -1
- package/dist/_chunks/{segment-context-Bg0pFbLT.js.map → segment-context-BnxoPSFQ.js.map} +1 -1
- package/dist/_chunks/{ssr-data-DVX8S7vj.js → ssr-data-DxXyoRrz.js} +1 -1
- package/dist/_chunks/{ssr-data-DVX8S7vj.js.map → ssr-data-DxXyoRrz.js.map} +1 -1
- package/dist/_chunks/{stale-reload-CCqb62Z3.js → stale-reload-DIIIVGh_.js} +1 -1
- package/dist/_chunks/{stale-reload-CCqb62Z3.js.map → stale-reload-DIIIVGh_.js.map} +1 -1
- package/dist/_chunks/tracing-DP5djRq5.js.map +1 -1
- package/dist/_chunks/{use-query-states-C9G6LP0F.js → use-query-states-D9SBlAfp.js} +2 -2
- package/dist/_chunks/{use-query-states-C9G6LP0F.js.map → use-query-states-D9SBlAfp.js.map} +1 -1
- package/dist/_chunks/{use-segment-params-CIeinIx2.js → use-segment-params-x2poKmk8.js} +2 -2
- package/dist/_chunks/use-segment-params-x2poKmk8.js.map +1 -0
- package/dist/_chunks/{validation-AfEFM5ze.js → validation-BoWM_qI1.js} +31 -2
- package/dist/_chunks/validation-BoWM_qI1.js.map +1 -0
- package/dist/_chunks/walkers-BbEu2_Pp.js.map +1 -1
- package/dist/_chunks/warnings-CAzunaGo.js.map +1 -1
- package/dist/adapters/cloudflare-dev.js.map +1 -1
- package/dist/adapters/cloudflare-kv-cache.js.map +1 -1
- package/dist/adapters/cloudflare.js +1 -1
- package/dist/adapters/cloudflare.js.map +1 -1
- package/dist/adapters/nitro.js +1 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/cache-api.d.ts +1 -1
- package/dist/cache/cache-api.d.ts.map +1 -1
- package/dist/cache/index.js +17 -39
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/timber-cache.d.ts +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/client/error-boundary.js +2 -2
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +14 -26
- package/dist/client/index.js.map +1 -1
- package/dist/client/internal.js +8 -8
- package/dist/client/internal.js.map +1 -1
- package/dist/client/link.d.ts +2 -4
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/use-pathname.d.ts.map +1 -1
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/client/use-search-params.d.ts.map +1 -1
- package/dist/codec.js +1 -1
- package/dist/codec.js.map +1 -1
- package/dist/cookies/index.js +3 -3
- package/dist/cookies/index.js.map +1 -1
- package/dist/cookies/validation.d.ts +11 -23
- package/dist/cookies/validation.d.ts.map +1 -1
- package/dist/dev-tools/error-page.d.ts.map +1 -1
- package/dist/fonts/virtual-modules.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +259 -3
- package/dist/index.js.map +1 -1
- package/dist/params/define-schema.d.ts.map +1 -1
- package/dist/params/index.js +2 -2
- package/dist/params/index.js.map +1 -1
- package/dist/plugins/cache.d.ts +31 -0
- package/dist/plugins/cache.d.ts.map +1 -0
- package/dist/routing/link-codegen.d.ts.map +1 -1
- package/dist/schema-bridge.d.ts.map +1 -1
- package/dist/search-params/index.js +3 -3
- package/dist/search-params/index.js.map +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/body-limits.d.ts.map +1 -1
- package/dist/server/cookie-context.d.ts +2 -2
- package/dist/server/cookie-context.d.ts.map +1 -1
- package/dist/server/csrf.d.ts +3 -2
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +17 -8
- package/dist/server/index.js.map +1 -1
- package/dist/server/internal.js +69 -21
- package/dist/server/internal.js.map +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts +5 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +5 -2
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/revalidate-renderer.d.ts +108 -0
- package/dist/server/rsc-entry/revalidate-renderer.d.ts.map +1 -0
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +15 -0
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/sitemap-handler.d.ts.map +1 -1
- package/dist/server/ssr-wrappers.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/dist/shared/href-validation.d.ts +38 -0
- package/dist/shared/href-validation.d.ts.map +1 -0
- package/dist/shims/font-google.js.map +1 -1
- package/dist/shims/font-local.js.map +1 -1
- package/package.json +5 -5
- package/src/cache/cache-api.ts +3 -2
- package/src/cache/timber-cache.ts +27 -4
- package/src/client/index.ts +1 -0
- package/src/client/link.tsx +13 -37
- package/src/client/navigation-context.ts +2 -0
- package/src/client/use-pathname.ts +1 -0
- package/src/client/use-router.ts +3 -0
- package/src/client/use-search-params.ts +1 -0
- package/src/client/use-segment-params.ts +1 -0
- package/src/config-validation.ts +1 -1
- package/src/cookies/validation.ts +58 -0
- package/src/dev-tools/error-page.ts +1 -0
- package/src/fonts/virtual-modules.ts +2 -0
- package/src/index.ts +5 -1
- package/src/params/define-schema.ts +1 -0
- package/src/plugins/cache.ts +180 -0
- package/src/routing/link-codegen.ts +5 -3
- package/src/schema-bridge.ts +3 -2
- package/src/server/action-client.ts +31 -13
- package/src/server/actions.ts +20 -3
- package/src/server/body-limits.ts +10 -2
- package/src/server/cookie-context.ts +7 -2
- package/src/server/cookie-parsing.ts +1 -1
- package/src/server/csrf.ts +39 -6
- package/src/server/deny-renderer.ts +0 -1
- package/src/server/html-injector-core.ts +6 -5
- package/src/server/html-injectors.ts +8 -5
- package/src/server/pipeline-interception.ts +1 -0
- package/src/server/pipeline-phases.ts +30 -19
- package/src/server/pipeline.ts +27 -1
- package/src/server/primitives.ts +19 -18
- package/src/server/route-element-builder.ts +2 -0
- package/src/server/rsc-entry/error-renderer.ts +4 -3
- package/src/server/rsc-entry/index.ts +16 -36
- package/src/server/rsc-entry/revalidate-renderer.ts +344 -0
- package/src/server/rsc-entry/rsc-payload.ts +0 -4
- package/src/server/rsc-entry/ssr-renderer.ts +76 -0
- package/src/server/sitemap-handler.ts +24 -2
- package/src/server/slot-resolver.ts +8 -2
- package/src/server/ssr-wrappers.tsx +2 -0
- package/src/server/tree-builder.ts +2 -0
- package/src/server/types.ts +2 -2
- package/src/shared/href-validation.ts +127 -0
- package/dist/_chunks/actions-BNhpxrnV.js.map +0 -1
- package/dist/_chunks/merge-search-params-Cm1j99HC.js +0 -41
- package/dist/_chunks/merge-search-params-Cm1j99HC.js.map +0 -1
- package/dist/_chunks/use-segment-params-CIeinIx2.js.map +0 -1
- package/dist/_chunks/validation-AfEFM5ze.js.map +0 -1
package/dist/server/internal.js
CHANGED
|
@@ -3,10 +3,10 @@ import { a as warnRedirectInSuspense, c as warnSuspenseWrappingChildren, i as wa
|
|
|
3
3
|
import { i as getMetadataRouteServePath, n as classifyMetadataRoute, r as getMetadataRouteAutoLink, t as METADATA_ROUTE_CONVENTIONS } from "../_chunks/metadata-routes-DESG8uk5.js";
|
|
4
4
|
import { n as classifyUrlSegment } from "../_chunks/segment-classify-BjfuctV2.js";
|
|
5
5
|
import { a as logProxyError, c as logRequestReceived, d as logSwrRefetchFailed, f as logWaitUntilRejected, h as swallow, i as logMiddlewareShortCircuit, l as logRouteError, m as setLogger, n as logCacheMiss, o as logRenderError, p as logWaitUntilUnsupported, r as logMiddlewareError, s as logRequestCompleted, t as getLogger, u as logSlowRequest } from "../_chunks/logger-CMd9P1xQ.js";
|
|
6
|
-
import { C as setMatchedSegmentPath, E as getCookie, O as getSetCookieHeaders, S as runWithRequestContext, T as setSegmentParams, _ as getHeader, b as getSegmentParams, c as DenySignal, d as RenderError, g as applyRequestHeaderOverlay, l as RedirectSignal, n as executeAction, o as coerce, r as isRscActionRequest, t as buildNoJsResponse, w as setMutableCookieContext, x as markResponseFlushed, y as getSearchParams } from "../_chunks/actions-
|
|
6
|
+
import { C as setMatchedSegmentPath, E as getCookie, O as getSetCookieHeaders, S as runWithRequestContext, T as setSegmentParams, _ as getHeader, b as getSegmentParams, c as DenySignal, d as RenderError, g as applyRequestHeaderOverlay, l as RedirectSignal, n as executeAction, o as coerce, r as isRscActionRequest, t as buildNoJsResponse, w as setMutableCookieContext, x as markResponseFlushed, y as getSearchParams } from "../_chunks/actions-CHFblsdT.js";
|
|
7
7
|
import "../client/error-boundary.js";
|
|
8
|
-
import { n as toBracketKey } from "../_chunks/resolve-schema-
|
|
9
|
-
import "../_chunks/segment-context-
|
|
8
|
+
import { n as toBracketKey } from "../_chunks/resolve-schema-D3CbcdCW.js";
|
|
9
|
+
import "../_chunks/segment-context-BnxoPSFQ.js";
|
|
10
10
|
import { readFile } from "node:fs/promises";
|
|
11
11
|
import "node:crypto";
|
|
12
12
|
import React, { createElement } from "react";
|
|
@@ -1621,6 +1621,7 @@ function escapeXml(str) {
|
|
|
1621
1621
|
* followed by '/' or be an exact match.
|
|
1622
1622
|
*/
|
|
1623
1623
|
function hasSegmentPrefix(pathname, prefix) {
|
|
1624
|
+
if (prefix === "/") return true;
|
|
1624
1625
|
if (!pathname.startsWith(prefix)) return false;
|
|
1625
1626
|
return pathname.length === prefix.length || pathname[prefix.length] === "/";
|
|
1626
1627
|
}
|
|
@@ -1830,7 +1831,7 @@ async function runProxyPhase(config, getProxy, req, method, path) {
|
|
|
1830
1831
|
const detailed = config.serverTiming === "detailed";
|
|
1831
1832
|
try {
|
|
1832
1833
|
const proxyExport = await getProxy();
|
|
1833
|
-
const proxyFn = () => runProxy(proxyExport, req, () => handleRequest(config, req, method, path));
|
|
1834
|
+
const proxyFn = () => runProxy(proxyExport, req, () => handleRequest(config, req, method, path, true));
|
|
1834
1835
|
return {
|
|
1835
1836
|
kind: "response",
|
|
1836
1837
|
phase: "proxy",
|
|
@@ -1944,16 +1945,23 @@ async function runRenderPhase(config, req, match, responseHeaders, requestHeader
|
|
|
1944
1945
|
*
|
|
1945
1946
|
* Used both as the top-level entry (when no proxy.ts is configured) and as
|
|
1946
1947
|
* the `next()` continuation passed to `runProxy()`.
|
|
1948
|
+
*
|
|
1949
|
+
* @param pathIsCanonical When true, `path` has already been canonicalized by
|
|
1950
|
+
* `createPipeline` — skip re-canonicalization to prevent double-decode.
|
|
1951
|
+
* When false (default), runs canonicalize as a safety net for direct callers.
|
|
1947
1952
|
*/
|
|
1948
|
-
async function handleRequest(config, req, method, path) {
|
|
1953
|
+
async function handleRequest(config, req, method, path, pathIsCanonical) {
|
|
1949
1954
|
const stripTrailingSlash = config.stripTrailingSlash ?? true;
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
+
let canonicalPathname;
|
|
1956
|
+
if (pathIsCanonical) canonicalPathname = path;
|
|
1957
|
+
else {
|
|
1958
|
+
const result = canonicalize(path, stripTrailingSlash);
|
|
1959
|
+
if (!result.ok) {
|
|
1960
|
+
if (isDebug()) console.warn(`[timber] URL canonicalization rejected ${method} ${path} — responding with ${result.status}\n This usually means the URL contains encoded separators (%2f, %5c),\n null bytes (%00), path traversal (..), or malformed percent-encoding.`);
|
|
1961
|
+
return new Response(null, { status: result.status });
|
|
1962
|
+
}
|
|
1963
|
+
canonicalPathname = result.pathname;
|
|
1955
1964
|
}
|
|
1956
|
-
const canonicalPathname = result.pathname;
|
|
1957
1965
|
if (config.matchMetadataRoute) {
|
|
1958
1966
|
const metaMatch = config.matchMetadataRoute(canonicalPathname);
|
|
1959
1967
|
if (metaMatch) try {
|
|
@@ -2033,7 +2041,7 @@ async function handleRequest(config, req, method, path) {
|
|
|
2033
2041
|
}
|
|
2034
2042
|
}
|
|
2035
2043
|
if (!match) {
|
|
2036
|
-
if (isDebug()) console.warn(`[timber] No route matched for pathname: ${canonicalPathname}\n
|
|
2044
|
+
if (isDebug()) console.warn(`[timber] No route matched for pathname: ${canonicalPathname}\n Input path: ${path}\n Method: ${method}`);
|
|
2037
2045
|
if (config.renderNoMatch) {
|
|
2038
2046
|
const responseHeaders = new Headers();
|
|
2039
2047
|
return cloneWithMutableHeaders(await config.renderNoMatch(req, responseHeaders));
|
|
@@ -2136,8 +2144,14 @@ function createPipeline(config) {
|
|
|
2136
2144
|
method,
|
|
2137
2145
|
path: canonicalPath
|
|
2138
2146
|
});
|
|
2139
|
-
else result = await handleRequest(config, canonicalReq, method, canonicalPath);
|
|
2147
|
+
else result = await handleRequest(config, canonicalReq, method, canonicalPath, true);
|
|
2140
2148
|
await setSpanAttribute("http.response.status_code", result.status);
|
|
2149
|
+
const varyTokens = ["Accept"];
|
|
2150
|
+
if (config.interceptionRewrites?.length) varyTokens.push("X-Timber-URL");
|
|
2151
|
+
const existingVary = result.headers.get("Vary");
|
|
2152
|
+
const existingTokens = existingVary ? existingVary.toLowerCase().split(",").map((t) => t.trim()) : [];
|
|
2153
|
+
const newTokens = varyTokens.filter((t) => !existingTokens.includes(t.toLowerCase()));
|
|
2154
|
+
if (newTokens.length > 0) result.headers.set("Vary", existingVary ? `${existingVary}, ${newTokens.join(", ")}` : newTokens.join(", "));
|
|
2141
2155
|
if (serverTiming === "detailed") {
|
|
2142
2156
|
const timingHeader = getServerTimingHeader();
|
|
2143
2157
|
if (timingHeader) result.headers.set("Server-Timing", timingHeader);
|
|
@@ -2844,12 +2858,34 @@ var SAFE_METHODS = new Set([
|
|
|
2844
2858
|
"OPTIONS"
|
|
2845
2859
|
]);
|
|
2846
2860
|
/**
|
|
2847
|
-
*
|
|
2861
|
+
* Derive the request's scheme from trusted sources.
|
|
2862
|
+
*
|
|
2863
|
+
* Priority:
|
|
2864
|
+
* 1. X-Forwarded-Proto (set by reverse proxies / load balancers)
|
|
2865
|
+
* 2. Request URL protocol
|
|
2866
|
+
*
|
|
2867
|
+
* Falls back to 'https' (fail closed) if neither is available.
|
|
2868
|
+
*/
|
|
2869
|
+
function deriveRequestScheme(req) {
|
|
2870
|
+
const forwarded = req.headers.get("X-Forwarded-Proto");
|
|
2871
|
+
if (forwarded) {
|
|
2872
|
+
const proto = forwarded.split(",")[0].trim().toLowerCase();
|
|
2873
|
+
if (proto === "http" || proto === "https") return proto;
|
|
2874
|
+
}
|
|
2875
|
+
try {
|
|
2876
|
+
return new URL(req.url).protocol.replace(":", "");
|
|
2877
|
+
} catch {
|
|
2878
|
+
return "https";
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
/**
|
|
2882
|
+
* Validate the Origin header against the request's full origin
|
|
2883
|
+
* (scheme + host + port).
|
|
2848
2884
|
*
|
|
2849
2885
|
* For mutation methods (POST, PUT, PATCH, DELETE):
|
|
2850
2886
|
* - If `csrf: false`, skip validation.
|
|
2851
2887
|
* - If `allowedOrigins` is set, Origin must match one exactly (no wildcards).
|
|
2852
|
-
* - Otherwise, Origin
|
|
2888
|
+
* - Otherwise, Origin must match the derived request origin.
|
|
2853
2889
|
*
|
|
2854
2890
|
* Safe methods (GET, HEAD, OPTIONS) always pass.
|
|
2855
2891
|
*/
|
|
@@ -2870,16 +2906,26 @@ function validateCsrf(req, config) {
|
|
|
2870
2906
|
ok: false,
|
|
2871
2907
|
status: 403
|
|
2872
2908
|
};
|
|
2873
|
-
let
|
|
2909
|
+
let originOrigin;
|
|
2910
|
+
try {
|
|
2911
|
+
originOrigin = new URL(origin).origin;
|
|
2912
|
+
} catch {
|
|
2913
|
+
return {
|
|
2914
|
+
ok: false,
|
|
2915
|
+
status: 403
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
const scheme = deriveRequestScheme(req);
|
|
2919
|
+
let expectedOrigin;
|
|
2874
2920
|
try {
|
|
2875
|
-
|
|
2921
|
+
expectedOrigin = new URL(`${scheme}://${host}`).origin;
|
|
2876
2922
|
} catch {
|
|
2877
2923
|
return {
|
|
2878
2924
|
ok: false,
|
|
2879
2925
|
status: 403
|
|
2880
2926
|
};
|
|
2881
2927
|
}
|
|
2882
|
-
return
|
|
2928
|
+
return originOrigin === expectedOrigin ? { ok: true } : {
|
|
2883
2929
|
ok: false,
|
|
2884
2930
|
status: 403
|
|
2885
2931
|
};
|
|
@@ -2909,6 +2955,8 @@ function parseBodySize(size) {
|
|
|
2909
2955
|
default: throw new Error(`Unknown size unit: "${unit}"`);
|
|
2910
2956
|
}
|
|
2911
2957
|
}
|
|
2958
|
+
/** Strict integer pattern: one or more digits, nothing else. */
|
|
2959
|
+
var STRICT_INTEGER_RE = /^\d+$/;
|
|
2912
2960
|
/** Check whether a request body exceeds the configured size limit (stateless, no ALS). */
|
|
2913
2961
|
function enforceBodyLimits(req, kind, config) {
|
|
2914
2962
|
const contentLength = req.headers.get("Content-Length");
|
|
@@ -2916,12 +2964,12 @@ function enforceBodyLimits(req, kind, config) {
|
|
|
2916
2964
|
ok: false,
|
|
2917
2965
|
status: 411
|
|
2918
2966
|
};
|
|
2919
|
-
const
|
|
2920
|
-
if (
|
|
2967
|
+
const trimmed = contentLength.trim();
|
|
2968
|
+
if (!STRICT_INTEGER_RE.test(trimmed)) return {
|
|
2921
2969
|
ok: false,
|
|
2922
2970
|
status: 411
|
|
2923
2971
|
};
|
|
2924
|
-
return
|
|
2972
|
+
return Number.parseInt(trimmed, 10) <= resolveLimit(kind, config) ? { ok: true } : {
|
|
2925
2973
|
ok: false,
|
|
2926
2974
|
status: 413
|
|
2927
2975
|
};
|