# xspeed/1.0.1/includes/class-cdn-rewriter.php

xSpeed Cache: AI-Powered Performance Hub with MCP, Caching &amp; CDN, version 1.0.1. 238 lines.

- Page: https://pluginprobe.com/plugins/xspeed/1.0.1/code/includes/class-cdn-rewriter.php
- Raw: https://pluginprobe.com/plugins/xspeed/1.0.1/raw/includes/class-cdn-rewriter.php
- Modified: 2026-06-01T17:33:22+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/xspeed/1.0.1/code/includes/class-cdn-rewriter.php#L10-L20`.

```php
<?php
/**
 * Cdn_Rewriter — rewrites local-origin asset URLs to a user-supplied
 * CDN hostname (BunnyCDN, KeyCDN, Cloudflare R2 pull-zone, etc.).
 *
 * Assumes pull-zone CDN (CDN fetches from origin on demand); we never
 * upload anything. The user sets `cdn_url` to e.g. `cdn.example.com`
 * and we rewrite asset URLs from `https://example.com/wp-content/…`
 * to `https://cdn.example.com/wp-content/…`.
 *
 * Strategy: same buffer-pass approach as Lazy_Loader — regex over
 * specific tag attributes is ~10× faster than a full DOMDocument round
 * trip, and CDN rewriting is purely a string substitution on URLs that
 * point at the site origin. Out-of-origin URLs are left alone.
 *
 * Handled attributes: src, href, srcset, data-src, data-srcset, poster.
 * Honors extension whitelist + glob exclude patterns (reuses
 * Glob_Matcher so `*.pdf` / `/cart/*` work the same as elsewhere).
 *
 * @package XSpeed
 */

declare(strict_types=1);

namespace XSpeed;

defined( 'ABSPATH' ) || exit;

final class Cdn_Rewriter {

	/** @var array|null */
	private static $opts = null;
	/** @var string|null */
	private static $home_host = null;
	/** @var string */
	private static $home_scheme = 'https';

	public const DEFAULT_EXTENSIONS = array(
		'jpg', 'jpeg', 'png', 'gif', 'webp', 'avif', 'svg', 'ico',
		'woff', 'woff2', 'ttf', 'otf', 'eot',
		'css', 'js',
		'mp4', 'webm', 'mp3', 'ogg',
	);

	public static function reset_state(): void {
		self::$opts        = null;
		self::$home_host   = null;
		self::$home_scheme = 'https';
	}

	/**
	 * Top-level HTML transform. Returns input unchanged if disabled or
	 * cdn_url is empty.
	 */
	public static function process_html( string $html ): string {
		if ( '' === $html ) {
			return $html;
		}
		$opts = self::opts();
		if ( empty( $opts['enabled'] ) || empty( $opts['cdn_url'] ) ) {
			return $html;
		}
		self::prime_origin();

		// Rewrite src, href, poster, data-src.
		$html = preg_replace_callback(
			'#\b(src|href|poster|data-src)\s*=\s*([\'"])([^\'"]+)\2#i',
			static function ( $m ) use ( $opts ) {
				$rewritten = self::rewrite_url( $m[3], $opts );
				return $m[1] . '=' . $m[2] . $rewritten . $m[2];
			},
			$html
		);

		// Rewrite srcset / data-srcset (comma-separated `url 1x, url 2x`).
		$html = preg_replace_callback(
			'#\b(srcset|data-srcset)\s*=\s*([\'"])([^\'"]+)\2#i',
			static function ( $m ) use ( $opts ) {
				$rewritten = self::rewrite_srcset( $m[3], $opts );
				return $m[1] . '=' . $m[2] . $rewritten . $m[2];
			},
			$html
		);

		return $html;
	}

	/**
	 * Public for tests + REST validation. Returns the rewritten URL or
	 * the input unchanged.
	 */
	public static function rewrite_url( string $url, array $opts ): string {
		$url = trim( $url );
		if ( '' === $url ) {
			return $url;
		}
		if ( null === self::$home_host ) {
			self::prime_origin();
		}
		// Skip data:, mailto:, tel:, javascript:, fragments, blob:.
		if ( preg_match( '#^(data|mailto|tel|javascript|blob|about):#i', $url ) ) {
			return $url;
		}
		if ( '#' === substr( $url, 0, 1 ) ) {
			return $url;
		}

		$abs = self::absolutize( $url );
		if ( null === $abs ) {
			return $url;
		}

		// Must be same origin.
		$parts = wp_parse_url( $abs );
		if ( ! is_array( $parts ) || empty( $parts['host'] ) ) {
			return $url;
		}
		if ( strtolower( $parts['host'] ) !== self::$home_host ) {
			return $url;
		}

		$path = (string) ( $parts['path'] ?? '' );
		if ( '' === $path ) {
			return $url;
		}

		// Extension whitelist.
		$included = isset( $opts['included_extensions'] ) && is_array( $opts['included_extensions'] )
			? $opts['included_extensions']
			: self::DEFAULT_EXTENSIONS;
		$ext = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
		if ( '' === $ext || ! in_array( $ext, array_map( 'strtolower', $included ), true ) ) {
			return $url;
		}

		// Excluded path globs (reuse Glob_Matcher for *.pdf, /cart/*).
		$excluded = isset( $opts['excluded_patterns'] ) && is_array( $opts['excluded_patterns'] )
			? $opts['excluded_patterns']
			: array();
		foreach ( $excluded as $pattern ) {
			if ( '' === $pattern ) {
				continue;
			}
			if ( class_exists( '\\XSpeed\\Glob_Matcher' ) && Glob_Matcher::matches( $pattern, $path ) ) {
				return $url;
			}
		}

		$cdn_host = self::normalize_host( (string) $opts['cdn_url'] );
		if ( '' === $cdn_host ) {
			return $url;
		}

		$query    = isset( $parts['query'] ) ? '?' . $parts['query'] : '';
		$fragment = isset( $parts['fragment'] ) ? '#' . $parts['fragment'] : '';

		return self::$home_scheme . '://' . $cdn_host . $path . $query . $fragment;
	}

	/**
	 * Rewrite each candidate URL inside an srcset descriptor list.
	 */
	public static function rewrite_srcset( string $srcset, array $opts ): string {
		$parts = preg_split( '#\s*,\s*#', trim( $srcset ) );
		if ( ! is_array( $parts ) ) {
			return $srcset;
		}
		$out = array();
		foreach ( $parts as $candidate ) {
			$candidate = trim( $candidate );
			if ( '' === $candidate ) {
				continue;
			}
			// `<url> <descriptor>` — descriptor optional (1x, 2x, 800w).
			$split    = preg_split( '#\s+#', $candidate, 2 );
			$url      = $split[0];
			$descr    = isset( $split[1] ) ? ' ' . $split[1] : '';
			$rewritten = self::rewrite_url( $url, $opts );
			$out[]     = $rewritten . $descr;
		}
		return implode( ', ', $out );
	}

	/**
	 * Convert relative/scheme-relative URLs to absolute against the site
	 * origin. Returns null if we can't make sense of it.
	 */
	private static function absolutize( string $url ): ?string {
		if ( preg_match( '#^https?://#i', $url ) ) {
			return $url;
		}
		if ( 0 === strpos( $url, '//' ) ) {
			return self::$home_scheme . ':' . $url;
		}
		if ( 0 === strpos( $url, '/' ) ) {
			return self::$home_scheme . '://' . self::$home_host . $url;
		}
		// Bare relative paths like `images/x.png` — these would need a
		// base URL to resolve. The DOM rendering picked one already; we
		// can't reliably guess. Leave alone.
		return null;
	}

	/**
	 * Strip scheme + trailing slash from a user-entered CDN URL so the
	 * stored value is just a host (cdn.example.com). Tolerant of
	 * `https://cdn.example.com/`, `//cdn.example.com`, or bare host.
	 */
	public static function normalize_host( string $value ): string {
		$value = trim( $value );
		if ( '' === $value ) {
			return '';
		}
		$value = preg_replace( '#^https?://#i', '', $value );
		$value = preg_replace( '#^//#', '', $value );
		$value = rtrim( $value, '/' );
		return strtolower( $value );
	}

	private static function prime_origin(): void {
		$home = function_exists( 'home_url' ) ? home_url() : '';
		$p    = wp_parse_url( $home );
		if ( is_array( $p ) && ! empty( $p['host'] ) ) {
			self::$home_host   = strtolower( $p['host'] );
			self::$home_scheme = isset( $p['scheme'] ) ? strtolower( $p['scheme'] ) : 'https';
		}
	}

	private static function opts(): array {
		if ( null === self::$opts ) {
			self::$opts = function_exists( 'get_option' )
				? (array) get_option( 'xspeed_module_cdn', array() )
				: array();
		}
		return self::$opts;
	}
}

```
