diff --git a/includes/sanitizers/class-amp-style-sanitizer.php b/includes/sanitizers/class-amp-style-sanitizer.php index 88d150f4acb..3c98bf5cfec 100644 --- a/includes/sanitizers/class-amp-style-sanitizer.php +++ b/includes/sanitizers/class-amp-style-sanitizer.php @@ -590,6 +590,18 @@ private function process_link_element( DOMElement $element ) { if ( $href !== $normalized_url ) { $element->setAttribute( 'href', $normalized_url ); } + + /* + * Opt-in to CORS Mode for the stylesheet. This ensures that a service worker caching the external + * stylesheet will not inflate the storage quota. + * + * See: + * - https://developers.google.com/web/tools/workbox/guides/storage-quota#beware_of_opaque_responses + * - https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests#cross-origin_requests_and_opaque_responses + */ + if ( ! $element->hasAttribute( 'crossorigin' ) ) { + $element->setAttribute( 'crossorigin', 'anonymous' ); + } return; } diff --git a/tests/test-amp-style-sanitizer.php b/tests/test-amp-style-sanitizer.php index 38ac4a791e7..4cf440278e3 100644 --- a/tests/test-amp-style-sanitizer.php +++ b/tests/test-amp-style-sanitizer.php @@ -1186,11 +1186,36 @@ public function test_font_urls( $url, $error_codes ) { preg_replace( '#^(http:)?(?=//)#', 'https:', $url ), $link->getAttribute( 'href' ) ); + $this->assertEquals( 'anonymous', $link->getAttribute( 'crossorigin' ) ); } else { $this->assertEmpty( $link ); } } + /** + * Test addition of crossorigin attribute to external stylesheet links. + * + * @covers AMP_Style_Sanitizer::process_link_element() + */ + public function test_cors_enabled_stylesheet_url() { + + // Test supplying crossorigin attribute. + $document = AMP_DOM_Utils::get_dom( '
' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet + $sanitizer = new AMP_Style_Sanitizer( $document, array( 'use_document_element' => true ) ); + $sanitizer->sanitize(); + $link = $document->getElementsByTagName( 'link' )->item( 0 ); + $this->assertInstanceOf( 'DOMElement', $link ); + $this->assertEquals( 'anonymous', $link->getAttribute( 'crossorigin' ) ); + + // Test that existing crossorigin attribute is not overridden. + $document = AMP_DOM_Utils::get_dom( '' ); // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedStylesheet + $sanitizer = new AMP_Style_Sanitizer( $document, array( 'use_document_element' => true ) ); + $sanitizer->sanitize(); + $link = $document->getElementsByTagName( 'link' )->item( 0 ); + $this->assertInstanceOf( 'DOMElement', $link ); + $this->assertEquals( 'use-credentials', $link->getAttribute( 'crossorigin' ) ); + } + /** * Test CSS imports. *