From 5c44cd6effdb2ef2e15a7ec7de40be009778b34c Mon Sep 17 00:00:00 2001 From: ldm0 Date: Thu, 8 Oct 2026 22:03:00 +0800 Subject: [PATCH] refactor(encoding): rename shared document streaming decoder --- moli-encoding/src/document.rs | 10 ++- moli-encoding/src/lib.rs | 2 +- moli-encoding/src/tests.rs | 65 +++++++++---------- .../src/document_response_decoder.rs | 12 ++-- .../src/runtime/phase_one/streaming.rs | 28 ++++---- .../runtime/phase_one/streaming_residence.rs | 6 +- 6 files changed, 63 insertions(+), 60 deletions(-) diff --git a/moli-encoding/src/document.rs b/moli-encoding/src/document.rs index 188351fc6d..a959a7cf30 100644 --- a/moli-encoding/src/document.rs +++ b/moli-encoding/src/document.rs @@ -22,7 +22,7 @@ pub fn decode_html_document_with_fallback( headers: &[(String, Vec)], fallback_encoding: Option<&str>, ) -> (String, &'static str) { - let mut decoder = HtmlDocumentStreamingDecoder::new_with_fallback(headers, fallback_encoding); + let mut decoder = DocumentStreamingDecoder::new_with_fallback(headers, fallback_encoding); let mut output = String::new(); for chunk in decoder.push(bytes) { output.push_str(&chunk); @@ -43,7 +43,11 @@ enum DocumentDeclarationPolicy { Text, } -pub struct HtmlDocumentStreamingDecoder { +/// Streaming decoder for HTML, XML, and text document responses. +/// +/// [`Self::new`] uses HTML declaration rules. XML and text responses use +/// [`Self::new_xml_document`] and [`Self::new_text_document`] respectively. +pub struct DocumentStreamingDecoder { transport_encoding: Option<&'static Encoding>, fallback_encoding: &'static Encoding, sniff_buffer: Vec, @@ -57,7 +61,7 @@ pub struct HtmlDocumentStreamingDecoder { declaration_policy: DocumentDeclarationPolicy, } -impl HtmlDocumentStreamingDecoder { +impl DocumentStreamingDecoder { /// Decode a text document without interpreting literal HTML/XML declarations. /// BOMs and transport charsets take precedence. JSON then defaults to UTF-8; /// other text uses a valid inherited encoding before heuristic detection. diff --git a/moli-encoding/src/lib.rs b/moli-encoding/src/lib.rs index 8583883848..d8ff46f621 100644 --- a/moli-encoding/src/lib.rs +++ b/moli-encoding/src/lib.rs @@ -9,7 +9,7 @@ mod query; mod script; pub use document::{ - HtmlDocumentStreamingDecoder, LegacyEncodingDetector, decode_html_document, + DocumentStreamingDecoder, LegacyEncodingDetector, decode_html_document, decode_html_document_with_fallback, }; pub use form::{ diff --git a/moli-encoding/src/tests.rs b/moli-encoding/src/tests.rs index d2621452e3..4e9f503986 100644 --- a/moli-encoding/src/tests.rs +++ b/moli-encoding/src/tests.rs @@ -49,14 +49,14 @@ fn assert_xml_document_decodes_across_chunk_splits( encoding: &str, ) { for split in 0..=bytes.len() { - let mut decoder = HtmlDocumentStreamingDecoder::new_xml_document(headers); + let mut decoder = DocumentStreamingDecoder::new_xml_document(headers); let mut decoded = decoder.push(&bytes[..split]).concat(); decoded.push_str(&decoder.push(&bytes[split..]).concat()); decoded.push_str(&decoder.finish().unwrap_or_default()); assert_eq!(decoded, source, "{encoding}: split {split}"); assert_eq!(decoder.document_encoding_name(), encoding, "split {split}"); } - let mut decoder = HtmlDocumentStreamingDecoder::new_xml_document(headers); + let mut decoder = DocumentStreamingDecoder::new_xml_document(headers); let mut decoded = String::new(); for byte in bytes { decoded.push_str(&decoder.push(std::slice::from_ref(byte)).concat()); @@ -107,7 +107,7 @@ fn xml_document_ignores_encoding_attributes_in_processing_instructions() { #[test] fn xml_document_selects_encoding_at_the_end_of_its_declaration() { - let mut decoder = HtmlDocumentStreamingDecoder::new_xml_document(&[]); + let mut decoder = DocumentStreamingDecoder::new_xml_document(&[]); let mut decoded = decoder .push(b"foo"; for (mut decoder, expected_encoding) in [ - (HtmlDocumentStreamingDecoder::new(&[]), "UTF-8"), - (HtmlDocumentStreamingDecoder::new_xml_document(&[]), "UTF-8"), + (DocumentStreamingDecoder::new(&[]), "UTF-8"), + (DocumentStreamingDecoder::new_xml_document(&[]), "UTF-8"), ( - HtmlDocumentStreamingDecoder::new_text_document( + DocumentStreamingDecoder::new_text_document( &[], "https://example.test/", test_legacy_encoding_detector, @@ -172,7 +172,7 @@ fn chromium_plain_text_broken_boms_are_flushed_with_the_default_encoding() { (b"\xff", "ÿ"), (b"\xfe", "þ"), ] { - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://example.test/", test_legacy_encoding_detector, @@ -209,7 +209,7 @@ fn chromium_bom_in_content_is_preserved_by_xml_decoding() { fn json_text_document_defaults_to_utf8_across_every_chunk_split() { let input = "{\"name\":\"Gülçek\"}"; for split in 0..=input.len() { - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://example.test/", unexpected_legacy_encoding_detector, @@ -230,7 +230,7 @@ fn plain_text_document_honors_transport_charset() { "Content-Type".to_owned(), b"text/plain; charset=gbk".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &headers, "https://example.test/", unexpected_legacy_encoding_detector, @@ -249,7 +249,7 @@ fn text_document_bom_precedes_transport_charset() { "Content-Type".to_owned(), b"text/plain; charset=gbk".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &headers, "https://example.test/", unexpected_legacy_encoding_detector, @@ -271,7 +271,7 @@ fn text_document_bom_precedes_transport_charset() { #[test] fn plain_text_document_retains_legacy_detection_without_a_charset() { - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://legacy.example/", test_legacy_encoding_detector, @@ -293,7 +293,7 @@ fn plain_text_document_inherits_encoding_before_detection_across_chunk_splits() ] { let bytes = encoding.encode(input).0; for split in 0..=bytes.len() { - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://example.test/", unexpected_legacy_encoding_detector, @@ -312,7 +312,7 @@ fn plain_text_document_inherits_encoding_before_detection_across_chunk_splits() #[test] fn invalid_inherited_text_encoding_does_not_disable_detection() { - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://legacy.example/", test_legacy_encoding_detector, @@ -333,7 +333,7 @@ fn plain_text_document_ignores_literal_encoding_declarations() { ] { let mut input = prefix.as_bytes().to_vec(); input.push(0xe9); - let mut decoder = HtmlDocumentStreamingDecoder::new_text_document( + let mut decoder = DocumentStreamingDecoder::new_text_document( &[], "https://example.test/", test_legacy_encoding_detector, @@ -353,7 +353,7 @@ fn content_type_charset_is_selected() { "Content-Type".to_owned(), b"text/html; charset=gbk".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!(decoder.push(&gbk_bytes("太平洋")), vec!["太平洋"]); assert_eq!(decoder.selected_encoding_name(), Some("GBK")); @@ -364,7 +364,7 @@ fn meta_charset_is_selected_without_header_charset() { let headers: Vec<(String, Vec)> = vec![("Content-Type".to_owned(), b"text/html".to_vec())]; let mut input = b"

".to_vec(); input.extend_from_slice(&gbk_bytes("家居")); - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!( decoder.push(&input), @@ -376,7 +376,7 @@ fn meta_charset_is_selected_without_header_charset() { #[test] fn meta_charset_can_be_split_across_chunks() { let headers: Vec<(String, Vec)> = vec![("Content-Type".to_owned(), b"text/html".to_vec())]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!( decoder.push(b")> = vec![("Content-Type".to_owned(), b"text/html".to_vec())]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!( decoder.push(b""), @@ -406,7 +406,7 @@ fn ascii_prefix_streams_while_charset_sniffing_continues() { #[test] fn later_meta_charset_decodes_unemitted_non_ascii_after_ascii_prefix() { let headers: Vec<(String, Vec)> = vec![("Content-Type".to_owned(), b"text/html".to_vec())]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); let mut tail = b"

".to_vec(); tail.extend_from_slice(&gbk_bytes("家居")); @@ -421,7 +421,7 @@ fn meta_charset_after_1024_bytes_still_in_head_is_selected() { let mut input = vec![b' '; HTML_META_CHARSET_PRESCAN_LIMIT]; input.extend_from_slice(b"

"); input.extend_from_slice(&gbk_bytes("家居")); - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); let decoded = decoder.push(&input).join(""); @@ -437,7 +437,7 @@ fn meta_charset_crossing_1024_byte_boundary_is_selected_while_in_head() { input.extend_from_slice(partial_meta); input.extend_from_slice(b"set=\"gbk\">

"); input.extend_from_slice(&gbk_bytes("家居")); - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); let decoded = decoder.push(&input).join(""); @@ -452,7 +452,7 @@ fn meta_charset_after_1024_bytes_after_head_is_ignored() { input.extend(vec![b' '; HTML_META_CHARSET_PRESCAN_LIMIT - input.len()]); input.extend_from_slice(b"

"); input.extend_from_slice(&gbk_bytes("家居")); - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); let decoded = decoder.push(&input).join(""); @@ -470,8 +470,7 @@ fn meta_charset_starting_before_1024_bytes_after_head_is_selected() { ]); input.extend_from_slice(b"

"); input.extend_from_slice(&gbk_bytes("家居")); - let mut decoder = - HtmlDocumentStreamingDecoder::new_with_fallback(&headers, Some("windows-1252")); + let mut decoder = DocumentStreamingDecoder::new_with_fallback(&headers, Some("windows-1252")); let decoded = decoder.push(&input).join(""); @@ -523,7 +522,7 @@ fn gbk_multibyte_can_be_split_across_chunks() { "Content-Type".to_owned(), b"text/html; charset=gbk".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert!(decoder.push(&[0xCC]).is_empty()); assert_eq!(decoder.push(&[0xAB]), vec!["太"]); @@ -535,7 +534,7 @@ fn bom_wins_over_header_charset() { "Content-Type".to_owned(), b"text/html; charset=gbk".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!(decoder.push(&[0xEF]), Vec::::new()); assert_eq!(decoder.push(&[0xBB]), Vec::::new()); @@ -549,7 +548,7 @@ fn unknown_charset_falls_back_to_html_default_on_finish() { "Content-Type".to_owned(), b"text/html; charset=x-unknown".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!(decoder.push(b"

ok"), vec!["

ok"]); assert_eq!(decoder.finish(), None); @@ -570,7 +569,7 @@ fn injected_legacy_content_detector_receives_url_hint() { "Content-Type".to_owned(), b"text/html; charset=x-unknown".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new_with_legacy_encoding_detector( + let mut decoder = DocumentStreamingDecoder::new_with_legacy_encoding_detector( &headers, "https://legacy.example/", test_legacy_encoding_detector, @@ -593,14 +592,14 @@ fn declared_encodings_precede_injected_legacy_detector() { "Content-Type".to_owned(), b"text/html; charset=gbk".to_vec(), )]; - let mut header_decoder = HtmlDocumentStreamingDecoder::new_with_legacy_encoding_detector( + let mut header_decoder = DocumentStreamingDecoder::new_with_legacy_encoding_detector( &headers, "https://legacy.example/", unexpected_legacy_encoding_detector, ); assert_eq!(header_decoder.push(&gbk_bytes("太平洋")), vec!["太平洋"]); - let mut meta_decoder = HtmlDocumentStreamingDecoder::new_with_legacy_encoding_detector( + let mut meta_decoder = DocumentStreamingDecoder::new_with_legacy_encoding_detector( &[], "https://legacy.example/", unexpected_legacy_encoding_detector, @@ -1023,7 +1022,7 @@ fn assert_bom_less_utf16_xml_decodes_across_signature_splits( expected_encoding: &str, ) { for split in 1..6 { - let mut decoder = HtmlDocumentStreamingDecoder::new(&[]); + let mut decoder = DocumentStreamingDecoder::new(&[]); assert_eq!( decoder.push(&input[..split]), Vec::::new(), @@ -1065,7 +1064,7 @@ fn bom_less_utf16be_xml_signature_survives_every_streaming_split() { #[test] fn diverged_utf16_xml_signature_prefix_resumes_ascii_streaming() { - let mut decoder = HtmlDocumentStreamingDecoder::new(&[]); + let mut decoder = DocumentStreamingDecoder::new(&[]); assert!(decoder.push(b"<").is_empty()); assert_eq!( @@ -1082,7 +1081,7 @@ fn transport_charset_does_not_wait_for_a_utf16_xml_signature_prefix() { "Content-Type".to_owned(), b"text/html; charset=windows-1252".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); assert_eq!(decoder.push(b"<"), vec!["<"]); assert_eq!(decoder.selected_encoding_name(), Some("windows-1252")); diff --git a/moli-renderer-v8/src/document_response_decoder.rs b/moli-renderer-v8/src/document_response_decoder.rs index 82cc35102e..90e7176728 100644 --- a/moli-renderer-v8/src/document_response_decoder.rs +++ b/moli-renderer-v8/src/document_response_decoder.rs @@ -1,4 +1,4 @@ -use moli_encoding::HtmlDocumentStreamingDecoder; +use moli_encoding::DocumentStreamingDecoder; use moli_encoding_detector::detect_legacy_html_encoding; use moli_web_mime::{is_json_mime, is_text_document_mime, is_xml_document_mime}; use url::Url; @@ -8,9 +8,9 @@ pub(crate) fn new_document_response_decoder( content_type: Option<&str>, final_url: &Url, inherited_encoding: Option<&str>, -) -> HtmlDocumentStreamingDecoder { +) -> DocumentStreamingDecoder { if let Some(mime) = content_type.filter(|mime| is_text_document_mime(mime)) { - HtmlDocumentStreamingDecoder::new_text_document( + DocumentStreamingDecoder::new_text_document( headers, final_url.as_str(), detect_legacy_html_encoding, @@ -18,11 +18,11 @@ pub(crate) fn new_document_response_decoder( inherited_encoding, ) } else if content_type.is_some_and(is_xml_document_mime) { - HtmlDocumentStreamingDecoder::new_xml_document(headers) + DocumentStreamingDecoder::new_xml_document(headers) } else if inherited_encoding.is_some() { - HtmlDocumentStreamingDecoder::new_with_fallback(headers, inherited_encoding) + DocumentStreamingDecoder::new_with_fallback(headers, inherited_encoding) } else { - HtmlDocumentStreamingDecoder::new_with_legacy_encoding_detector( + DocumentStreamingDecoder::new_with_legacy_encoding_detector( headers, final_url.as_str(), detect_legacy_html_encoding, diff --git a/moli-renderer-v8/src/runtime/phase_one/streaming.rs b/moli-renderer-v8/src/runtime/phase_one/streaming.rs index 61a56d0967..94e0e745a3 100644 --- a/moli-renderer-v8/src/runtime/phase_one/streaming.rs +++ b/moli-renderer-v8/src/runtime/phase_one/streaming.rs @@ -4,7 +4,7 @@ use super::parser_blocking_pending::main_parser_blocking_classic_script_item; use super::scaffold::continue_phase_one_until_streaming_boundary_on_execution_context; use super::*; use crate::document_response_decoder::{decode_document_response, new_document_response_decoder}; -use moli_encoding::HtmlDocumentStreamingDecoder; +use moli_encoding::DocumentStreamingDecoder; use moli_web_mime::response_headers_indicate_attachment_download; use tokio::sync::{mpsc, oneshot}; @@ -620,7 +620,7 @@ fn response_document_parser( final_url: Url, headers: &[(String, Vec)], env: &PageVmEnvConfig, -) -> (ParseTimeDriverState, HtmlDocumentStreamingDecoder) { +) -> (ParseTimeDriverState, DocumentStreamingDecoder) { let content_type = moli_web_mime::response_document_content_type(headers); let text_type = content_type .as_deref() @@ -643,7 +643,7 @@ fn response_document_parser( pub(super) fn enqueue_streaming_raw_chunk( runtime: &mut ConcurrentParseTimeRuntime, - decoder: &mut HtmlDocumentStreamingDecoder, + decoder: &mut DocumentStreamingDecoder, chunk: Vec, service_worker_context: Option<&ServiceWorkerScriptPreloadContext>, ) { @@ -659,7 +659,7 @@ pub(super) fn enqueue_streaming_raw_chunk( fn scan_prebootstrap_raw_chunk_into_state( state: &mut ParseTimeDriverState, - decoder: &mut HtmlDocumentStreamingDecoder, + decoder: &mut DocumentStreamingDecoder, loader: &ResourceRequestClient, chunk: Vec, service_worker_context: Option<&ServiceWorkerScriptPreloadContext>, @@ -677,7 +677,7 @@ fn scan_prebootstrap_raw_chunk_into_state( fn preload_scan_ready_streaming_raw_chunks( runtime: &mut ConcurrentParseTimeRuntime, response: &mut RawDocumentBodySource, - decoder: &mut HtmlDocumentStreamingDecoder, + decoder: &mut DocumentStreamingDecoder, service_worker_context: Option<&ServiceWorkerScriptPreloadContext>, ) { // Chromium keeps parser-visible tree construction paused while allowing the @@ -692,7 +692,7 @@ fn preload_scan_ready_streaming_raw_chunks( fn prebootstrap_scan_ready_streaming_raw_chunks( state: &mut ParseTimeDriverState, response: &mut RawDocumentBodySource, - decoder: &mut HtmlDocumentStreamingDecoder, + decoder: &mut DocumentStreamingDecoder, loader: &ResourceRequestClient, service_worker_context: Option<&ServiceWorkerScriptPreloadContext>, ) -> Vec { @@ -724,7 +724,7 @@ async fn settle_streaming_raw_response_at_boundary( bootstrap_outcome: ParseTimePageVmStreamingBootstrapOutcome, response: RawDocumentBodySource, prebootstrap_chunks: Vec, - decoder: HtmlDocumentStreamingDecoder, + decoder: DocumentStreamingDecoder, service_worker_context: Option, started: Instant, boundary: CommittedNavigationBootstrapBoundary, @@ -758,7 +758,7 @@ fn park_streaming_raw_response_at_document_commit( bootstrap_outcome: ParseTimePageVmStreamingBootstrapOutcome, response: RawDocumentBodySource, prebootstrap_chunks: Vec, - decoder: HtmlDocumentStreamingDecoder, + decoder: DocumentStreamingDecoder, service_worker_context: Option, started: Instant, ) -> Result { @@ -803,7 +803,7 @@ async fn drive_streaming_raw_response_through_phase_one( bootstrap_outcome: ParseTimePageVmStreamingBootstrapOutcome, mut response: RawDocumentBodySource, prebootstrap_chunks: Vec, - mut decoder: HtmlDocumentStreamingDecoder, + mut decoder: DocumentStreamingDecoder, service_worker_context: Option, started: Instant, ) -> Result { @@ -900,7 +900,7 @@ async fn drive_streaming_raw_response_through_phase_one( pub(super) fn sync_document_character_set_from_decoder( runtime: &mut ConcurrentParseTimeRuntime, - decoder: &HtmlDocumentStreamingDecoder, + decoder: &DocumentStreamingDecoder, ) { let encoding = decoder.document_encoding_name(); runtime.state.document_character_set = encoding.to_owned(); @@ -913,7 +913,7 @@ pub(super) fn sync_document_character_set_from_decoder( fn sync_state_document_character_set_from_decoder( state: &mut ParseTimeDriverState, - decoder: &HtmlDocumentStreamingDecoder, + decoder: &DocumentStreamingDecoder, ) { let encoding = decoder.document_encoding_name(); state.document_character_set = encoding.to_owned(); @@ -1346,7 +1346,7 @@ mod tests { "Content-Type".to_owned(), b"text/html; charset=utf-8".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); preload_scan_ready_streaming_raw_chunks(&mut runtime, &mut source, &mut decoder, None); @@ -1421,7 +1421,7 @@ mod tests { "Content-Type".to_owned(), b"text/html; charset=utf-8".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); preload_scan_ready_streaming_raw_chunks( &mut runtime, @@ -1482,7 +1482,7 @@ mod tests { "Content-Type".to_owned(), b"text/html; charset=utf-8".to_vec(), )]; - let mut decoder = HtmlDocumentStreamingDecoder::new(&headers); + let mut decoder = DocumentStreamingDecoder::new(&headers); let chunks = prebootstrap_scan_ready_streaming_raw_chunks( &mut state, diff --git a/moli-renderer-v8/src/runtime/phase_one/streaming_residence.rs b/moli-renderer-v8/src/runtime/phase_one/streaming_residence.rs index 88722b39dd..6b6c3a979f 100644 --- a/moli-renderer-v8/src/runtime/phase_one/streaming_residence.rs +++ b/moli-renderer-v8/src/runtime/phase_one/streaming_residence.rs @@ -1,5 +1,5 @@ use anyhow::{Result, anyhow}; -use moli_encoding::HtmlDocumentStreamingDecoder; +use moli_encoding::DocumentStreamingDecoder; use std::time::Instant; use super::streaming::{ @@ -21,7 +21,7 @@ use super::{ pub(in crate::runtime) struct PendingStreamingPhaseOneContinuation { runtime: Box, input: StreamingDocumentInputSource, - decoder: HtmlDocumentStreamingDecoder, + decoder: DocumentStreamingDecoder, service_worker_preload_context: Option, started: Instant, deferred_main_resource_failure: Option, @@ -35,7 +35,7 @@ impl PendingStreamingPhaseOneContinuation { pub(super) fn bridge( runtime: ConcurrentParseTimeRuntime, raw_body: RawDocumentBodySource, - decoder: HtmlDocumentStreamingDecoder, + decoder: DocumentStreamingDecoder, service_worker_preload_context: Option, started: Instant, ) -> Result {