From 998203fbe945f109bbb93df8d0ba97565d5440de Mon Sep 17 00:00:00 2001 From: ldm0 Date: Fri, 9 Oct 2026 04:11:02 +0800 Subject: [PATCH] feat(core): support skipping raw response bodies by status Add MaterializeBelowStatus so document callers can return raw response metadata and cancel the download from its headers. Apply the same policy to network and service-worker responses while preserving the existing Materialize and RequirePage behavior. --- moli-core/src/runtime/mod.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/moli-core/src/runtime/mod.rs b/moli-core/src/runtime/mod.rs index 2adca07725..f5f924f7da 100644 --- a/moli-core/src/runtime/mod.rs +++ b/moli-core/src/runtime/mod.rs @@ -59,6 +59,9 @@ static NEXT_SESSION_ID: AtomicU64 = AtomicU64::new(1); pub enum RawDocumentFetchPolicy { /// Read the response body and return [`FetchedDocument::Raw`]. Materialize, + /// Read the body only for statuses below the threshold. Otherwise return + /// response metadata with an empty body and cancel the download. + MaterializeBelowStatus(u16), /// Require a renderable Page, rejecting raw responses from their headers. RequirePage, } @@ -75,10 +78,13 @@ impl fmt::Display for RawDocumentPageRequired { impl std::error::Error for RawDocumentPageRequired {} -fn ensure_raw_document_materialization_allowed(policy: RawDocumentFetchPolicy) -> Result<()> { - match policy { - RawDocumentFetchPolicy::Materialize => Ok(()), - RawDocumentFetchPolicy::RequirePage => Err(anyhow::Error::new(RawDocumentPageRequired)), +impl RawDocumentFetchPolicy { + fn should_materialize_body(self, status: u16) -> Result { + match self { + Self::Materialize => Ok(true), + Self::MaterializeBelowStatus(threshold) => Ok(status < threshold), + Self::RequirePage => Err(anyhow::Error::new(RawDocumentPageRequired)), + } } } @@ -563,9 +569,12 @@ impl Browser { if let Some(response) = response { navigation_loader.note_service_worker_response_ready()?; if response_headers_indicate_raw_document(&response.headers) { - ensure_raw_document_materialization_allowed(raw_document_policy)?; - let raw_response = - RawResponse::from_head_and_body(response.head(), response.clone_body_bytes()); + let body = if raw_document_policy.should_materialize_body(response.status)? { + response.clone_body_bytes() + } else { + Vec::new() + }; + let raw_response = RawResponse::from_head_and_body(response.head(), body); return Ok(FetchedDocument::Raw(Box::new(RawDocument::from_response( raw_response, )))); @@ -609,7 +618,12 @@ impl Browser { ) .await?; if response_headers_indicate_raw_document(&response.headers) { - ensure_raw_document_materialization_allowed(raw_document_policy)?; + if !raw_document_policy.should_materialize_body(response.status)? { + let raw_response = RawResponse::from_head_and_body(response.head(), Vec::new()); + return Ok(FetchedDocument::Raw(Box::new(RawDocument::from_response( + raw_response, + )))); + } // Binary/download-like main resources have no DOM lifecycle // milestones, but materializing a RawDocument still consumes the // caller-owned absolute fetch-readiness budget.