@@ -11,7 +11,7 @@ import {
1111 createErrorResponse ,
1212 type ErrorResponse ,
1313} from "./response-schemas" ;
14- import { isPublicEndpoint } from "./validation" ;
14+ import { isPublicEndpoint , MAX_REQUEST_SIZE } from "./validation" ;
1515import { routeRequest } from "./router" ;
1616
1717/**
@@ -29,6 +29,29 @@ export async function handleRequest(req: Request): Promise<Response> {
2929 const url = new URL ( req . url ) ;
3030 const path = url . pathname ;
3131
32+ // Reject oversized requests early using the Content-Length header.
33+ // Only reject when the header is present; chunked requests (no header) pass through.
34+ const contentLength = req . headers . get ( "content-length" ) ;
35+ if (
36+ contentLength !== null &&
37+ parseInt ( contentLength , 10 ) > MAX_REQUEST_SIZE
38+ ) {
39+ const error : ErrorResponse = createErrorResponse (
40+ ErrorCode . PAYLOAD_TOO_LARGE ,
41+ "Request body exceeds 1MB limit" ,
42+ 413 ,
43+ requestId
44+ ) ;
45+ return new Response ( JSON . stringify ( error , null , 2 ) , {
46+ status : 413 ,
47+ headers : {
48+ "Content-Type" : "application/json" ,
49+ ...getCorsHeaders ( requestOrigin ) ,
50+ "X-Request-ID" : requestId ,
51+ } ,
52+ } ) ;
53+ }
54+
3255 // Check if endpoint is public or CORS preflight (OPTIONS)
3356 // CORS preflight requests must skip auth since browsers don't send credentials
3457 const isPublic = isPublicEndpoint ( path ) || req . method === "OPTIONS" ;
0 commit comments