From 2e01076abc2c5d4db9edbc2043e8e9442bdfe294 Mon Sep 17 00:00:00 2001 From: Klimov Paul Date: Thu, 7 Sep 2017 18:08:36 +0300 Subject: [PATCH] `yii\filters\ContentNegotiator` now generates 406 'Not Acceptable' instead of 415 'Unsupported Media Type' on content-type negotiation fail --- framework/CHANGELOG.md | 1 + framework/filters/ContentNegotiator.php | 12 +++---- tests/framework/filters/ContentNegotiatorTest.php | 44 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 tests/framework/filters/ContentNegotiatorTest.php diff --git a/framework/CHANGELOG.md b/framework/CHANGELOG.md index ae05cca..2f37284 100644 --- a/framework/CHANGELOG.md +++ b/framework/CHANGELOG.md @@ -4,6 +4,7 @@ Yii Framework 2 Change Log 2.1.0 under development ----------------------- +- Bug #12539: `yii\filters\ContentNegotiator` now generates 406 'Not Acceptable' instead of 415 'Unsupported Media Type' on content-type negotiation fail (PowerGamer1) - Bug #14458: Fixed `yii\filters\VerbFilter` uses case-insensitive comparison for the HTTP method name (klimov-paul) - Enh #879: Caching implementation refactored according to PSR-16 'Simple Cache' specification (klimov-paul) - Enh #11328: Added support for PSR-7 'HTTP Message' (klimov-paul) diff --git a/framework/filters/ContentNegotiator.php b/framework/filters/ContentNegotiator.php index 45483dc..8acb7ac 100644 --- a/framework/filters/ContentNegotiator.php +++ b/framework/filters/ContentNegotiator.php @@ -11,9 +11,9 @@ use Yii; use yii\base\ActionFilter; use yii\base\BootstrapInterface; use yii\base\InvalidConfigException; +use yii\web\NotAcceptableHttpException; use yii\web\Request; use yii\web\Response; -use yii\web\UnsupportedMediaTypeHttpException; /** * ContentNegotiator supports response format negotiation and application language negotiation. @@ -87,7 +87,7 @@ class ContentNegotiator extends ActionFilter implements BootstrapInterface { /** * @var string the name of the GET parameter that specifies the response format. - * Note that if the specified format does not exist in [[formats]], a [[UnsupportedMediaTypeHttpException]] + * Note that if the specified format does not exist in [[formats]], a [[NotAcceptableHttpException]] * exception will be thrown. If the parameter value is empty or if this property is null, * the response format will be determined based on the `Accept` HTTP header only. * @see formats @@ -104,7 +104,7 @@ class ContentNegotiator extends ActionFilter implements BootstrapInterface /** * @var array list of supported response formats. The keys are MIME types (e.g. `application/json`) * while the values are the corresponding formats (e.g. `html`, `json`) which must be supported - * as declared in [[\yii\web\Response::formatters]]. + * as declared in [[\yii\web\Response::$formatters]]. * * If this property is empty or not set, response format negotiation will be skipped. */ @@ -166,7 +166,7 @@ class ContentNegotiator extends ActionFilter implements BootstrapInterface * @param Request $request * @param Response $response * @throws InvalidConfigException if [[formats]] is empty - * @throws UnsupportedMediaTypeHttpException if none of the requested content types is accepted. + * @throws NotAcceptableHttpException if none of the requested content types is accepted. */ protected function negotiateContentType($request, $response) { @@ -178,7 +178,7 @@ class ContentNegotiator extends ActionFilter implements BootstrapInterface return; } - throw new UnsupportedMediaTypeHttpException('The requested response format is not supported: ' . $format); + throw new NotAcceptableHttpException('The requested response format is not supported: ' . $format); } $types = $request->getAcceptableContentTypes(); @@ -205,7 +205,7 @@ class ContentNegotiator extends ActionFilter implements BootstrapInterface } } - throw new UnsupportedMediaTypeHttpException('None of your requested content types is supported.'); + throw new NotAcceptableHttpException('None of your requested media types is supported.'); } /** diff --git a/tests/framework/filters/ContentNegotiatorTest.php b/tests/framework/filters/ContentNegotiatorTest.php new file mode 100644 index 0000000..a2f689c --- /dev/null +++ b/tests/framework/filters/ContentNegotiatorTest.php @@ -0,0 +1,44 @@ +mockWebApplication(); + } + + public function testNegotiateContentType() + { + $filter = new ContentNegotiator([ + 'formats' => [ + 'application/json' => Response::FORMAT_JSON, + ], + ]); + + Yii::$app->request->setAcceptableContentTypes(['application/json' => ['q' => 1, 'version' => '1.0']]); + $filter->negotiate(); + $this->assertSame('json', Yii::$app->response->format); + + $this->expectException(NotAcceptableHttpException::class); + Yii::$app->request->setAcceptableContentTypes(['application/xml' => ['q' => 1, 'version' => '2.0']]); + $filter->negotiate(); + } +} \ No newline at end of file