Browse Source

`yii\filters\ContentNegotiator` now generates 406 'Not Acceptable' instead of 415 'Unsupported Media Type' on content-type negotiation fail

tags/3.0.0-alpha1
Klimov Paul 7 years ago
parent
commit
2e01076abc
  1. 1
      framework/CHANGELOG.md
  2. 12
      framework/filters/ContentNegotiator.php
  3. 44
      tests/framework/filters/ContentNegotiatorTest.php

1
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)

12
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.');
}
/**

44
tests/framework/filters/ContentNegotiatorTest.php

@ -0,0 +1,44 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yiiunit\framework\filters;
use Yii;
use yii\filters\ContentNegotiator;
use yii\web\NotAcceptableHttpException;
use yii\web\Response;
use yiiunit\TestCase;
class ContentNegotiatorTest extends TestCase
{
protected function setUp()
{
parent::setUp();
$_SERVER['SCRIPT_FILENAME'] = '/index.php';
$_SERVER['SCRIPT_NAME'] = '/index.php';
$this->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();
}
}
Loading…
Cancel
Save