@@ -69,19 +69,22 @@ export async function readValidatedBody<
6969 * You can use a simple function to validate the body or use a Standard-Schema compatible library like `zod` to define a schema.
7070 *
7171 * @example
72+ * function validateBody(body: any) {
73+ * return typeof body === "object" && body !== null;
74+ * }
75+ *
7276 * app.get("/", async (event) => {
73- * const body = await readValidatedBody(event, (body) => {
74- * return typeof body === "object" && body !== null;
75- * });
77+ * const body = await readValidatedBody(event, validateBody);
7678 * });
7779 * @example
7880 * import { z } from "zod";
7981 *
82+ * const objectSchema = z.object({
83+ * name: z.string().min(3).max(20),
84+ * age: z.number({ coerce: true }).positive().int(),
85+ * });
86+ *
8087 * app.get("/", async (event) => {
81- * const objectSchema = z.object({
82- * name: z.string().min(3).max(20),
83- * age: z.number({ coerce: true }).positive().int(),
84- * });
8588 * const body = await readValidatedBody(event, objectSchema);
8689 * });
8790 *
@@ -98,3 +101,60 @@ export async function readValidatedBody(
98101 const _body = await readBody ( event ) ;
99102 return validateData ( _body , validate ) ;
100103}
104+
105+ /**
106+ * Asserts that request body size is within the specified limit.
107+ *
108+ * If body size exceeds the limit, throws a `413` Request Entity Too Large response error.
109+ *
110+ * @example
111+ * app.get("/", async (event) => {
112+ * await assertBodySize(event, 10 * 1024 * 1024); // 10MB
113+ * const data = await event.req.formData();
114+ * });
115+ *
116+ * @param event HTTP event
117+ * @param limit Body size limit in bytes
118+ */
119+ export async function assertBodySize (
120+ event : HTTPEvent ,
121+ limit : number ,
122+ ) : Promise < void > {
123+ const isWithin = await isBodySizeWithin ( event , limit ) ;
124+ if ( ! isWithin ) {
125+ throw new HTTPError ( {
126+ status : 413 ,
127+ statusText : "Request Entity Too Large" ,
128+ message : `Request body size exceeds the limit of ${ limit } bytes` ,
129+ } ) ;
130+ }
131+ }
132+
133+ // Internal util for now. We can export later if needed
134+ async function isBodySizeWithin (
135+ event : HTTPEvent ,
136+ limit : number ,
137+ ) : Promise < boolean > {
138+ const req = event . req ;
139+ if ( req . body === null ) {
140+ return true ;
141+ }
142+
143+ const bodyLen = req . headers . get ( "content-length" ) ;
144+ if ( bodyLen !== null && ! req . headers . has ( "transfer-encoding" ) ) {
145+ return + bodyLen <= limit ;
146+ }
147+
148+ const reader = req . clone ( ) . body ! . getReader ( ) ;
149+ let chunk = await reader . read ( ) ;
150+ let size = 0 ;
151+ while ( ! chunk . done ) {
152+ size += chunk . value . byteLength ;
153+ if ( size > limit ) {
154+ return false ;
155+ }
156+ chunk = await reader . read ( ) ;
157+ }
158+
159+ return true ;
160+ }
0 commit comments