fix(performance): distinguish cached and validated resource transfers

Carry Fetch response cache state through buffered and streaming responses,
navigation, child-document snapshots, and paused response continuations.
Fresh disk and memory hits are local; an actual 304 merge is validated.
A later memory-cache read resets validated state to local.

Resource Timing now reports zero transferred bytes for local hits, 300 for
validation, and body size plus the fixed 300-byte overhead for network
responses. Real response-header lengths no longer affect transferSize.

Exercise real HTTP cache hits, conditional requests, response bodies and
header padding in top and child documents. Preserve the existing network
provenance of in-flight script waiters.

Validation: cargo fmt --all; full workspace/all-targets/all-features Clippy
with -D warnings; cargo nextest run --no-fail-fast (19872 passed, 13 skipped).
All Cargo runs used 32 build jobs and 32 test threads. The production binary
matches Chromium across 22 cache-timing observations; preload controls stay
at 23/24 with the existing pending-preload duplicate-download failure.
This commit is contained in:
ldm0
2026-10-11 18:06:41 +08:00
parent 40fe7dd38d
commit 9bcfe70fab
64 changed files with 409 additions and 26 deletions
Generated
+1
View File
@@ -2669,6 +2669,7 @@ dependencies = [
"moli-web-mime",
"parking_lot",
"rcgen",
"serde",
"strum",
"tokio",
"tokio-rustls",
+1
View File
@@ -90,6 +90,7 @@ async fn external_raw_bridge_drop_after_body_eof_cancels_pending_fetch_completio
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_rx,
+2 -1
View File
@@ -10,7 +10,8 @@ use std::time::Instant;
use support::FixtureServer;
use tokio::time::Duration;
#[path = "fetch_behaviors/cache_timing.rs"]
mod cache_timing;
#[path = "fetch_behaviors/preload_as.rs"]
mod preload_as;
#[path = "fetch_behaviors/preload_crossorigin.rs"]
@@ -0,0 +1,164 @@
use super::*;
use std::{collections::HashMap, path::PathBuf, sync::Arc};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::TcpListener;
struct CacheDirectory(PathBuf);
impl Drop for CacheDirectory {
fn drop(&mut self) {
let _ = std::fs::remove_dir_all(&self.0);
}
}
#[tokio::test(flavor = "multi_thread")]
async fn resource_timing_distinguishes_network_local_and_revalidated_responses() -> Result<()> {
let listener = TcpListener::bind("127.0.0.1:0").await?;
let addr = listener.local_addr()?;
let cache_dir = CacheDirectory(std::env::temp_dir().join(format!(
"moli-resource-timing-{}-{}",
std::process::id(),
addr.port()
)));
let requests = Arc::new(parking_lot::Mutex::new(HashMap::<
String,
Vec<Option<String>>,
>::new()));
let (shutdown, mut shutting_down) = tokio::sync::oneshot::channel::<()>();
let server = tokio::spawn(async move {
let mut connections = tokio::task::JoinSet::new();
loop {
tokio::select! {
_ = &mut shutting_down => break,
accepted = listener.accept() => {
let (mut socket, _) = accepted?;
let requests = Arc::clone(&requests);
connections.spawn(async move {
let mut bytes = Vec::new();
loop {
let mut buffer = [0; 4096];
let size = socket.read(&mut buffer).await?;
if size == 0 { return Ok::<_, anyhow::Error>(()); }
bytes.extend_from_slice(&buffer[..size]);
if bytes.windows(4).any(|part| part == b"\r\n\r\n") { break; }
}
let request = String::from_utf8(bytes)?;
let path = request.split_whitespace().nth(1).context("request path")?;
let url = url::Url::parse(&format!("http://fixture{path}"))?;
let params: HashMap<_, _> = url.query_pairs().collect();
let mode = params.get("mode").map(|value| value.as_ref()).unwrap_or("");
let context = params.get("context").map(|value| value.as_ref()).unwrap_or("");
let key = format!("{mode}:{context}");
let conditional = request.lines().find_map(|line| {
let (name, value) = line.split_once(':')?;
name.eq_ignore_ascii_case("if-none-match").then(|| value.trim().to_owned())
});
let mut headers = String::new();
let (status, mime, body) = match url.path() {
"/probe-cache" => {
requests.lock().entry(key).or_default().push(conditional.clone());
let validated = mode == "revalidate" && conditional.as_deref() == Some("\"v1\"");
let cache = if mode == "fresh" || validated { "max-age=600" }
else if mode == "revalidate" { "no-cache" }
else { "no-store" };
headers = format!("ETag: \"v1\"\r\nCache-Control: {cache}\r\n");
if mode == "padding" {
let padding: usize = params.get("padding").context("padding")?.parse()?;
headers.push_str(&format!("X-Padding: {}\r\n", "x".repeat(padding)));
}
if validated { ("304 Not Modified", "text/plain", String::new()) }
else { ("200 OK", "text/plain", "cached".to_owned()) }
}
"/probe-cache-stats" => {
headers.push_str("Cache-Control: no-store\r\n");
let records = requests.lock().get(&key).cloned().unwrap_or_default();
let records: Vec<_> = records.into_iter().map(|conditional| serde_json::json!({"conditional":conditional})).collect();
("200 OK", "application/json", serde_json::to_string(&records)?)
}
_ => ("200 OK", "text/html", "<!doctype html><body>cache timing".to_owned()),
};
socket.write_all(format!(
"HTTP/1.1 {status}\r\nContent-Type: {mime}\r\nContent-Length: {}\r\n{headers}Connection: close\r\n\r\n{body}", body.len()
).as_bytes()).await?;
Ok(())
});
}
Some(result) = connections.join_next(), if !connections.is_empty() => { result??; }
}
}
connections.shutdown().await;
Ok::<_, anyhow::Error>(())
});
let mut config = AppConfig::default();
config
.fetch_mut()
.set_http_cache_dir(Some(cache_dir.0.display().to_string()));
let browser = Browser::new(config)?;
let mut page = browser.fetch(&format!("http://{addr}/")).await?;
let fixture = include_str!("../fixtures/cache-resource-timing.js");
for context in ["top", "child"] {
let script = if context == "top" {
fixture.to_owned()
} else {
format!(
r#"(async () => {{
const frame = document.createElement('iframe');
frame.srcdoc = '<!doctype html><body>child';
await new Promise(resolve => {{ frame.onload=resolve; document.body.append(frame); }});
frame.contentWindow.cacheTimingContext = 'child';
const result = await frame.contentWindow.eval({});
frame.remove();
return result;
}})()"#,
serde_json::to_string(fixture)?
)
};
let result = tokio::time::timeout(
Duration::from_secs(15),
page.evaluate_runtime_expression_with_await_async(
&format!("({script}).then(JSON.stringify)"),
true,
),
)
.await??;
let observed: serde_json::Value =
serde_json::from_str(result["value"].as_str().context("timing observations")?)?;
let expected = [
("fresh", [306, 0, 0]),
("revalidate", [306, 300, 0]),
("no-store", [306, 306, 306]),
];
let mut expected_rows = Vec::new();
for (mode, transfers) in expected {
let observations: Vec<_> = transfers
.into_iter()
.enumerate()
.map(|(index, transfer)| {
serde_json::json!({
"body":"cached", "count":index + 1, "transfer":transfer, "encoded":6, "decoded":6, "status":200
})
})
.collect();
let stats = match mode {
"fresh" => serde_json::json!([{"conditional":null}]),
"revalidate" => serde_json::json!([{"conditional":null},{"conditional":"\"v1\""}]),
_ => {
serde_json::json!([{"conditional":null},{"conditional":null},{"conditional":null}])
}
};
expected_rows
.push(serde_json::json!({"mode":mode,"observations":observations,"stats":stats}));
}
assert_eq!(
observed,
serde_json::json!({"result":expected_rows,"headers":[
{"padding":0,"transfer":306,"encoded":6},
{"padding":4096,"transfer":306,"encoded":6}
]}),
"{context}"
);
}
let _ = shutdown.send(());
server.await??;
Ok(())
}
+45
View File
@@ -0,0 +1,45 @@
(async () => {
const xhr = url => new Promise((resolve, reject) => {
const request = new XMLHttpRequest();
request.open('GET', url);
request.onload = () => resolve(request.responseText);
request.onerror = () => reject(new Error('xhr ' + url));
request.send();
});
const context = globalThis.cacheTimingContext || 'top';
const resourceUrl = (path, parameters) => {
const url = new URL(path, document.baseURI);
url.search = new URLSearchParams({...parameters, context});
return url.href;
};
const result = [];
for (const mode of ['fresh', 'revalidate', 'no-store']) {
const url = resourceUrl('/probe-cache', {mode});
const observations = [];
for (let i = 0; i < 3; i++) {
const body = await xhr(url);
await new Promise(resolve => setTimeout(resolve, 0));
const entries = performance.getEntriesByName(url);
const entry = entries[entries.length - 1];
observations.push({
body,
count: entries.length,
transfer: entry.transferSize,
encoded: entry.encodedBodySize,
decoded: entry.decodedBodySize,
status: entry.responseStatus
});
}
const stats = await (await fetch(resourceUrl('/probe-cache-stats', {mode}))).json();
result.push({mode, observations, stats});
}
const headers = [];
for (const padding of [0, 4096]) {
const url = resourceUrl('/probe-cache', {mode: 'padding', padding});
await xhr(url);
await new Promise(resolve => setTimeout(resolve, 0));
const entry = performance.getEntriesByName(url)[0];
headers.push({padding, transfer: entry.transferSize, encoded: entry.encodedBodySize});
}
return {result, headers};
})()
+1
View File
@@ -27,6 +27,7 @@ moli-url-policy = { path = "../moli-url-policy" }
moli-web-bot-auth = { path = "../moli-web-bot-auth" }
moli-web-mime = { path = "../moli-web-mime" }
parking_lot = "0.12"
serde = { version = "1.0.228", features = ["derive"] }
strum = { version = "0.28.0", features = ["derive"] }
tokio = { version = "1.51.0", features = ["rt", "sync"] }
tracing = "0.1.41"
+1
View File
@@ -90,6 +90,7 @@ pub(crate) struct CachedStreamingResponseLookup {
pub(crate) body: std::io::BufReader<std::fs::File>,
pub(crate) expires_at_unix_ms: Option<u64>,
pub(crate) force_validate: bool,
pub(crate) cache_state: crate::ResponseCacheState,
}
pub(crate) fn cached_streaming_response_is_stale(record: &CachedStreamingResponseLookup) -> bool {
+1
View File
@@ -165,6 +165,7 @@ fn cached_streaming_record_from_entry(
body: entry.body,
expires_at_unix_ms: entry.metadata.expires_at_unix_ms,
force_validate,
cache_state: crate::ResponseCacheState::Local,
}
}
+1
View File
@@ -25,6 +25,7 @@ pub(crate) fn merge_cached_not_modified_streaming_response_lookup(
) -> Result<CachedStreamingResponseLookup> {
let headers = merge_not_modified_headers(&cached.headers, not_modified_headers);
cached.headers = headers.clone();
cached.cache_state = crate::ResponseCacheState::Validated;
cached.metadata.headers = headers.clone();
let final_url = Url::parse(&cached.final_url).with_context(|| {
+2
View File
@@ -537,6 +537,7 @@ impl StreamingResponseCollector {
redirected: !self.redirect_chain.is_empty(),
redirect_chain: self.redirect_chain.clone(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: self.negotiated_http_version,
network_request_extra_info: self.network_request_extra_info.clone(),
}));
@@ -940,6 +941,7 @@ impl RawStreamingResponseCollector {
redirected: !self.redirect_chain.is_empty(),
redirect_chain: self.redirect_chain.clone(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: self.negotiated_http_version,
network_request_extra_info: self.network_request_extra_info.clone(),
}));
+2
View File
@@ -73,6 +73,7 @@ pub struct StreamingHtmlResponseStart {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
pub network_request_extra_info: Option<NetworkRequestExtraInfo>,
}
@@ -89,6 +90,7 @@ impl StreamingHtmlResponseStart {
redirected: self.redirected,
redirect_chain: self.redirect_chain,
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
+1 -1
View File
@@ -83,7 +83,7 @@ pub use request::{
pub use request_policy::{is_bad_port, should_request_be_blocked_due_to_bad_port};
pub use response::{
NegotiatedHttpVersion, NetworkRequestExtraInfo, NetworkResponseExtraInfo, RawResponse,
RedirectInfo, RedirectSource, Response, ResponseBody, ResponseHead,
RedirectInfo, RedirectSource, Response, ResponseBody, ResponseCacheState, ResponseHead,
};
pub use runtime::PendingStreamingRawResponse;
pub use runtime::{
+26
View File
@@ -4,6 +4,18 @@ use url::Url;
use crate::{StreamingHtmlResponse, StreamingRawResponse};
/// Fetch's response cache state, retained separately from the legacy
/// `from_cache` flag so Resource Timing can distinguish a 304 validation from
/// a response served without a network request.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum ResponseCacheState {
#[default]
None,
Local,
Validated,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum NegotiatedHttpVersion {
Http09,
@@ -51,6 +63,7 @@ pub struct ResponseHead {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
}
@@ -327,6 +340,7 @@ pub struct Response {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
network_request_extra_info: Option<NetworkRequestExtraInfo>,
}
@@ -347,6 +361,7 @@ impl Clone for Response {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
network_request_extra_info: self.network_request_extra_info.clone(),
}
@@ -401,6 +416,7 @@ impl Response {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -439,6 +455,7 @@ impl Response {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
})
@@ -457,6 +474,7 @@ impl Response {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
})
@@ -473,6 +491,7 @@ impl Response {
redirected: self.redirected,
redirect_chain: self.redirect_chain,
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
};
let (body, body_bytes) = self
@@ -510,6 +529,7 @@ impl Response {
redirected: self.redirected,
redirect_chain: self.redirect_chain,
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
};
(head, self.body)
@@ -536,6 +556,7 @@ pub struct RawResponse {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
network_request_extra_info: Option<NetworkRequestExtraInfo>,
}
@@ -556,6 +577,7 @@ impl Clone for RawResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
network_request_extra_info: self.network_request_extra_info.clone(),
}
@@ -604,6 +626,7 @@ impl RawResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -628,6 +651,7 @@ impl RawResponse {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
})
@@ -646,6 +670,7 @@ impl RawResponse {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
})
@@ -662,6 +687,7 @@ impl RawResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain,
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
};
(head, self.body)
+9
View File
@@ -2344,6 +2344,7 @@ impl RuntimeOwner {
redirected: !job.request.redirect_chain.is_empty(),
redirect_chain: job.request.redirect_chain,
from_cache: false,
cache_state: Default::default(),
negotiated_http_version,
network_request_extra_info: request_extra_info,
}));
@@ -2920,6 +2921,7 @@ fn complete_streaming_html_job(job: StreamingRuntimeJob, response: Response) {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info,
}));
@@ -2941,6 +2943,7 @@ fn complete_cached_streaming_html_job(
let redirect_chain = job.request.redirect_chain.clone();
let CachedStreamingResponseLookup {
metadata,
cache_state,
final_url,
status,
headers,
@@ -2973,6 +2976,7 @@ fn complete_cached_streaming_html_job(
redirected,
redirect_chain,
from_cache: true,
cache_state,
negotiated_http_version: None,
network_request_extra_info: None,
}));
@@ -3063,6 +3067,7 @@ fn complete_cached_streaming_raw_job(
let redirect_chain = job.request.redirect_chain.clone();
let CachedStreamingResponseLookup {
metadata,
cache_state,
final_url,
status,
headers,
@@ -3095,6 +3100,7 @@ fn complete_cached_streaming_raw_job(
redirected,
redirect_chain,
from_cache: true,
cache_state,
negotiated_http_version: None,
network_request_extra_info: None,
}));
@@ -3537,6 +3543,7 @@ fn proxy_connect_response_start(
redirected: !redirect_chain.is_empty(),
redirect_chain: redirect_chain.to_vec(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
network_request_extra_info: None,
}
@@ -3640,6 +3647,7 @@ fn collect_buffered_response(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version,
},
body,
@@ -4300,6 +4308,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"<!doctype html><html><body>cached</body></html>".to_owned(),
+9
View File
@@ -31,6 +31,7 @@ pub struct StreamingHtmlResponse {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
network_request_extra_info: Option<NetworkRequestExtraInfo>,
body_chunks: mpsc::UnboundedReceiver<String>,
@@ -58,6 +59,7 @@ impl StreamingHtmlResponse {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_chunks,
@@ -82,6 +84,7 @@ impl StreamingHtmlResponse {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
body_chunks,
@@ -101,6 +104,7 @@ impl StreamingHtmlResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -174,6 +178,7 @@ pub struct StreamingRawResponse {
pub redirected: bool,
pub redirect_chain: Vec<RedirectInfo>,
pub from_cache: bool,
pub cache_state: crate::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
network_request_extra_info: Option<NetworkRequestExtraInfo>,
body_chunks: mpsc::UnboundedReceiver<Vec<u8>>,
@@ -205,6 +210,7 @@ impl StreamingRawResponse {
redirected,
redirect_chain,
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
network_request_extra_info: None,
body_chunks,
@@ -230,6 +236,7 @@ impl StreamingRawResponse {
redirected: head.redirected,
redirect_chain: head.redirect_chain,
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_extra_info: None,
body_chunks,
@@ -321,6 +328,7 @@ impl StreamingRawResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -387,6 +395,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
}
}
+12
View File
@@ -74,6 +74,7 @@ fn sample_response_head() -> ResponseHead {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
}
}
@@ -4405,11 +4406,19 @@ fn network_metadata_keeps_raw_304_separate_from_merged_cached_response() {
fetch_raw_with_network_metadata_for_test(&client, Request::get(&server.url()).unwrap())
.unwrap();
assert_eq!(first.response().status, 200);
assert_eq!(
first.response().cache_state,
crate::ResponseCacheState::None
);
let second =
fetch_raw_with_network_metadata_for_test(&client, Request::get(&server.url()).unwrap())
.unwrap();
assert_eq!(second.response().status, 200);
assert_eq!(
second.response().cache_state,
crate::ResponseCacheState::Validated
);
assert_eq!(second.response().body_bytes(), b"cached");
let exchange = second
.observation_journal()
@@ -4812,6 +4821,9 @@ fn fetch_client_cache_updates_freshness_after_not_modified() {
assert_eq!(first.body_text(), "hit-1");
assert_eq!(second.body_text(), "hit-1");
assert_eq!(third.body_text(), "hit-1");
assert_eq!(first.cache_state, crate::ResponseCacheState::None);
assert_eq!(second.cache_state, crate::ResponseCacheState::Validated);
assert_eq!(third.cache_state, crate::ResponseCacheState::Local);
for response in [&first, &second, &third] {
assert_eq!(response.status, 200);
assert_eq!(
+14
View File
@@ -326,6 +326,7 @@ pub struct NavigationResponse {
pub redirected: bool,
pub redirect_chain: Vec<NavigationRedirect>,
pub from_cache: bool,
pub cache_state: moli_fetch::ResponseCacheState,
pub negotiated_http_version: Option<NegotiatedHttpVersion>,
network_request_headers: Option<Vec<(String, String)>>,
}
@@ -346,6 +347,7 @@ impl Clone for NavigationResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.clone(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
network_request_headers: self.network_request_headers.clone(),
}
@@ -407,6 +409,7 @@ impl NavigationResponse {
.map(Into::into)
.collect(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -448,6 +451,7 @@ impl NavigationResponse {
redirected: head.redirected,
redirect_chain: head.redirect_chain.into_iter().map(Into::into).collect(),
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_headers: None,
}
@@ -474,6 +478,7 @@ impl NavigationResponse {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body,
@@ -506,6 +511,7 @@ impl NavigationResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.into_iter().map(Into::into).collect(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
};
let (body, body_bytes) = self
@@ -543,6 +549,7 @@ impl NavigationResponse {
redirected: self.redirected,
redirect_chain: self.redirect_chain.into_iter().map(Into::into).collect(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
};
(head, self.body)
@@ -2431,6 +2438,7 @@ pub struct PendingSubresourceResponseInfo {
/// a response-stage Fetch pause is held.
pub response_body: SubresourceResponseBody,
pub from_cache: bool,
pub cache_state: moli_fetch::ResponseCacheState,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -2450,6 +2458,7 @@ pub struct PendingSubresourceAuthInfo {
pub response_headers: Vec<(String, Vec<u8>)>,
pub response_body: SubresourceResponseBody,
pub response_from_cache: bool,
pub response_cache_state: moli_fetch::ResponseCacheState,
}
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -3310,6 +3319,8 @@ pub struct ChildFrameDocumentNetworkSnapshot {
pub response_body: Option<SubresourceResponseBody>,
#[serde(default)]
pub from_cache: bool,
#[serde(default)]
pub cache_state: moli_fetch::ResponseCacheState,
}
/// A completed child main-resource request whose Network facts remain
@@ -4033,6 +4044,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"hello".to_owned(),
@@ -4060,6 +4072,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"é".to_owned(),
@@ -4098,6 +4111,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
String::new(),
+1
View File
@@ -273,6 +273,7 @@ impl PendingFetchAuthNavigation {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
b"auth required".to_vec(),
@@ -408,6 +408,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body.to_vec(),
+4
View File
@@ -159,6 +159,7 @@ async fn prepare_browser_owned_error_page_navigation_with_engine_async(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
prepare_captured_document_response_with_engine_async(
@@ -1215,6 +1216,7 @@ fn decoded_data_url_navigation_response(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
decoded.body,
@@ -1311,6 +1313,7 @@ async fn load_inline_html_navigation_with_engine_async(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
prepare_navigation_from_captured_raw_response_with_engine_async(
@@ -3003,6 +3006,7 @@ impl CdpConnection {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
self.build_navigation_from_captured_raw_response_with_load_inputs_async(
@@ -629,6 +629,7 @@ fn pause_data_url_response_stage_navigation_into_buffer(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body,
@@ -592,6 +592,7 @@ mod tests {
response_headers: vec![("content-type".to_owned(), b"text/plain".to_vec())],
response_body: SubresourceResponseBody::from_bytes(b"prepared".to_vec()),
from_cache: false,
cache_state: Default::default(),
});
let action = crate::domains::activity::PreparedSubresourceContinueAction::capture_for_test(
&mut conn,
@@ -669,6 +670,7 @@ mod tests {
response_headers: Vec::new(),
response_body: SubresourceResponseBody::from_bytes(b"old".to_vec()),
from_cache: false,
cache_state: Default::default(),
});
let old_action =
crate::domains::activity::PreparedSubresourceContinueAction::capture_for_test(
@@ -689,6 +689,7 @@ async fn clear_browser_cache_keeps_pending_response_navigation_transfer() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
b"body".to_vec(),
@@ -1643,6 +1643,7 @@ async fn child_frame_activity_emits_document_network_events_from_prepared_load()
encoded_data_length: 3,
response_body: Some(SubresourceResponseBody::from_bytes(vec![0x00, 0xff, b'a'])),
from_cache: true,
cache_state: moli_fetch::ResponseCacheState::Local,
}),
}],
"https://example.test".to_owned(),
@@ -1774,6 +1775,7 @@ async fn stale_child_document_response_emits_network_without_navigation_or_lifec
b"historical child body".to_vec(),
)),
from_cache: false,
cache_state: Default::default(),
},
}],
Vec::new(),
@@ -1875,6 +1877,7 @@ async fn child_document_network_without_body_records_known_no_data() {
encoded_data_length: 0,
response_body: None,
from_cache: false,
cache_state: Default::default(),
};
let mut background_events = Vec::new();
@@ -298,6 +298,7 @@ impl ResourcePerformanceEntry {
response.status,
&response.headers,
body_size as f64,
response.cache_state,
)
}
@@ -315,6 +316,7 @@ impl ResourcePerformanceEntry {
response.status,
&response.headers,
body_size as f64,
response.cache_state,
)
}
@@ -331,6 +333,7 @@ impl ResourcePerformanceEntry {
response.status,
&response.headers,
response.body_bytes().len() as f64,
response.cache_state,
)
}
@@ -341,11 +344,15 @@ impl ResourcePerformanceEntry {
response_status: u16,
response_headers: &[(String, Vec<u8>)],
body_size: f64,
cache_state: moli_fetch::ResponseCacheState,
) -> Self {
let header_size = response_headers
.iter()
.map(|(name, value)| name.len() + value.len() + 4)
.sum::<usize>() as f64;
// Resource Timing deliberately uses a fixed overhead rather than
// exposing response-header sizes, which could reveal cookies.
let transfer_size = match cache_state {
moli_fetch::ResponseCacheState::None => body_size + 300.0,
moli_fetch::ResponseCacheState::Local => 0.0,
moli_fetch::ResponseCacheState::Validated => 300.0,
};
let content_type = moli_web_mime::response_content_type(response_headers)
.and_then(|value| moli_web_mime::mime_essence(&value))
.unwrap_or_default();
@@ -353,7 +360,7 @@ impl ResourcePerformanceEntry {
name: name.into(),
initiator_type: initiator_type.to_owned(),
start_unix_millis,
transfer_size: (body_size + header_size).max(1.0),
transfer_size,
encoded_body_size: body_size,
decoded_body_size: body_size,
// The fetch lifecycle does not yet retain render-blocking metadata.
@@ -370,26 +377,15 @@ impl ResourcePerformanceEntry {
start_unix_millis: Option<f64>,
network: &crate::protocol_types::ChildFrameDocumentNetworkSnapshot,
) -> Self {
let body_size = network.encoded_data_length as f64;
let header_size = network
.response_headers
.iter()
.map(|(name, value)| name.len() + value.len() + 4)
.sum::<usize>() as f64;
let content_type = moli_web_mime::response_content_type(&network.response_headers)
.and_then(|value| moli_web_mime::mime_essence(&value))
.unwrap_or_default();
Self {
name: name.into(),
initiator_type: initiator_type.to_owned(),
Self::from_response_parts(
name,
initiator_type,
start_unix_millis,
transfer_size: (body_size + header_size).max(1.0),
encoded_body_size: body_size,
decoded_body_size: body_size,
render_blocking_status: "non-blocking".to_owned(),
response_status: f64::from(network.status),
content_type,
}
network.status,
&network.response_headers,
network.encoded_data_length as f64,
network.cache_state,
)
}
pub(crate) fn from_network_failure(
@@ -1108,6 +1108,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: true,
cache_state: moli_fetch::ResponseCacheState::Local,
negotiated_http_version: None,
},
"export default 1;".to_owned(),
@@ -888,6 +888,7 @@ fn child_document_load_outcome_from_response(
encoded_data_length,
response_body: Some(response_body),
from_cache: head.from_cache,
cache_state: head.cache_state,
}),
},
)))
@@ -956,6 +957,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(body_bytes.clone()),
@@ -3085,6 +3085,7 @@ impl JsContextHost {
redirected: false,
redirect_chain: Vec::new(),
from_cache: info.from_cache,
cache_state: info.cache_state,
negotiated_http_version: None,
},
)
@@ -3130,6 +3131,7 @@ impl JsContextHost {
redirected: false,
redirect_chain: Vec::new(),
from_cache: info.response_from_cache,
cache_state: info.response_cache_state,
negotiated_http_version: None,
},
)
@@ -306,6 +306,7 @@ impl JsContextHost {
response_headers: response_headers.into_iter().collect(),
response_body: SubresourceResponseBody::from_bytes(Vec::new()),
from_cache: false,
cache_state: Default::default(),
}),
);
true
@@ -836,6 +836,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body.to_owned(),
@@ -854,6 +855,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body.to_vec(),
@@ -1058,6 +1060,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"x".repeat(64),
@@ -68,6 +68,7 @@ impl RendererPreparedNetworkResourceLoad {
cookie_set_reports: head.cookie_set_reports,
redirect_chain: head.redirect_chain.into_iter().map(Into::into).collect(),
from_cache: head.from_cache,
cache_state: head.cache_state,
negotiated_http_version: head.negotiated_http_version,
network_request_headers,
},
@@ -90,6 +91,7 @@ pub struct RendererNetworkResourceLoadResponse {
pub cookie_set_reports: Vec<StoredCookieSetReport>,
pub redirect_chain: Vec<NavigationRedirect>,
pub from_cache: bool,
pub cache_state: moli_fetch::ResponseCacheState,
pub negotiated_http_version: Option<moli_fetch::NegotiatedHttpVersion>,
pub network_request_headers: Option<Vec<(String, String)>>,
}
@@ -111,6 +113,7 @@ impl RendererNetworkResourceLoadResponse {
.map(Into::into)
.collect(),
from_cache: self.from_cache,
cache_state: self.cache_state,
negotiated_http_version: self.negotiated_http_version,
}
}
@@ -1208,6 +1208,7 @@ fn streaming_raw_response_from_cached_subresource(
) -> Result<StreamingRawResponse> {
let mut head = response.head();
head.from_cache = true;
head.cache_state = moli_fetch::ResponseCacheState::Local;
for redirect in &mut head.redirect_chain {
redirect.from_cache = true;
redirect.network_extra_info_available = false;
@@ -1231,6 +1232,7 @@ fn streaming_raw_response_from_local_response(response: Response) -> Result<Stre
fn response_with_memory_cache_hit(mut response: Response) -> Response {
response.from_cache = true;
response.cache_state = moli_fetch::ResponseCacheState::Local;
for redirect in &mut response.redirect_chain {
redirect.from_cache = true;
redirect.network_extra_info_available = false;
@@ -288,6 +288,7 @@ async fn memory_cache_tee_drop_after_body_eof_cancels_pending_completion_and_rel
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_rx,
@@ -1228,6 +1229,8 @@ async fn concurrent_script_text_waiter_preserves_owner_cache_state() -> Result<(
!second.from_cache,
"in-flight coalescing should preserve the owner's network provenance"
);
assert_eq!(first.cache_state, moli_fetch::ResponseCacheState::None);
assert_eq!(second.cache_state, moli_fetch::ResponseCacheState::None);
let third = loader
.fetch_cacheable_script_text_stream(request()?)
@@ -1240,6 +1243,7 @@ async fn concurrent_script_text_waiter_preserves_owner_cache_state() -> Result<(
third.from_cache,
"completed script text cache hits should still report memory-cache provenance"
);
assert_eq!(third.cache_state, moli_fetch::ResponseCacheState::Local);
server.await?;
Ok(())
@@ -1605,6 +1609,7 @@ async fn cached_raw_subresource_marks_redirect_hops_from_cache() -> Result<()> {
negotiated_http_version: None,
}],
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
b"cached-final-body".to_vec(),
@@ -1089,6 +1089,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
true,
@@ -187,6 +187,7 @@ fn cors_redirect_referrer_never_recovers_stripped_information() -> Result<()> {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
assert_eq!(
@@ -239,6 +240,7 @@ fn cors_redirect_modes_precede_location_parsing() -> Result<()> {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let result = redirects.advance(head, false, None);
@@ -129,6 +129,7 @@ pub(super) fn blob_response(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_bytes.to_vec(),
@@ -152,6 +153,7 @@ pub(crate) fn data_url_response(url: &url::Url) -> Option<Response> {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_bytes,
@@ -626,6 +626,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
}
}
@@ -657,6 +658,7 @@ mod tests {
negotiated_http_version: None,
}],
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let document_url = url("https://document.test/page.html");
@@ -95,6 +95,7 @@ fn xhr_complete_callback(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
pending_body_value,
@@ -312,6 +312,7 @@ impl DetachedParserScriptFetchContinuation {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
ResponseBody::materialized_text(text, response_body),
@@ -732,6 +732,7 @@ fn dedicated_worker_navigation_response_eq(
&& left.redirected == right.redirected
&& left.redirect_chain == right.redirect_chain
&& left.from_cache == right.from_cache
&& left.cache_state == right.cache_state
&& left.negotiated_http_version == right.negotiated_http_version
&& left.network_request_headers() == right.network_request_headers()
}
@@ -491,6 +491,7 @@ fn about_blank_navigation_response(url: &Url) -> Option<moli_fetch::Response> {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
Vec::new(),
@@ -245,6 +245,7 @@ fetch({:?})
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
},
@@ -460,6 +461,7 @@ async fn streaming_finish_requires_matching_request_and_body_source_identity() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
},
@@ -738,6 +738,7 @@ pub(super) fn stale_loaded_completion(
encoded_data_length: 0,
response_body: None,
from_cache: false,
cache_state: Default::default(),
}),
},
))),
@@ -633,6 +633,7 @@ fn module_graph_network_result_records_staged_response_started_with_cache_state(
redirected: false,
redirect_chain: Vec::new(),
from_cache: true,
cache_state: moli_fetch::ResponseCacheState::Local,
negotiated_http_version: None,
},
"export default 1;".to_owned(),
@@ -859,6 +859,7 @@ impl ScriptVm {
response_headers: response.headers.clone(),
response_body: SubresourceResponseBody::from_navigation_response(&response),
from_cache: response.from_cache,
cache_state: response.cache_state,
};
self._context_host
.borrow_mut()
@@ -1115,6 +1116,7 @@ impl ScriptVm {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let pending = match continuation {
@@ -1861,6 +1863,7 @@ impl ScriptVm {
redirected: false,
redirect_chain: Vec::new(),
from_cache: pending.response.from_cache,
cache_state: pending.response.cache_state,
negotiated_http_version: pending.response.negotiated_http_version,
});
let result = if pending.pending.request_mode == moli_fetch::RequestMode::NoCors {
@@ -1925,6 +1928,7 @@ impl ScriptVm {
redirected: false,
redirect_chain: Vec::new(),
from_cache: pending.response.from_cache,
cache_state: pending.response.cache_state,
negotiated_http_version: pending.response.negotiated_http_version,
});
let result = if pending.pending.request_mode == moli_fetch::RequestMode::NoCors {
@@ -1998,6 +2002,7 @@ impl ScriptVm {
redirected: false,
redirect_chain: Vec::new(),
from_cache: pending.response.from_cache,
cache_state: pending.response.cache_state,
negotiated_http_version: pending.response.negotiated_http_version,
}),
),
@@ -138,6 +138,7 @@ impl ScriptVm {
response_headers: response.headers.clone(),
response_body: SubresourceResponseBody::from_navigation_response(&response),
response_from_cache: response.from_cache,
response_cache_state: response.cache_state,
};
trace_async_subresource_stage(
"async_subresource_complete_running_auth_required",
@@ -191,6 +192,7 @@ impl ScriptVm {
response_headers: response.headers.clone(),
response_body: SubresourceResponseBody::from_navigation_response(&response),
from_cache: response.from_cache,
cache_state: response.cache_state,
};
self._context_host
.borrow_mut()
@@ -588,6 +588,7 @@ fn parser_script_network_results_populate_buffered_resource_timing_snapshots() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"void 0;".to_owned(),
@@ -179,6 +179,7 @@ fn xhr_null_body_statuses_discard_buffered_and_streamed_bytes() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
if streaming {
@@ -344,6 +345,7 @@ fn xhr_null_body_late_completion_preserves_a_replacement_requests_progress() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -64,6 +64,7 @@ fn window_service_worker_response_filter_survives_streaming_clone_and_cache() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let response_filter = Some(if cors {
@@ -233,6 +234,7 @@ fn window_filtered_fetch_preserves_internal_head_through_clone_and_cache() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
if streaming {
@@ -57,6 +57,7 @@ fn redirect_filter_completion_keeps_status_text_and_explicit_filters() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"body".to_owned(),
@@ -35,6 +35,7 @@ fn xhr_response_headers_are_filtered_combined_and_sorted_before_events() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
if streaming {
@@ -1200,6 +1200,7 @@ fn xml_http_request_blob_response_uses_final_mime_type() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(b"body".to_vec()),
@@ -1300,6 +1301,7 @@ fn xml_http_request_default_response_type_parses_response_xml_for_document_mime(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(
@@ -1327,6 +1329,7 @@ fn xml_http_request_default_response_type_parses_response_xml_for_document_mime(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(b"plain text".to_vec()),
@@ -1405,6 +1408,7 @@ fn xml_http_request_response_document_uses_response_url_and_requester_origin() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(br#"<html xmlns="http://www.w3.org/1999/xhtml"><head><base href="../assets/" /></head><body><a id="link" href="child">link</a></body></html>"#.to_vec()),
@@ -1502,6 +1506,7 @@ fn xml_http_request_document_response_requires_an_eligible_mime_and_well_formed_
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
if streaming {
@@ -1656,6 +1661,7 @@ fn xhr_streamed_response_documents_keep_distinct_source_modification_times() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -1773,6 +1779,7 @@ fn xhr_response_decoding_uses_headers_received_overrides_for_buffered_and_stream
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
if streaming {
@@ -2958,6 +2965,7 @@ __streamingXhr.send();
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
@@ -3144,6 +3152,7 @@ async fn streaming_subresource_finish_preserves_response_head_cache_state() {
negotiated_http_version: None,
}],
from_cache: true,
cache_state: moli_fetch::ResponseCacheState::Local,
negotiated_http_version: None,
},
network_request_headers: None,
@@ -3424,6 +3433,7 @@ async fn streaming_fetch_body_error_records_response_started_then_body_failed()
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -3525,6 +3535,7 @@ fn install_streaming_fetch_response_fixture(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_source_id,
@@ -3587,6 +3598,7 @@ fn install_streaming_fetch_response_fixture(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -3699,6 +3711,7 @@ async fn streaming_fetch_body_cancel_aborts_streaming_subresource() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -4336,6 +4349,7 @@ async fn streaming_xhr_materialization_failure_errors_body_source_before_close()
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -655,6 +655,7 @@ async fn child_navigation_keeps_accepted_beacon_network_only_and_rejects_stale_s
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
})
@@ -325,6 +325,7 @@ async fn child_csp_report_keeps_exact_violation_document_without_v8_after_naviga
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
})
@@ -1967,6 +1967,7 @@ fn isolated_realm_destruction_aborts_fetch_and_detaches_keepalive() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
})
@@ -31,6 +31,7 @@ fn fetch_request_initializers_use_request_header_guards() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
vm.complete_async_subresource_fetch(crate::types::AsyncSubresourceFetchCompletion {
@@ -374,6 +374,7 @@ fn register_pending_window_fetch_for_test(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
network_request_headers: None,
@@ -357,6 +357,7 @@ fn external_script_redirect_final_url_obeys_script_src_csp() {
redirected: true,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"globalThis.__redirectScriptRan = true;".to_owned(),
@@ -725,6 +725,7 @@ fn response_clone_tees_pending_network_body_after_parent_consumption() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_source_id,
@@ -831,6 +832,7 @@ fn pending_fetch_body_pipe_through_text_decoder_stream_pulls_future_chunks() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
body_source_id,
@@ -954,6 +956,7 @@ fn materialize_response_object_preserves_redirected_slot() {
redirected: true,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
"redirected-body".to_owned(),
@@ -1336,6 +1339,7 @@ redirect_mode: moli_fetch::RequestRedirectMode::Follow,
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let id = crate::network_host::new_network_body_source_id();
@@ -1439,6 +1443,7 @@ fn opaque_window_fetch_keeps_blocked_bytes_out_of_internal_clone_consumers() {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
},
@@ -1551,6 +1556,7 @@ redirect_mode: moli_fetch::RequestRedirectMode::Follow, method: "GET", mode: mol
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
moli_fetch::ResponseBody::materialized_bytes(Vec::new()),
@@ -554,6 +554,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
@@ -950,6 +951,7 @@ mod tests {
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let mut resource =
@@ -115,6 +115,7 @@ fn service_worker_fetch_stream_response_head(
redirected: response_head.redirected || !job.request.redirect_chain().is_empty(),
redirect_chain: job.request.redirect_chain().to_vec(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
}
}
@@ -638,6 +639,7 @@ impl ServiceWorkerRuntimeService {
redirected: response.redirected || !job.request.redirect_chain().is_empty(),
redirect_chain: job.request.redirect_chain().to_vec(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
},
String::from_utf8_lossy(&response.body).into_owned(),
@@ -2677,6 +2677,7 @@ pub(in crate::worker) fn worker_response_from_body(
redirected: false,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
})
}
@@ -3088,6 +3089,7 @@ pub(in crate::worker) fn drain_worker_fetch_completion_result(
response_headers: response_head.headers.clone(),
response_body,
response_from_cache: response_head.from_cache,
response_cache_state: response_head.cache_state,
})
} else {
None
@@ -3122,6 +3124,7 @@ pub(in crate::worker) fn drain_worker_fetch_completion_result(
response_headers: response_head.headers.clone(),
response_body: response_body.clone(),
from_cache: response_head.from_cache,
cache_state: response_head.cache_state,
};
pending.paused_response = Some(PausedWorkerSubresourceResponse {
response_filter: completion.response_filter.clone(),
@@ -1069,6 +1069,7 @@ pub(in crate::worker) fn drain_worker_xhr_completion(
response_headers: response_head.headers.clone(),
response_body,
response_from_cache: response_head.from_cache,
response_cache_state: response_head.cache_state,
})
} else {
None
@@ -1104,6 +1105,7 @@ pub(in crate::worker) fn drain_worker_xhr_completion(
response_headers: response_head.headers.clone(),
response_body: response_body.clone(),
from_cache: response_head.from_cache,
cache_state: response_head.cache_state,
};
pending.paused_response = Some(PausedWorkerSubresourceResponse {
response_filter: None,
@@ -3446,6 +3446,7 @@ fn start_service_worker_navigation_preload_response_in_context(
redirected: started.response_head.redirected,
redirect_chain: Vec::new(),
from_cache: false,
cache_state: Default::default(),
negotiated_http_version: None,
};
let response_object = build_navigation_preload_response_object_from_stream_for_request_mode(