@@ -204,16 +204,25 @@ function rewriteLinkHref(
204204 * `document.write` / `document.writeln`.
205205 *
206206 * Uses `DOMParser` for robust HTML parsing instead of regex so that
207- * edge-cases (unquoted attributes, unusual spacing, mixed quote styles)
208- * are handled by the browser's native parser. The raw `getAttribute`
209- * value is swapped in the original HTML string so the surrounding markup
210- * is preserved verbatim .
207+ * edge-cases (unquoted attributes, unusual spacing, mixed quote styles,
208+ * HTML-entity-encoded query parameters) are handled by the browser's
209+ * native parser. GPT script `src` attributes are mutated in the parsed
210+ * DOM and the result is serialized back to HTML .
211211 *
212212 * If the GPT domain is present in the HTML but `DOMParser` is
213213 * unavailable or throws, the function **fails closed** (returns an
214214 * empty string) rather than passing the unproxied URL through.
215+ *
216+ * Non-GPT HTML is always passed through unchanged regardless of
217+ * `DOMParser` availability.
215218 */
216219function rewriteHtmlString ( html : string ) : string {
220+ // Fast-path: if the HTML does not reference the GPT domain at all,
221+ // pass it through unchanged. This avoids unnecessary DOMParser
222+ // overhead and, critically, prevents non-GPT document.write calls
223+ // from being silently dropped when DOMParser is unavailable.
224+ if ( ! html . includes ( GPT_DOMAIN ) ) return html ;
225+
217226 if ( typeof DOMParser === 'undefined' ) {
218227 log . warn (
219228 `${ LOG_PREFIX } : DOMParser unavailable, blocking document.write HTML that references GPT domain`
@@ -224,7 +233,7 @@ function rewriteHtmlString(html: string): string {
224233 try {
225234 const doc = new DOMParser ( ) . parseFromString ( html , 'text/html' ) ;
226235 const scripts = doc . querySelectorAll ( 'script[src]' ) ;
227- let result = html ;
236+ let didRewriteAny = false ;
228237
229238 for ( const script of scripts ) {
230239 const rawSrc = script . getAttribute ( 'src' ) ?? '' ;
@@ -235,10 +244,17 @@ function rewriteHtmlString(html: string): string {
235244 original : rawSrc ,
236245 rewritten : rewrittenUrl ,
237246 } ) ;
238- result = result . replaceAll ( rawSrc , rewrittenUrl ) ;
247+ // Mutate the parsed DOM so that HTML-entity-encoded attribute
248+ // values (e.g. `&`) are handled correctly. Serializing the
249+ // DOM back to HTML avoids the mismatch between decoded
250+ // `getAttribute()` values and the raw HTML string.
251+ script . setAttribute ( 'src' , rewrittenUrl ) ;
252+ didRewriteAny = true ;
239253 }
240254
241- return result ;
255+ // DOMParser wraps input in <html><head>…</head><body>…</body></html>.
256+ // Bare <script> tags land in <head>, so we serialize from both.
257+ return didRewriteAny ? ( doc . head ?. innerHTML ?? '' ) + ( doc . body ?. innerHTML ?? '' ) : html ;
242258 } catch ( err ) {
243259 log . warn (
244260 `${ LOG_PREFIX } : failed to parse document.write HTML containing GPT domain, blocking` ,
0 commit comments