-
Notifications
You must be signed in to change notification settings - Fork 384
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Cache response status and headers when fetching external stylesheets #4509
Changes from 7 commits
75a98d2
b42340c
78b7bcd
83a14b3
a1203b5
e87ab88
af0b450
d940b45
2784270
fab8ef3
fcc435c
be928c5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<?php | ||
|
||
namespace AmpProject\Exception; | ||
|
||
/** | ||
* Marker interface to enable consumers to catch all exceptions for failed remote requests. | ||
* | ||
* @package ampproject/common | ||
*/ | ||
interface FailedRemoteRequest extends AmpException | ||
{ | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<?php | ||
|
||
namespace AmpProject\Exception; | ||
|
||
use RuntimeException; | ||
|
||
/** | ||
* Exception thrown when a cached remote response could not be retrieved. | ||
* | ||
* @package ampproject/common | ||
*/ | ||
final class FailedToGetCachedResponse extends RuntimeException implements FailedRemoteRequest | ||
{ | ||
|
||
/** | ||
* Instantiate a FailedToGetCachedResponseData exception for a URL if the cached response data could not be retrieved. | ||
* | ||
* @param string $url URL that failed to be fetched. | ||
* @return self | ||
*/ | ||
public static function withUrl($url) | ||
{ | ||
$message = "Failed to retrieve the cached response for the URL '{$url}'."; | ||
|
||
return new self($message); | ||
} | ||
} |
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -7,6 +7,8 @@ | |||||
|
||||||
namespace AmpProject\AmpWP\RemoteRequest; | ||||||
|
||||||
use AmpProject\Exception\FailedRemoteRequest; | ||||||
use AmpProject\Exception\FailedToGetCachedResponse; | ||||||
use AmpProject\Exception\FailedToGetFromRemoteUrl; | ||||||
use AmpProject\RemoteGetRequest; | ||||||
use AmpProject\RemoteRequest\RemoteGetRequestResponse; | ||||||
|
@@ -28,7 +30,7 @@ final class CachedRemoteGetRequest implements RemoteGetRequest { | |||||
* | ||||||
* @var string | ||||||
*/ | ||||||
const TRANSIENT_PREFIX = 'amp_remote_request_'; | ||||||
const TRANSIENT_PREFIX = 'amp_remote_request_v2_'; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the transient prefix to bust the cache. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might not be necessary if we check the type of the class per my comment below. |
||||||
|
||||||
/** | ||||||
* Cache control header directive name. | ||||||
|
@@ -101,42 +103,48 @@ public function __construct( | |||||
* | ||||||
* @param string $url URL to get. | ||||||
* @return Response Response for the executed request. | ||||||
* @throws FailedToGetFromRemoteUrl If retrieving the contents from the URL failed. | ||||||
* @throws FailedRemoteRequest If retrieving the contents from the URL failed. | ||||||
pierlon marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
*/ | ||||||
public function get( $url ) { | ||||||
$cache_key = self::TRANSIENT_PREFIX . md5( __CLASS__ . $url ); | ||||||
$cached_data = get_transient( $cache_key ); | ||||||
$headers = []; | ||||||
$status = null; | ||||||
$cache_key = self::TRANSIENT_PREFIX . md5( __CLASS__ . $url ); | ||||||
$cached_response = get_transient( $cache_key ); | ||||||
$headers = []; | ||||||
|
||||||
if ( false !== $cached_data ) { | ||||||
if ( false !== $cached_response ) { | ||||||
if ( PHP_MAJOR_VERSION >= 7 ) { | ||||||
$cached_data = unserialize( $cached_data, [ CachedData::class, DateTimeImmutable::class ] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize,PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound | ||||||
$cached_response = unserialize( $cached_response, [ CachedResponse::class, DateTimeImmutable::class ] ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize,PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound | ||||||
} else { | ||||||
// PHP 5.6 does not provide the second $options argument yet. | ||||||
$cached_data = unserialize( $cached_data ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize | ||||||
$cached_response = unserialize( $cached_response ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize | ||||||
} | ||||||
} | ||||||
|
||||||
if ( false === $cached_data || $cached_data->is_expired() ) { | ||||||
if ( false === $cached_response || $cached_response->is_expired() ) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
try { | ||||||
$response = $this->remote_request->get( $url ); | ||||||
$status = $response->getStatusCode(); | ||||||
$expiry = $this->get_expiry_time( $response ); | ||||||
$headers = $response->getHeaders(); | ||||||
$body = $response->getBody(); | ||||||
} catch ( FailedToGetFromRemoteUrl $exception ) { | ||||||
$status = $exception->getStatusCode(); | ||||||
$expiry = new DateTimeImmutable( "+ {$this->min_expiry} seconds" ); | ||||||
$body = $exception->getMessage(); | ||||||
$status = $exception->getStatusCode(); | ||||||
$expiry = new DateTimeImmutable( "+ {$this->min_expiry} seconds" ); | ||||||
$body = $exception->getMessage(); | ||||||
$response = new RemoteGetRequestResponse( $body, $headers, $status ); | ||||||
} | ||||||
|
||||||
$cached_data = new CachedData( $body, $expiry ); | ||||||
$cached_response = new CachedResponse( $body, $headers, $status, $expiry ); | ||||||
|
||||||
set_transient( $cache_key, serialize( $cached_data ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize | ||||||
set_transient( $cache_key, serialize( $cached_response ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize | ||||||
|
||||||
return $response; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this
Suggested change
Would removing it make the logic more consistent between cached and non-cached code paths? |
||||||
} | ||||||
|
||||||
if ( ! $cached_response->is_valid() ) { | ||||||
throw new FailedToGetCachedResponse( $url ); | ||||||
} | ||||||
|
||||||
return new RemoteGetRequestResponse( $cached_data->get_value(), $headers, $status ); | ||||||
return new RemoteGetRequestResponse( $cached_response->get_body(), $cached_response->get_headers(), $cached_response->get_status_code() ); | ||||||
} | ||||||
|
||||||
/** | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
phpstan complains about
FailedRemoteRequest
not being a subtype ofThrowable
, butThrowable
is not available in PHP 5.6 so I'm ignoring it for now.