+42
-33
| /** | ||
| * The canonical error thrown when a request body exceeds `maxRequestBodySize`. | ||
| * Returns a request whose body is size-limited to `maxRequestBodySize`. | ||
| * | ||
| * It carries a stable, documented shape so any layer can map it to an HTTP | ||
| * `413 Payload Too Large` response without string matching. | ||
| * If the request has no body it is returned unchanged; otherwise it is wrapped | ||
| * in a `Proxy` that routes every body read (`body` / `text` / `json` / | ||
| * `formData` / `arrayBuffer` / `blob` / `bytes` / `bodyUsed`) through a single | ||
| * lazily-created size-limited stream and passes everything else through to the | ||
| * original request. Used for runtimes that have no native body-size option (e.g. | ||
| * Deno) and exported so downstream layers can apply per-handler limits. | ||
| * | ||
| * @see https://srvx.h3.dev/guide/body-limit | ||
| */ | ||
| interface BodyTooLargeError extends Error { | ||
| /** Stable machine-readable code. */ | ||
| code: "ERR_BODY_TOO_LARGE"; | ||
| /** HTTP status to respond with. */ | ||
| statusCode: 413; | ||
| /** Alias of {@link statusCode}. */ | ||
| status: 413; | ||
| } | ||
| /** | ||
| * Creates the canonical {@link BodyTooLargeError | `413 Payload Too Large` error} | ||
| * used across srvx when a request body exceeds the configured `maxRequestBodySize`. | ||
| * Proxy-wrapping (rather than rebuilding via `new Request(request, …)`) is | ||
| * deliberate: it preserves the exact object handed in — including srvx's | ||
| * `ServerRequest` augmentation (`runtime`, `waitUntil`, `ip`, `context`, …) — | ||
| * and works on the Node adapter's `ServerRequest`. The returned | ||
| * value is the same type as the input, so `limitRequestBody(req)` on a | ||
| * `ServerRequest` yields a `ServerRequest`. | ||
| * | ||
| * When the request declares a `Content-Length` that already exceeds the limit, | ||
| * the body is rejected early: the original body is cancelled without being read | ||
| * and the returned request's body errors immediately with the | ||
| * {@link createBodyTooLargeError | `413`-style error}. `Content-Length` is only | ||
| * a fast path — it may be absent (chunked transfer encoding) or understated, so | ||
| * the streaming limit is always enforced regardless. A request that overstates | ||
| * its `Content-Length` is rejected on the declared length (a malformed request, | ||
| * matching how e.g. Bun and nginx enforce limits). The error still surfaces when | ||
| * the body is consumed (`request.text()` / `.json()` / `.arrayBuffer()` / | ||
| * `.body`), matching the streamed-limit behaviour. | ||
| * | ||
| * @see https://srvx.h3.dev/guide/body-limit | ||
| */ | ||
| declare function createBodyTooLargeError(maxRequestBodySize: number): BodyTooLargeError; | ||
| declare function limitRequestBody<T extends Request>(request: T, maxRequestBodySize: number): T; | ||
| /** | ||
@@ -40,23 +48,24 @@ * Wraps a body `ReadableStream` so the total number of bytes read cannot exceed | ||
| /** | ||
| * Returns a `Request` whose body is size-limited to `maxRequestBodySize`. | ||
| * The canonical error thrown when a request body exceeds `maxRequestBodySize`. | ||
| * | ||
| * If the request has no body it is returned unchanged; otherwise it is rebuilt | ||
| * with a size-limited body stream (method, url, headers and signal are | ||
| * preserved). Used for runtimes that expose a native `Request` but no body-size | ||
| * option (e.g. Deno). | ||
| * It carries a stable, documented shape so any layer can map it to an HTTP | ||
| * `413 Payload Too Large` response without string matching. | ||
| * | ||
| * When the request declares a `Content-Length` that already exceeds the limit, | ||
| * the body is rejected early: the original body is cancelled without being read | ||
| * and the returned request's body errors immediately with the | ||
| * {@link createBodyTooLargeError | `413`-style error}. `Content-Length` is only | ||
| * a fast path — it may be absent (chunked transfer encoding) or understated, so | ||
| * the streaming limit is always enforced regardless. A request that overstates | ||
| * its `Content-Length` is rejected on the declared length (a malformed request, | ||
| * matching how e.g. Bun and nginx enforce limits). The error still surfaces when | ||
| * the body is consumed (`request.text()` / `.json()` / `.arrayBuffer()` / | ||
| * `.body`), matching the streamed-limit behaviour. | ||
| * @see https://srvx.h3.dev/guide/body-limit | ||
| */ | ||
| interface BodyTooLargeError extends Error { | ||
| /** Stable machine-readable code. */ | ||
| code: "ERR_BODY_TOO_LARGE"; | ||
| /** HTTP status to respond with. */ | ||
| statusCode: 413; | ||
| /** Alias of {@link statusCode}. */ | ||
| status: 413; | ||
| } | ||
| /** | ||
| * Creates the canonical {@link BodyTooLargeError | `413 Payload Too Large` error} | ||
| * used across srvx when a request body exceeds the configured `maxRequestBodySize`. | ||
| * | ||
| * @see https://srvx.h3.dev/guide/body-limit | ||
| */ | ||
| declare function limitRequestBody(request: Request, maxRequestBodySize: number): Request; | ||
| declare function createBodyTooLargeError(maxRequestBodySize: number): BodyTooLargeError; | ||
| export { BodyTooLargeError, createBodyTooLargeError, limitBodyStream, limitRequestBody }; |
+35
-22
@@ -1,7 +0,18 @@ | ||
| function createBodyTooLargeError(maxRequestBodySize) { | ||
| return Object.assign(/* @__PURE__ */ new Error(`Request body exceeds the maximum allowed size of ${maxRequestBodySize} bytes.`), { | ||
| code: "ERR_BODY_TOO_LARGE", | ||
| statusCode: 413, | ||
| status: 413 | ||
| }); | ||
| function limitRequestBody(request, maxRequestBodySize) { | ||
| if (!request.body) return request; | ||
| const contentLengthHeader = request.headers.get("content-length"); | ||
| const contentLength = contentLengthHeader && /^\d+$/.test(contentLengthHeader) ? Number(contentLengthHeader) : NaN; | ||
| const initiallyUsed = request.bodyUsed; | ||
| const overLimit = contentLength > maxRequestBodySize; | ||
| if (overLimit) request.body.cancel(createBodyTooLargeError(maxRequestBodySize)).catch(() => {}); | ||
| let limited; | ||
| const limitedBody = () => limited ??= new Response(overLimit ? erroredStream(createBodyTooLargeError(maxRequestBodySize)) : limitBodyStream(request.body, maxRequestBodySize)); | ||
| return new Proxy(request, { get(target, prop) { | ||
| if (prop === "body") return limitedBody().body; | ||
| if (prop === "bodyUsed") return initiallyUsed || (limited?.bodyUsed ?? false); | ||
| if (typeof prop === "string" && bodyReadMethods.has(prop)) return () => limitedBody()[prop](); | ||
| if (prop === "clone") return () => limitRequestBody(target.clone(), maxRequestBodySize); | ||
| const value = Reflect.get(target, prop, target); | ||
| return typeof value === "function" ? value.bind(target) : value; | ||
| } }); | ||
| } | ||
@@ -32,20 +43,22 @@ function limitBodyStream(stream, maxRequestBodySize) { | ||
| } | ||
| function limitRequestBody(request, maxRequestBodySize) { | ||
| if (!request.body) return request; | ||
| const contentLengthHeader = request.headers.get("content-length"); | ||
| if ((contentLengthHeader && /^\d+$/.test(contentLengthHeader) ? Number(contentLengthHeader) : NaN) > maxRequestBodySize) { | ||
| const error = createBodyTooLargeError(maxRequestBodySize); | ||
| request.body.cancel(error).catch(() => {}); | ||
| return new Request(request, { | ||
| body: new ReadableStream({ start(controller) { | ||
| controller.error(error); | ||
| } }), | ||
| duplex: "half" | ||
| }); | ||
| } | ||
| return new Request(request, { | ||
| body: limitBodyStream(request.body, maxRequestBodySize), | ||
| duplex: "half" | ||
| const bodyReadMethods = /* @__PURE__ */ new Set([ | ||
| "arrayBuffer", | ||
| "blob", | ||
| "bytes", | ||
| "formData", | ||
| "json", | ||
| "text" | ||
| ]); | ||
| function createBodyTooLargeError(maxRequestBodySize) { | ||
| return Object.assign(/* @__PURE__ */ new Error(`Request body exceeds the maximum allowed size of ${maxRequestBodySize} bytes.`), { | ||
| code: "ERR_BODY_TOO_LARGE", | ||
| statusCode: 413, | ||
| status: 413 | ||
| }); | ||
| } | ||
| function erroredStream(error) { | ||
| return new ReadableStream({ start(controller) { | ||
| controller.error(error); | ||
| } }); | ||
| } | ||
| export { createBodyTooLargeError, limitBodyStream, limitRequestBody }; |
+1
-1
@@ -208,3 +208,3 @@ import { bold, cyan, gray, green, magenta, red, url, yellow } from "./_chunks/_utils.mjs"; | ||
| name: "srvx", | ||
| version: "0.12.1", | ||
| version: "0.12.2", | ||
| description: "Universal Server." | ||
@@ -211,0 +211,0 @@ }; |
+1
-1
| { | ||
| "name": "srvx", | ||
| "version": "0.12.2", | ||
| "version": "0.12.3", | ||
| "description": "Universal Server.", | ||
@@ -5,0 +5,0 @@ "homepage": "https://srvx.h3.dev", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
166637
0.83%3513
0.37%