diff --git a/module/Rest/config/dependencies.config.php b/module/Rest/config/dependencies.config.php index 685de2c3..a6b51cb7 100644 --- a/module/Rest/config/dependencies.config.php +++ b/module/Rest/config/dependencies.config.php @@ -18,7 +18,9 @@ return [ Action\ResolveUrlAction::class => AnnotatedFactory::class, Action\GetVisitsAction::class => AnnotatedFactory::class, Action\ListShortcodesAction::class => AnnotatedFactory::class, + Action\EditTagsAction::class => AnnotatedFactory::class, + Middleware\BodyParserMiddleware::class => AnnotatedFactory::class, Middleware\CrossDomainMiddleware::class => InvokableFactory::class, Middleware\CheckAuthenticationMiddleware::class => AnnotatedFactory::class, ], diff --git a/module/Rest/config/middleware-pipeline.config.php b/module/Rest/config/middleware-pipeline.config.php index 78c20c38..817fc568 100644 --- a/module/Rest/config/middleware-pipeline.config.php +++ b/module/Rest/config/middleware-pipeline.config.php @@ -7,6 +7,7 @@ return [ 'rest' => [ 'path' => '/rest', 'middleware' => [ + Middleware\BodyParserMiddleware::class, Middleware\CheckAuthenticationMiddleware::class, Middleware\CrossDomainMiddleware::class, ], diff --git a/module/Rest/src/Middleware/BodyParserMiddleware.php b/module/Rest/src/Middleware/BodyParserMiddleware.php new file mode 100644 index 00000000..598f53ca --- /dev/null +++ b/module/Rest/src/Middleware/BodyParserMiddleware.php @@ -0,0 +1,52 @@ +getMethod(); + if (! in_array($method, ['PUT', 'PATCH'])) { + return $out($request, $response); + } + + $contentType = $request->getHeaderLine('Content-type'); + $rawBody = (string) $request->getBody(); + if (in_array($contentType, ['application/json', 'text/json', 'application/x-json'])) { + return $out($request->withParsedBody(json_decode($rawBody, true)), $response); + } + + $parsedBody = []; + parse_str($rawBody, $parsedBody); + return $out($request->withParsedBody($parsedBody), $response); + } +} diff --git a/module/Rest/test/Middleware/BodyParserMiddlewareTest.php b/module/Rest/test/Middleware/BodyParserMiddlewareTest.php new file mode 100644 index 00000000..17c3057b --- /dev/null +++ b/module/Rest/test/Middleware/BodyParserMiddlewareTest.php @@ -0,0 +1,79 @@ +middleware = new BodyParserMiddleware(); + } + + /** + * @test + */ + public function requestsFromOtherMethodsJustFallbackToNextMiddleware() + { + $request = ServerRequestFactory::fromGlobals()->withMethod('GET'); + $test = $this; + $this->middleware->__invoke($request, new Response(), function ($req, $resp) use ($test, $request) { + $test->assertSame($request, $req); + }); + + $request = $request->withMethod('POST'); + $test = $this; + $this->middleware->__invoke($request, new Response(), function ($req, $resp) use ($test, $request) { + $test->assertSame($request, $req); + }); + } + + /** + * @test + */ + public function jsonRequestsAreJsonDecoded() + { + $body = new Stream('php://temp', 'wr'); + $body->write('{"foo": "bar", "bar": ["one", 5]}'); + $request = ServerRequestFactory::fromGlobals()->withMethod('PUT') + ->withBody($body) + ->withHeader('content-type', 'application/json'); + $test = $this; + $this->middleware->__invoke($request, new Response(), function (Request $req, $resp) use ($test, $request) { + $test->assertNotSame($request, $req); + $test->assertEquals([ + 'foo' => 'bar', + 'bar' => ['one', 5], + ], $req->getParsedBody()); + }); + } + + /** + * @test + */ + public function regularRequestsAreUrlDecoded() + { + $body = new Stream('php://temp', 'wr'); + $body->write('foo=bar&bar[]=one&bar[]=5'); + $request = ServerRequestFactory::fromGlobals()->withMethod('PUT') + ->withBody($body); + $test = $this; + $this->middleware->__invoke($request, new Response(), function (Request $req, $resp) use ($test, $request) { + $test->assertNotSame($request, $req); + $test->assertEquals([ + 'foo' => 'bar', + 'bar' => ['one', 5], + ], $req->getParsedBody()); + }); + } +}