Description
Symfony version(s) affected
6.2.8
Description
I was writing a crawler for an API on Drupal.org and I tried to be nice for the provider by caching responses locally. I have followed the official documentation for enabling response caching on the HTTP client. I was surprised to see that the responses are not being cached. I dig deeper and deeper and I spotted that private
Cache-Control header appears in responses, however the API backend definitely does not send that header.
I think the root cause is related to the implementation in the HTTP.
- ˙\Symfony\Component\HttpKernel\HttpClientKernel::handle()` builds a new response in
- Which calls
\Symfony\Component\HttpFoundation\ResponseHeaderBag::computeCacheControlValue()
marks the response areprivate
due to the lack of explicitly specifiedpublic
header value. This bubbles up the following calls...
https://github.com/symfony/symfony/blob/v6.2.8/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php#L255-L259 - ...even if there is a workaround (I suppose) here for ignoring calculated headers
symfony/src/Symfony/Component/HttpKernel/HttpClientKernel.php
Lines 64 to 69 in 93fbfe0
Stack trace:
How to reproduce
POC
$ php guzzle.php
Array
(
[0] => store, no-cache, must-revalidate, post-check=0, pre-check=0
)
$ php symfony.php
Array
(
[0] => store, no-cache, must-revalidate, post-check=0, pre-check=0
)
$ php symfony_with_cache.php
Array
(
[0] => must-revalidate, no-cache, post-check=0, pre-check=0, private, store
)
symfony.php
use Symfony\Component\HttpClient\HttpClient;
$client = HttpClient::create();
$response = $client->request('GET', 'https://updates.drupal.org/release-history/drupal/current?version=10.0.0', [
'headers' => [
'Accept' => 'text/xml',
],
]);
print_r($response->getHeaders()['cache-control']);
symfony-with-cache.php
use Symfony\Component\HttpClient\CachingHttpClient;
use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpKernel\HttpCache\Store;
$client = HttpClient::create();
$client = new CachingHttpClient($client, new Store(__DIR__ . '/cache'));
$response = $client->request('GET', 'https://updates.drupal.org/release-history/drupal/current?version=10.0.0', [
'headers' => [
'Accept' => 'text/xml',
],
]);
print_r($response->getHeaders()['cache-control']);
Possible Solution
No response
Additional Context
The root cause of the issue can be the interpretation of https://www.rfc-editor.org/rfc/rfc7234#section-3.
Only one of these is required, so s-maxage
should not be required on a GET request with HTTP 200 response.
the response either:
* contains an Expires header field (see [Section 5.3](https://www.rfc-editor.org/rfc/rfc7234#section-5.3)), or * contains a max-age response directive (see [Section 5.2.2.8](https://www.rfc-editor.org/rfc/rfc7234#section-5.2.2.8)), or * contains a s-maxage response directive (see [Section 5.2.2.9](https://www.rfc-editor.org/rfc/rfc7234#section-5.2.2.9)) and the cache is shared, or * contains a Cache Control Extension (see [Section 5.2.3](https://www.rfc-editor.org/rfc/rfc7234#section-5.2.3)) that allows it to be cached, or * has a status code that is defined as cacheable by default (see [Section 4.2.2](https://www.rfc-editor.org/rfc/rfc7234#section-4.2.2)), or