Skip to content

Commit

Permalink
feature #34847 Add support for safe HTTP preference - RFC 8674 (pyrech)
Browse files Browse the repository at this point in the history
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
-------

7f2cef7 Add support for safe preference - RFC8674
  • Loading branch information
fabpot committed Jan 10, 2020
2 parents c146de1 + 7f2cef7 commit ebf3885
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Symfony/Component/HttpFoundation/CHANGELOG.md
Expand Up @@ -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
-----
Expand Down
28 changes: 28 additions & 0 deletions src/Symfony/Component/HttpFoundation/Request.php
Expand Up @@ -199,6 +199,11 @@ class Request
private $isHostValid = true;
private $isForwardedValid = true;

/**
* @var bool|null
*/
private $isSafeContentPreferred;

private static $trustedHeaderSet = -1;

private static $forwardedParams = [
Expand Down Expand Up @@ -1702,6 +1707,29 @@ public function isXmlHttpRequest()
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)
*
Expand Down
16 changes: 16 additions & 0 deletions src/Symfony/Component/HttpFoundation/Response.php
Expand Up @@ -1210,6 +1210,22 @@ public static function closeOutputBuffers(int $targetLevel, bool $flush): void
}
}

/**
* 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.
*
Expand Down
58 changes: 58 additions & 0 deletions src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
Expand Up @@ -2325,6 +2325,64 @@ public function trustedProxiesRemoteAddr()
[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
Expand Down
18 changes: 18 additions & 0 deletions src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
Expand Up @@ -1040,6 +1040,24 @@ public function testReasonPhraseDefaultsAgainstIana($code, $reasonPhrase)
{
$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
Expand Down

0 comments on commit ebf3885

Please sign in to comment.