Implemented per-route body size limit configuration for the GrantFox campaign, allowing different size limits for different API route categories:
- Default routes: 256 KB (configurable via
MAX_STREAM_BODY_BYTES) - Webhook routes: 1 MB (configurable via
MAX_WEBHOOK_BODY_BYTES)
Extracted and enhanced body size checking logic into a dedicated utility module with the following exports:
DEFAULT_MAX_BODY_BYTES: 256 KB (262,144 bytes)WEBHOOK_MAX_BODY_BYTES: 1 MB (1,048,576 bytes)WRITE_METHODS: Set of HTTP methods that carry request bodies (POST, PUT, PATCH)
resolveMaxBodyBytes(envVar: string, defaultBytes: number): number- Resolves configured limit from environment variable with validationisWebhookPath(pathname: string): boolean- Determines if path is a webhook route (/api/webhooks/*)getBodySizeLimit(pathname: string, limits: object): number- Returns appropriate limit for a pathextractPathname(request: Request): string- Safely extracts pathname from both NextRequest and plain Request objectscreateBodySizeTooLargeResponse(contentLength: number, maxBytes: number, requestId: string): NextResponse- Creates standardized 413 error responsecheckRequestBodySize(request: Request, limits: object): NextResponse | null- Main validation functionbuildLimitsConfig(): object- Builds complete limits configuration from environment variables
Key Properties:
- O(1) complexity: reads Content-Length header without buffering body
- Supports both Edge runtime (NextRequest) and test environments (plain Request)
- Comprehensive validation and error handling
- Structured error responses with request correlation IDs
Refactored middleware to use new bodySize utility:
Removed:
- Inline body size validation logic
- Single configurable limit (MAX_STREAM_BODY_BYTES only)
- Path-specific routing code
Added:
- Import of bodySize utility functions
- Per-route configuration via
buildLimitsConfig() - Support for webhook-specific limits
Updated:
- Body size check now calls
checkRequestBodySize(request, bodyLimits)with limits object
Comprehensive test suite with 90%+ coverage including:
Test Categories:
- Constants validation
resolveMaxBodyBytes()- validates parsing, defaults, and error handlingisWebhookPath()- tests path matching for various webhook routesgetBodySizeLimit()- tests limit selection based on pathextractPathname()- tests pathname extraction for different request typescreateBodySizeTooLargeResponse()- tests error response structurecheckRequestBodySize()- comprehensive end-to-end validationbuildLimitsConfig()- tests configuration building from env vars- Integration tests - full workflow scenarios
Edge Cases Covered:
- Malformed Content-Length headers
- Negative and infinite values
- Boundary conditions (exact limit values)
- Missing headers
- Different HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
- Path variations (/api/webhooks, /api/webhooks/rotate, /api/webhooks/dlq, etc.)
- Request ID generation and forwarding
Added comprehensive webhook test suite covering:
New Test Cases:
- Webhook routes return 413 for bodies exceeding 1 MB limit
- Webhook routes accept bodies at and below 1 MB limit
- Nested webhook paths (
/api/webhooks/rotate,/api/webhooks/deliveries,/api/webhooks/dlq) - Error messages include correct 1 MB limit (1,048,576 bytes)
- MAX_WEBHOOK_BODY_BYTES environment variable override
- Isolation between webhook and default route limits
- Non-webhook similar paths don't get webhook limits
- Controls the body size limit for default routes
- Must be a positive integer
- Fractional values are floored
- Invalid values are logged and defaults are used
Example:
MAX_STREAM_BODY_BYTES=131072 # 128 KB- Controls the body size limit for webhook routes (
/api/webhooks/*) - Must be a positive integer
- Fractional values are floored
- Invalid values are logged and defaults are used
Example:
MAX_WEBHOOK_BODY_BYTES=2097152 # 2 MB/api/v2/streams/api/v2/streams/{id}/api/v2/streams/{id}/pause/api/v2/streams/{id}/resume- Other
/api/*routes not matching webhook patterns
/api/webhooks/api/webhooks/rotate/api/webhooks/deliveries/api/webhooks/dlq- Any path starting with
/api/webhooks
Returned when Content-Length exceeds configured limit for the route:
{
"error": {
"code": "REQUEST_TOO_LARGE",
"message": "Request body exceeds the 262144-byte limit. Received Content-Length: 300000 bytes.",
"request_id": "req_abc123def456"
}
}Fields:
code: Standard error code for identificationmessage: Includes configured limit and received size for debuggingrequest_id: Forwarded from request header or auto-generated (format:req_${timestamp})
- All 413 responses include the request fingerprint header (
x-request-id) - Fingerprints are set before body size check for correlation
- Handles both NextRequest (Edge runtime) and plain Request objects (tests)
- Falls back to URL.pathname parsing if nextUrl is unavailable
- Gracefully handles malformed URLs
- O(1) complexity: only reads Content-Length header
- No body buffering or streaming
- Clients without Content-Length are allowed through (downstream responsibility)
- Minimum 90% line coverage on changed files
- Unit tests in
lib/bodySize.test.ts(~80 test cases) - Integration tests in
middleware.test.ts(~15 new test cases)
# Test bodySize utility
npm test -- lib/bodySize.test.ts
# Test middleware with new webhook tests
npm test -- middleware.test.ts
# All tests with coverage
npm test -- --coverageIf using custom MAX_STREAM_BODY_BYTES:
- No change needed - behavior is backward compatible
- New
MAX_WEBHOOK_BODY_BYTEScan be set independently
- Existing clients under 256 KB are unaffected
- Webhook clients can now send up to 1 MB (increased from 256 KB)
- Error responses maintain same structure, only limits may differ
- Boundary Enforcement: Limits are checked at Content-Length level, preventing unnecessary resource allocation
- Input Validation: All numeric inputs are validated before use
- Error Disclosure: Error messages include actual vs. allowed sizes for debugging (consider logging level in production)
- Request Correlation: All errors include request IDs for audit trails
- Route pattern matching for more granular control
- Dynamic limit adjustment based on client authentication
- Metrics collection for body size distribution analysis
- Rate limiting integration with per-route quotas