PluginProbe
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant / 2.0.4
EasyFonts – Host Google Fonts Locally, Fast & Auto-Optimize, GDPR Compliant v2.0.4
2.0.4 2.0.3 2.0.2 2.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2 1.3 2.0.0
← All changes | src/Fonts/Downloader.php +27 -1 2.0.2 → 2.0.4 View file →
@@ -47,8 +47,13 @@
47 47 */
48 48 const UA_WOFF2 = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0';
49 49
50 50 /**
51 + * Transient value marking a recently-failed CSS fetch (negative cache).
52 + */
53 + const FAIL_MARKER = '__easyfonts_fetch_failed__';
54 +
55 + /**
51 56 * Old UA that makes the API return TTF (used for metric extraction only).
52 57 */
53 58 const UA_TTF = 'Mozilla/5.0 (Windows NT 6.1; rv:27.0) Gecko/20100101 Firefox/27.0';
54 59
@@ -155,14 +160,28 @@
155 160 // (which bumps the buster) transparently refreshes it.
156 161 $cache_key = 'easyfonts_css_' . md5( $url . '|' . \EasyFonts\Settings::buster() );
157 162 $cached = get_transient( $cache_key );
158 163
164 + // Negative cache: a recently-failed fetch is not retried on every render,
165 + // so a dead/blocked CSS host can never add its full timeout to each view.
166 + if ( self::FAIL_MARKER === $cached ) {
167 + return null;
168 + }
169 +
159 170 if ( is_string( $cached ) && '' !== $cached ) {
160 171 return $cached;
161 172 }
162 173
174 + /**
175 + * How long a failed stylesheet fetch is remembered before retrying.
176 + *
177 + * @param int $ttl Seconds.
178 + */
179 + $fail_ttl = (int) apply_filters( 'easyfonts_css_fail_ttl', HOUR_IN_SECONDS );
180 +
163 181 // SSRF guard: never fetch a stylesheet from an internal/private address.
164 182 if ( ! self::is_public_url( $url ) ) {
183 + set_transient( $cache_key, self::FAIL_MARKER, $fail_ttl );
165 184 return null;
166 185 }
167 186
168 187 $response = wp_remote_get(
@@ -167,14 +186,20 @@
167 186
168 187 $response = wp_remote_get(
169 188 $url,
170 189 array(
171 - 'timeout' => 10,
190 + /**
191 + * Timeout for stylesheet fetches (seconds).
192 + *
193 + * @param int $timeout
194 + */
195 + 'timeout' => (int) apply_filters( 'easyfonts_css_timeout', 10 ),
172 196 'user-agent' => apply_filters( 'easyfonts_css_user_agent', self::UA_WOFF2 ),
173 197 )
174 198 );
175 199
176 200 if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
201 + set_transient( $cache_key, self::FAIL_MARKER, $fail_ttl );
177 202 return null;
178 203 }
179 204
180 205 $body = wp_remote_retrieve_body( $response );
@@ -179,8 +204,9 @@
179 204
180 205 $body = wp_remote_retrieve_body( $response );
181 206
182 207 if ( '' === $body ) {
208 + set_transient( $cache_key, self::FAIL_MARKER, $fail_ttl );
183 209 return null;
184 210 }
185 211
186 212 set_transient( $cache_key, $body, 7 * DAY_IN_SECONDS );