createServerRequest('POST', '/x') ->withBody((new StreamFactory())->createStream(str_repeat('a', 512))) ->withHeader('Content-Length', '512'); $response = $mw->process($request, $this->okHandler()); self::assertSame(200, $response->getStatusCode()); } public function testRequestOverCapByContentLengthIs413(): void { $mw = new RequestBodySizeLimitMiddleware(new ResponseFactory(), 1024); $request = (new ServerRequestFactory()) ->createServerRequest('POST', '/x') ->withBody((new StreamFactory())->createStream(str_repeat('a', 4096))) ->withHeader('Content-Length', '4096'); $response = $mw->process($request, $this->shouldNotRunHandler()); self::assertSame(413, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); self::assertSame('payload_too_large', $body['error'] ?? null); } public function testRequestOverCapByStreamSizeIs413(): void { // No Content-Length header (chunked-style request); fall back // to the stream's reported size. $mw = new RequestBodySizeLimitMiddleware(new ResponseFactory(), 1024); $request = (new ServerRequestFactory()) ->createServerRequest('POST', '/x') ->withBody((new StreamFactory())->createStream(str_repeat('a', 4096))); // Strip Content-Length the factory might have set. $request = $request->withoutHeader('Content-Length'); $response = $mw->process($request, $this->shouldNotRunHandler()); self::assertSame(413, $response->getStatusCode()); } public function testEmptyBodyPasses(): void { $mw = new RequestBodySizeLimitMiddleware(new ResponseFactory(), 1024); $request = (new ServerRequestFactory())->createServerRequest('GET', '/healthz'); $response = $mw->process($request, $this->okHandler()); self::assertSame(200, $response->getStatusCode()); } public function testNonNumericContentLengthDoesNotShortCircuitButStreamSizeStillCaught(): void { // A garbage Content-Length is ignored (not a digit string), but // the stream-size fallback catches the actual oversize body. $mw = new RequestBodySizeLimitMiddleware(new ResponseFactory(), 1024); $body = (new StreamFactory())->createStream(str_repeat('a', 4096)); $request = (new ServerRequestFactory()) ->createServerRequest('POST', '/x') ->withBody($body) ->withHeader('Content-Length', 'garbage'); $response = $mw->process($request, $this->shouldNotRunHandler()); self::assertSame(413, $response->getStatusCode()); } private function okHandler(): RequestHandlerInterface { return new class () implements RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface { return (new ResponseFactory())->createResponse(200); } }; } private function shouldNotRunHandler(): RequestHandlerInterface { return new class () implements RequestHandlerInterface { public function handle(ServerRequestInterface $request): ResponseInterface { throw new \LogicException('handler must not be invoked when middleware rejects oversize'); } }; } }