feature #34847 Add support for safe HTTP preference - RFC 8674 (pyrech)

This PR was merged into the 5.1-dev branch.

Discussion
----------

Add support for safe HTTP preference - RFC 8674

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| Deprecations? | no
| Tickets       | -
| License       | MIT
| Doc PR        | -

[RFC 8674](https://tools.ietf.org/html/rfc8674) (not a IETF standard at the moment) defines a way for user agents to ask for "safe" content to a server. This PR add helper methods to :
- know if the user agent prefers a safe content
- mark the response as safe

Commits
-------

7f2cef759c Add support for safe preference - RFC8674
This commit is contained in:
Fabien Potencier 2020-01-10 09:14:56 +01:00
commit ebf3885aca
5 changed files with 122 additions and 0 deletions

View File

@ -7,6 +7,8 @@ CHANGELOG
* Deprecate `Response::create()`, `JsonResponse::create()`,
`RedirectResponse::create()`, and `StreamedResponse::create()` methods (use
`__construct()` instead)
* added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference
according to [RFC 8674](https://tools.ietf.org/html/rfc8674)
5.0.0
-----

View File

@ -199,6 +199,11 @@ class Request
private $isHostValid = true;
private $isForwardedValid = true;
/**
* @var bool|null
*/
private $isSafeContentPreferred;
private static $trustedHeaderSet = -1;
private static $forwardedParams = [
@ -1702,6 +1707,29 @@ class Request
return 'XMLHttpRequest' == $this->headers->get('X-Requested-With');
}
/**
* Checks whether the client browser prefers safe content or not according to RFC8674.
*
* @see https://tools.ietf.org/html/rfc8674
*/
public function preferSafeContent(): bool
{
if (null !== $this->isSafeContentPreferred) {
return $this->isSafeContentPreferred;
}
if (!$this->isSecure()) {
// see https://tools.ietf.org/html/rfc8674#section-3
$this->isSafeContentPreferred = false;
return $this->isSafeContentPreferred;
}
$this->isSafeContentPreferred = AcceptHeader::fromString($this->headers->get('Prefer'))->has('safe');
return $this->isSafeContentPreferred;
}
/*
* The following methods are derived from code of the Zend Framework (1.10dev - 2010-01-24)
*

View File

@ -1210,6 +1210,22 @@ class Response
}
}
/**
* Mark a response as safe according to RFC8674.
*
* @see https://tools.ietf.org/html/rfc8674
*/
public function setContentSafe(bool $safe = true): void
{
if ($safe) {
$this->headers->set('Preference-Applied', 'safe');
} elseif ('safe' === $this->headers->get('Preference-Applied')) {
$this->headers->remove('Preference-Applied');
}
$this->setVary('Prefer', false);
}
/**
* Checks if we need to remove Cache-Control for SSL encrypted downloads when using IE < 9.
*

View File

@ -2325,6 +2325,64 @@ class RequestTest extends TestCase
[null, ['REMOTE_ADDR', '2.2.2.2'], ['2.2.2.2']],
];
}
/**
* @dataProvider preferSafeContentData
*/
public function testPreferSafeContent($server, bool $safePreferenceExpected)
{
$request = new Request([], [], [], [], [], $server);
$this->assertEquals($safePreferenceExpected, $request->preferSafeContent());
}
public function preferSafeContentData()
{
return [
[[], false],
[
[
'HTTPS' => 'on',
],
false,
],
[
[
'HTTPS' => 'off',
'HTTP_PREFER' => 'safe',
],
false,
],
[
[
'HTTPS' => 'on',
'HTTP_PREFER' => 'safe',
],
true,
],
[
[
'HTTPS' => 'on',
'HTTP_PREFER' => 'unknown-preference',
],
false,
],
[
[
'HTTPS' => 'on',
'HTTP_PREFER' => 'unknown-preference=42, safe',
],
true,
],
[
[
'HTTPS' => 'on',
'HTTP_PREFER' => 'safe, unknown-preference=42',
],
true,
],
];
}
}
class RequestContentProxy extends Request

View File

@ -1040,6 +1040,24 @@ class ResponseTest extends ResponseTestCase
{
$this->assertEquals($reasonPhrase, Response::$statusTexts[$code]);
}
public function testSetContentSafe()
{
$response = new Response();
$this->assertFalse($response->headers->has('Preference-Applied'));
$this->assertFalse($response->headers->has('Vary'));
$response->setContentSafe();
$this->assertSame('safe', $response->headers->get('Preference-Applied'));
$this->assertSame('Prefer', $response->headers->get('Vary'));
$response->setContentSafe(false);
$this->assertFalse($response->headers->has('Preference-Applied'));
$this->assertSame('Prefer', $response->headers->get('Vary'));
}
}
class StringableObject