From 5d7dfc61690b68c1738d87f202ab1ca22d9d78b1 Mon Sep 17 00:00:00 2001 From: Simon Schick Date: Thu, 9 Jan 2014 12:59:13 +0100 Subject: [PATCH] Return 415 on unsupported format in request-body --- DependencyInjection/Configuration.php | 3 +++ DependencyInjection/FOSRestExtension.php | 1 + EventListener/BodyListener.php | 16 +++++++++++++++- Resources/config/body_listener.xml | 1 + Resources/doc/configuration-reference.md | 1 + .../DependencyInjection/FOSRestExtensionTest.php | 1 + Tests/EventListener/BodyListenerTest.php | 15 ++++++++++++--- 7 files changed, 34 insertions(+), 4 deletions(-) diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index 4ed5b1314..a7f716a50 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -168,6 +168,9 @@ private function addBodyListenerSection(ArrayNodeDefinition $rootNode) ->addDefaultsIfNotSet() ->canBeUnset() ->children() + ->booleanNode('throw_exception_on_unsupported_content_type') + ->defaultFalse() + ->end() ->arrayNode('decoders') ->useAttributeAsKey('name') ->defaultValue(array('json' => 'fos_rest.decoder.json', 'xml' => 'fos_rest.decoder.xml')) diff --git a/DependencyInjection/FOSRestExtension.php b/DependencyInjection/FOSRestExtension.php index 27e6d27e9..f2c66098d 100644 --- a/DependencyInjection/FOSRestExtension.php +++ b/DependencyInjection/FOSRestExtension.php @@ -121,6 +121,7 @@ public function load(array $configs, ContainerBuilder $container) if (!empty($config['body_listener'])) { $loader->load('body_listener.xml'); + $container->setParameter($this->getAlias().'.throw_exception_on_unsupported_content_type', $config['body_listener']['throw_exception_on_unsupported_content_type']); $container->setParameter($this->getAlias().'.decoders', $config['body_listener']['decoders']); } diff --git a/EventListener/BodyListener.php b/EventListener/BodyListener.php index 1ac9b152e..751890aa4 100644 --- a/EventListener/BodyListener.php +++ b/EventListener/BodyListener.php @@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; +use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException; /** * This listener handles Request body decoding. @@ -28,20 +29,29 @@ class BodyListener */ private $decoderProvider; + /** + * @var boolean + */ + private $throwExceptionOnUnsupportedContentType; + /** * Constructor. * * @param DecoderProviderInterface $decoderProvider Provider for fetching decoders + * @param boolean $throwExceptionOnUnsupportedContentType */ - public function __construct(DecoderProviderInterface $decoderProvider) + public function __construct(DecoderProviderInterface $decoderProvider, $throwExceptionOnUnsupportedContentType = false) { $this->decoderProvider = $decoderProvider; + $this->throwExceptionOnUnsupportedContentType = $throwExceptionOnUnsupportedContentType; } /** * Core request handler * * @param GetResponseEvent $event The event + * @throws BadRequestHttpException + * @throws UnsupportedMediaTypeHttpException */ public function onKernelRequest(GetResponseEvent $event) { @@ -57,6 +67,10 @@ public function onKernelRequest(GetResponseEvent $event) : $request->getFormat($contentType); if (!$this->decoderProvider->supports($format)) { + if ($this->throwExceptionOnUnsupportedContentType) { + throw new UnsupportedMediaTypeHttpException("Request body format '$format' not supported"); + } + return; } diff --git a/Resources/config/body_listener.xml b/Resources/config/body_listener.xml index bae9ae6af..d62380e30 100644 --- a/Resources/config/body_listener.xml +++ b/Resources/config/body_listener.xml @@ -32,6 +32,7 @@ + %fos_rest.throw_exception_on_unsupported_content_type% diff --git a/Resources/doc/configuration-reference.md b/Resources/doc/configuration-reference.md index 72c697987..4c18a1e77 100644 --- a/Resources/doc/configuration-reference.md +++ b/Resources/doc/configuration-reference.md @@ -65,6 +65,7 @@ fos_rest: # Prototype name: [] body_listener: + throw_exception_on_unsupported_content_type: false decoders: # Prototype diff --git a/Tests/DependencyInjection/FOSRestExtensionTest.php b/Tests/DependencyInjection/FOSRestExtensionTest.php index 53c734ad8..b5613ce08 100644 --- a/Tests/DependencyInjection/FOSRestExtensionTest.php +++ b/Tests/DependencyInjection/FOSRestExtensionTest.php @@ -88,6 +88,7 @@ public function testLoadBodyListenerWithDefaults() $this->assertTrue($this->container->hasDefinition('fos_rest.body_listener')); $this->assertParameter($decoders, 'fos_rest.decoders'); + $this->assertParameter(false, 'fos_rest.throw_exception_on_unsupported_content_type'); } public function testDisableFormatListener() diff --git a/Tests/EventListener/BodyListenerTest.php b/Tests/EventListener/BodyListenerTest.php index 0ff48bde7..dd0ee9fb9 100644 --- a/Tests/EventListener/BodyListenerTest.php +++ b/Tests/EventListener/BodyListenerTest.php @@ -15,7 +15,6 @@ use Symfony\Component\HttpFoundation\HeaderBag; use FOS\RestBundle\Decoder\ContainerDecoderProvider; use FOS\RestBundle\EventListener\BodyListener; -use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; /** * Request listener test @@ -31,10 +30,11 @@ class BodyListenerTest extends \PHPUnit_Framework_TestCase * @param string $method a http method (e.g. POST, GET, PUT, ...) * @param string $contentType the request header content type * @param array $expectedParameters the http parameters of the updated request + * @param boolean $throwExceptionOnUnsupportedContentType * * @dataProvider testOnKernelRequestDataProvider */ - public function testOnKernelRequest($decode, $request, $method, $contentType, $expectedParameters) + public function testOnKernelRequest($decode, $request, $method, $contentType, $expectedParameters, $throwExceptionOnUnsupportedContentType = false) { $decoder = $this->getMockBuilder('FOS\RestBundle\Decoder\DecoderInterface')->disableOriginalConstructor()->getMock(); $decoder->expects($this->any()) @@ -43,7 +43,7 @@ public function testOnKernelRequest($decode, $request, $method, $contentType, $e $decoderProvider = new ContainerDecoderProvider(array('json' => 'foo')); - $listener = new BodyListener($decoderProvider); + $listener = new BodyListener($decoderProvider, $throwExceptionOnUnsupportedContentType); if ($decode) { $container = $this->getMock('Symfony\Component\DependencyInjection\Container', array('get')); @@ -93,4 +93,13 @@ public function testBadRequestExceptionOnMalformedContent() $this->testOnKernelRequest(true, new Request(array(), array(), array(), array(), array(), array(), 'foo'), 'POST', 'application/json', array()); } + /** + * Test that a unallowed format will cause a UnsupportedMediaTypeHttpException to be thrown + */ + public function testUnsupportedMediaTypeHttpExceptionOnUnsupportedMediaType() + { + $this->setExpectedException('\Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException'); + $this->testOnKernelRequest(false, new Request(array(), array(), array(), array(), array(), array(), 'foo'), 'POST', 'application/foo', array(), true); + } + }