Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 46 additions & 20 deletions src/wp-admin/includes/class-wp-site-health.php
Original file line number Diff line number Diff line change
Expand Up @@ -3378,22 +3378,20 @@ public function is_development_environment() {
}

/**
* Returns a list of headers and its verification callback to verify if page cache is enabled or not.
*
* Note: key is header name and value could be callable function to verify header value.
* Empty value mean existence of header detect page cache is enabled.
* Returns a mapping to response headers to an optional callback to verify if page cache is enabled or not.
*
* @since 6.1.0
*
* @return array List of client caching headers and their (optional) verification callbacks.
* @return array<string, ?callable> Mapping of page caching headers and their (optional) verification callbacks.
*/
public function get_page_cache_headers() {
public function get_page_cache_headers(): array {

$cache_hit_callback = static function ( $header_value ) {
return str_contains( strtolower( $header_value ), 'hit' );
return (bool) preg_match( '/\bhit\b/i', $header_value );
};

$cache_headers = array(
// Standard HTTP caching headers.
'cache-control' => static function ( $header_value ) {
return (bool) preg_match( '/max-age=[1-9]/', $header_value );
},
Expand All @@ -3403,36 +3401,64 @@ public function get_page_cache_headers() {
'age' => static function ( $header_value ) {
return is_numeric( $header_value ) && $header_value > 0;
},
'last-modified' => '',
'etag' => '',
'last-modified' => null,
'etag' => null,

// Custom caching headers.
'x-cache-enabled' => static function ( $header_value ) {
return 'true' === strtolower( $header_value );
},
'x-cache-disabled' => static function ( $header_value ) {
return ( 'on' !== strtolower( $header_value ) );
},
'x-srcache-store-status' => $cache_hit_callback,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was incorrect. Now fixed.


/**
* OpenResty srcache-nginx-module.
*
* The `x-srcache-store-status` header indicates if the response was stored in the cache.
* Valid values include `STORE` and `BYPASS`.
*
* The `x-srcache-fetch-status` header indicates if the response was fetched from the cache.
* Valid values include `HIT`, `MISS`, and `BYPASS`.
*
* @link https://github.com/openresty/srcache-nginx-module
*/
'x-srcache-store-status' => static function ( $header_value ) {
return 'store' === strtolower( $header_value );
},
'x-srcache-fetch-status' => $cache_hit_callback,

// Generic caching proxies (Nginx, Varnish, etc.)
'x-cache' => $cache_hit_callback,
'x-cache-status' => $cache_hit_callback,
'x-litespeed-cache' => $cache_hit_callback,
'x-proxy-cache' => $cache_hit_callback,
'via' => '',
// Generic caching proxies (Nginx, Varnish, Squid, Go, Fastly, LiteSpeed, etc.).
'x-cache' => $cache_hit_callback,
'x-cache-status' => $cache_hit_callback,
'x-litespeed-cache' => $cache_hit_callback,
'x-proxy-cache' => $cache_hit_callback,

/**
* Varnish Cache.
*
* For a cache hit, it includes both the ID of the current request and the ID of the request
* that populated the cache. For a miss, it only includes the current request ID.
*
* @link https://vinyl-cache.org/docs/2.1/faq/http.html
*/
'x-varnish' => static function ( $header_value ) {
return (bool) preg_match( '/\d+ \d+/', $header_value );
},
'via' => null,

// Cloudflare
'cf-cache-status' => $cache_hit_callback,
// Cloudflare.
'cf-cache-status' => $cache_hit_callback,
);

/**
* Filters the list of cache headers supported by core.
*
* @since 6.1.0
*
* @param array $cache_headers Array of supported cache headers.
* @param array<string, ?callable> $cache_headers Mapping of page caching headers and their (optional) verification callbacks.
*/
return apply_filters( 'site_status_page_cache_supported_cache_headers', $cache_headers );
return (array) apply_filters( 'site_status_page_cache_supported_cache_headers', $cache_headers );
}

/**
Expand Down
102 changes: 89 additions & 13 deletions tests/phpunit/tests/admin/wpSiteHealth.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,8 @@ class Tests_Admin_wpSiteHealth extends WP_UnitTestCase {
* An instance of the class to test.
*
* @since 6.1.0
*
* @var WP_Site_Health
*/
private $instance;
private WP_Site_Health $instance;

public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
// Include the `WP_Site_Health` file.
Expand Down Expand Up @@ -172,7 +170,7 @@ public function data_cron_health_checks() {
* @covers ::get_page_cache_headers()
* @covers ::check_for_page_caching()
*/
public function test_get_page_cache( $responses, $expected_status, $expected_label, $good_basic_auth = null, $delay_the_response = false ) {
public function test_get_page_cache( array $responses, string $expected_status, string $expected_label, bool $good_basic_auth = false, bool $delay_the_response = false ) {
$expected_props = array(
'badge' => array(
'label' => __( 'Performance' ),
Expand All @@ -183,7 +181,7 @@ public function test_get_page_cache( $responses, $expected_status, $expected_lab
'label' => $expected_label,
);

if ( null !== $good_basic_auth ) {
if ( $good_basic_auth ) {
$_SERVER['PHP_AUTH_USER'] = 'admin';
$_SERVER['PHP_AUTH_PW'] = 'password';
}
Expand Down Expand Up @@ -219,7 +217,7 @@ function ( $response, $parsed_args ) use ( &$responses, &$is_unauthorized, $good
);
}

if ( null !== $good_basic_auth ) {
if ( $good_basic_auth ) {
$this->assertArrayHasKey(
'Authorization',
$parsed_args['headers']
Expand Down Expand Up @@ -263,9 +261,15 @@ function ( $response, $parsed_args ) use ( &$responses, &$is_unauthorized, $good
*
* @ticket 56041
*
* @return array[]
* @return array<string, array{
* responses: array<int, string|array<string, string|string[]>>,
* expected_status: 'recommended'|'critical'|'good',
* expected_label: string,
* good_basic_auth?: bool,
* delay_the_response?: bool,
* }>
*/
public function data_get_page_cache() {
public function data_get_page_cache(): array {
$recommended_label = 'Page cache is not detected but the server response time is OK';
$good_label = 'Page cache is detected and the server response time is good';
$critical_label = 'Page cache is not detected and the server response time is slow';
Expand All @@ -278,13 +282,13 @@ public function data_get_page_cache() {
),
'expected_status' => 'recommended',
'expected_label' => $error_label,
'good_basic_auth' => false,
'good_basic_auth' => true,
),
'no-cache-control' => array(
'responses' => array_fill( 0, 3, array() ),
'expected_status' => 'critical',
'expected_label' => $critical_label,
'good_basic_auth' => null,
'good_basic_auth' => false,
'delay_the_response' => true,
),
'no-cache' => array(
Expand All @@ -310,7 +314,7 @@ public function data_get_page_cache() {
'responses' => array_fill( 0, 3, array( 'cache-control' => 'no-cache' ) ),
'expected_status' => 'critical',
'expected_label' => $critical_label,
'good_basic_auth' => null,
'good_basic_auth' => false,
'delay_the_response' => true,
),
'age' => array(
Expand Down Expand Up @@ -366,7 +370,7 @@ public function data_get_page_cache() {
),
'expected_status' => 'critical',
'expected_label' => $critical_label,
'good_basic_auth' => null,
'good_basic_auth' => false,
'delay_the_response' => true,
),
'cache-control-with-basic-auth' => array(
Expand Down Expand Up @@ -396,7 +400,7 @@ public function data_get_page_cache() {
),
'expected_status' => 'critical',
'expected_label' => $critical_label,
'good_basic_auth' => null,
'good_basic_auth' => false,
'delay_the_response' => true,
),
'x-cache-disabled' => array(
Expand All @@ -408,6 +412,78 @@ public function data_get_page_cache() {
'expected_status' => 'good',
'expected_label' => $good_label,
),
'false-positive-hit-in-word' => array(
'responses' => array_fill(
0,
3,
array( 'x-cache' => 'shit' )
),
'expected_status' => 'recommended',
'expected_label' => $recommended_label,
),
'varnish-header' => array(
'responses' => array_fill(
0,
3,
array( 'x-varnish' => '123 456' )
),
'expected_status' => 'good',
'expected_label' => $good_label,
),
'varnish-header-miss' => array(
'responses' => array_fill(
0,
3,
array( 'x-varnish' => '123' )
),
'expected_status' => 'recommended',
'expected_label' => $recommended_label,
),
'srcache-store-status' => array(
'responses' => array_fill(
0,
3,
array( 'x-srcache-store-status' => 'STORE' )
),
'expected_status' => 'good',
'expected_label' => $good_label,
),
'srcache-store-status-bypass' => array(
'responses' => array_fill(
0,
3,
array( 'x-srcache-store-status' => 'BYPASS' )
),
'expected_status' => 'recommended',
'expected_label' => $recommended_label,
),
'srcache-fetch-status' => array(
'responses' => array_fill(
0,
3,
array( 'x-srcache-fetch-status' => 'HIT' )
),
'expected_status' => 'good',
'expected_label' => $good_label,
),
'last-modified' => array(
'responses' => array_fill(
0,
3,
array( 'last-modified' => 'Wed, 21 Oct 2015 07:28:00 GMT' )
),
'expected_status' => 'good',
'expected_label' => $good_label,
),
'via' => array(
'responses' => array_fill(
0,
3,
array( 'via' => '1.1 varnish' )
),
'expected_status' => 'good',
'expected_label' => $good_label,
),
);
}

Expand Down
Loading