diff --git a/src/runtime/action.rs b/src/runtime/action.rs
index 1ceb9b4..05c75d5 100644
--- a/src/runtime/action.rs
+++ b/src/runtime/action.rs
@@ -1633,7 +1633,7 @@ drop.addEventListener('dragover', e=>e.preventDefault()); drop.addEventListener(
const root=document.querySelector('#shadow').attachShadow({{mode:'open'}}); root.innerHTML=``;
root.querySelector('button').onclick=()=>window.shadowClicked=true;
-"#
+"#
);
let parent_server = tokio::spawn(serve_live_locator_fixture(
parent_listener,
@@ -1649,14 +1649,13 @@ root.querySelector('button').onclick=()=>window.shadowClicked=true;
let runtime = BrowserRuntime::launch(
LaunchOptions::default()
.headless(true)
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
)
.await
.unwrap();
let session = runtime.default_session().await.unwrap();
let page = session
- .new_page(format!("http://parent.test:{parent_port}/"))
+ .new_page(format!("http://127.0.0.1:{parent_port}/"))
.await
.unwrap();
tokio::time::timeout(Duration::from_secs(5), async {
diff --git a/src/runtime/artifact.rs b/src/runtime/artifact.rs
index 57a65f1..44c3e37 100644
--- a/src/runtime/artifact.rs
+++ b/src/runtime/artifact.rs
@@ -2793,7 +2793,7 @@ mod tests {
let child_body = "
".to_owned();
let nested_body = "".to_owned();
let parent_body = format!(
- r#""#
+ r#""#
);
let parent_server = tokio::spawn(serve_artifact_fixture(
parent_listener,
@@ -2809,7 +2809,6 @@ mod tests {
LaunchOptions::default()
.headless(true)
.arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1")
.arg(explicitly_allowed_ports_arg([
parent_address.port(),
child_address.port(),
@@ -2823,7 +2822,7 @@ mod tests {
let initial_epoch = initial_main.document_epoch();
let initial_generation = page.generation();
let mut events = page.subscribe_events().await.unwrap();
- let target_url = format!("http://parent.test:{parent_port}/");
+ let target_url = format!("http://127.0.0.1:{parent_port}/");
let navigation = page.goto(target_url.as_str()).await.unwrap();
assert_eq!(navigation.final_url(), target_url);
let committed = tokio::time::timeout(std::time::Duration::from_secs(8), async {
diff --git a/src/runtime/evaluate.rs b/src/runtime/evaluate.rs
index f8ca943..7242ef5 100644
--- a/src/runtime/evaluate.rs
+++ b/src/runtime/evaluate.rs
@@ -1295,7 +1295,7 @@ mod tests {
let parent_port = parent_listener.local_addr().unwrap().port();
let parent_body = format!(
r#"
- "#
+ "#
);
let same_body = "".to_owned();
let oopif_body = "".to_owned();
@@ -1313,14 +1313,13 @@ mod tests {
let runtime = BrowserRuntime::launch(
LaunchOptions::default()
.headless(true)
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
)
.await
.unwrap();
let session = runtime.default_session().await.unwrap();
let page = session
- .new_page(format!("http://parent.test:{parent_port}/"))
+ .new_page(format!("http://127.0.0.1:{parent_port}/"))
.await
.unwrap();
let main = page.main_frame().await.unwrap();
diff --git a/src/runtime/frame.rs b/src/runtime/frame.rs
index 2a3f06a..59847fa 100644
--- a/src/runtime/frame.rs
+++ b/src/runtime/frame.rs
@@ -6281,7 +6281,7 @@ mod tests {
let child_server = tokio::spawn(serve_fixture(
child_listener,
format!(
- r#"child"#
+ r#"child"#
),
));
let grandchild_server = tokio::spawn(serve_fixture(
@@ -6291,21 +6291,20 @@ mod tests {
let parent_server = tokio::spawn(serve_fixture(
parent_listener,
format!(
- r#""#
+ r#""#
),
));
let runtime = BrowserRuntime::launch(
LaunchOptions::default()
.headless(true)
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
)
.await
.expect("launch Chrome");
let session = runtime.default_session().await.expect("default session");
let page = session
- .new_page(format!("http://parent.test:{parent_port}/"))
+ .new_page(format!("http://127.0.0.1:{parent_port}/"))
.await
.expect("open fixture");
let main = page.main_frame().await.expect("main frame");
diff --git a/src/runtime/locator/resolver.rs b/src/runtime/locator/resolver.rs
index ac4812e..5d556fa 100644
--- a/src/runtime/locator/resolver.rs
+++ b/src/runtime/locator/resolver.rs
@@ -1274,7 +1274,7 @@ pub(crate) mod tests {
closedRoot.innerHTML = ``;
-"#
+"#
);
let parent_server = tokio::spawn(serve_live_locator_fixture(
parent_listener,
@@ -1290,14 +1290,13 @@ pub(crate) mod tests {
let runtime = BrowserRuntime::launch(
LaunchOptions::default()
.headless(true)
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
)
.await
.expect("launch private Chrome");
let session = runtime.default_session().await.expect("default session");
let page = session
- .new_page(format!("http://parent.test:{parent_port}/"))
+ .new_page(format!("http://127.0.0.1:{parent_port}/"))
.await
.expect("open locator fixture");
let main = page.main_frame().await.expect("main frame");
@@ -1508,7 +1507,7 @@ pub(crate) mod tests {
let stale_document = page.locator("#text-only");
cdpkit::page::methods::Navigate::new(format!(
- "http://parent.test:{parent_port}/?replacement"
+ "http://127.0.0.1:{parent_port}/?replacement"
))
.send(page.cdp_session())
.await
diff --git a/src/runtime/snapshot.rs b/src/runtime/snapshot.rs
index 840bf70..a677bac 100644
--- a/src/runtime/snapshot.rs
+++ b/src/runtime/snapshot.rs
@@ -1589,7 +1589,7 @@ const shadow = document.querySelector('#shadow').attachShadow({{mode:'open'}});
shadow.innerHTML = '';
document.querySelector('#focused').focus();
-"#,
+"#,
"X".repeat(8_192)
);
let parent_server = tokio::spawn(serve_fixture(parent_listener, parent, child.clone()));
@@ -1597,8 +1597,7 @@ document.querySelector('#focused').focus();
let runtime = BrowserRuntime::launch(
LaunchOptions::default()
.headless(true)
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
)
.await
.unwrap();
@@ -1606,7 +1605,7 @@ document.querySelector('#focused').focus();
.default_session()
.await
.unwrap()
- .new_page(format!("http://parent.test:{parent_port}/"))
+ .new_page(format!("http://127.0.0.1:{parent_port}/"))
.await
.unwrap();
tokio::time::timeout(Duration::from_secs(5), async {
@@ -1756,7 +1755,7 @@ document.querySelector('#focused').focus();
);
}
cdpkit::page::methods::Navigate::new(format!(
- "http://parent.test:{parent_port}/?replacement"
+ "http://127.0.0.1:{parent_port}/?replacement"
))
.send(page.cdp_session())
.await
diff --git a/src/runtime/storage.rs b/src/runtime/storage.rs
index 742b048..d41f28d 100644
--- a/src/runtime/storage.rs
+++ b/src/runtime/storage.rs
@@ -1639,73 +1639,30 @@ mod tests {
(port, task)
}
- #[tokio::test]
- #[ignore = "requires installed Chrome and loopback sockets"]
- async fn live_chrome_storage_routes_contexts_origins_frames_and_page_session_storage() {
- let (second_port, second_server) = start_http_fixture(|path| match path {
- "/oopif" => "oopif leafoopif storage".into(),
- _ => format!(
- "second storagesecond storage for {path}"
- ),
- })
- .await;
- let (first_port, first_server) = start_http_fixture(move |path| match path {
- "/page-one" => format!(
- "page one"
- ),
- "/same" => "same leafsame storage".into(),
- _ => format!(
- "first storagefirst storage for {path}"
- ),
- })
- .await;
- let runtime = super::super::BrowserRuntime::launch(
- super::super::LaunchOptions::default()
- .headless(true)
- .arg("--site-per-process"),
- )
- .await
- .unwrap();
- let default_session = runtime.default_session().await.unwrap();
- let default_url = format!("http://127.0.0.1:{first_port}/default");
- let default_page = default_session.new_page("about:blank").await.unwrap();
- fence_live_document(&default_page, &default_url).await;
- default_page
- .local_storage()
- .set("default-sentinel", "preserve")
- .await
- .unwrap();
- default_session
- .set_cookie(
- BrowserCookie::new("default-sentinel", "preserve")
- .url(format!("http://127.0.0.1:{first_port}/")),
- )
- .await
- .unwrap();
- let session = runtime
- .isolated_session(super::super::IsolatedSessionOptions::default())
- .await
- .unwrap();
- let page_one_url = format!("http://127.0.0.1:{first_port}/page-one");
- let same_frame_url = format!("http://127.0.0.1:{first_port}/same");
- let oopif_frame_url = format!("http://localhost:{second_port}/oopif");
- let page_one = session.new_page("about:blank").await.unwrap();
- let mut page_one_events = page_one.subscribe_events().await.unwrap();
- fence_live_document(&page_one, &page_one_url).await;
- let page_two_url = format!("http://127.0.0.1:{second_port}/");
- let page_two = session.new_page("about:blank").await.unwrap();
- fence_live_document(&page_two, &page_two_url).await;
- let page_same_origin_url = format!("http://127.0.0.1:{first_port}/other");
- let page_same_origin = session.new_page("about:blank").await.unwrap();
- fence_live_document(&page_same_origin, &page_same_origin_url).await;
- let other_session = runtime
- .isolated_session(super::super::IsolatedSessionOptions::default())
- .await
- .unwrap();
- let other_page_url = format!("http://127.0.0.1:{first_port}/other-context");
- let other_page = other_session.new_page("about:blank").await.unwrap();
- fence_live_document(&other_page, &other_page_url).await;
+ struct LiveStorageScopes<'a> {
+ default_session: &'a BrowserSession,
+ default_page: &'a Page,
+ session: &'a BrowserSession,
+ page_one: &'a Page,
+ page_two: &'a Page,
+ page_same_origin: &'a Page,
+ other_session: &'a BrowserSession,
+ other_page: &'a Page,
+ first_port: u16,
+ }
+ async fn assert_context_and_page_storage(scopes: LiveStorageScopes<'_>) {
+ let LiveStorageScopes {
+ default_session,
+ default_page,
+ session,
+ page_one,
+ page_two,
+ page_same_origin,
+ other_session,
+ other_page,
+ first_port,
+ } = scopes;
page_one
.local_storage()
.set("context", "one")
@@ -1831,376 +1788,9 @@ mod tests {
.as_deref(),
Some("other")
);
+ }
- let main = page_one.main_frame().await.unwrap();
- let main_frame_id = main.id().as_str().to_owned();
- let main_session = main.cdp_session().await.unwrap().id().to_owned();
- let route_deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(5);
- let (oopif_frame_id, old_oopif_session, new_oopif_session, oopif_target_id) = loop {
- let envelope = tokio::time::timeout_at(route_deadline, page_one_events.next())
- .await
- .unwrap_or_else(|_| panic!("deadline waiting for the OOPIF FrameRouteChanged"))
- .expect("page-one event stream closed before the OOPIF route changed")
- .unwrap_or_else(|error| {
- panic!("page-one event stream failed before the OOPIF route changed: {error}")
- });
- match envelope.into_event() {
- super::super::PageEvent::FrameRouteChanged {
- frame_id,
- previous_session_id,
- session_id,
- target_id: Some(target_id),
- } if session_id != main_session => {
- break (
- frame_id.as_str().to_owned(),
- previous_session_id,
- session_id,
- target_id,
- );
- }
- _ => {}
- }
- };
- assert!(
- !oopif_target_id.is_empty(),
- "OOPIF route event must identify its target"
- );
-
- let frames = page_one.frames().await.unwrap();
- let active_frames = frames
- .into_iter()
- .map(|frame| (frame.id().as_str().to_owned(), frame))
- .collect::>();
- assert_eq!(
- active_frames.len(),
- 3,
- "page-one must have exactly its main frame and the two fixture leaf frames"
- );
- assert!(
- active_frames.contains_key(&main_frame_id),
- "active frame snapshot must contain the main frame"
- );
- let oopif_frame = active_frames
- .get(&oopif_frame_id)
- .expect("OOPIF route event must identify an active frame")
- .clone();
- let mut same_frames = active_frames
- .iter()
- .filter(|(frame_id, _)| {
- frame_id.as_str() != main_frame_id && frame_id.as_str() != oopif_frame_id
- })
- .map(|(_, frame)| frame.clone());
- let same_frame = same_frames
- .next()
- .expect("active frame snapshot must contain the same-process child");
- assert!(
- same_frames.next().is_none(),
- "active frame snapshot must contain only one same-process child"
- );
- let same_parent = same_frame.parent().await.unwrap().unwrap();
- let oopif_parent = oopif_frame.parent().await.unwrap().unwrap();
- assert_eq!(same_parent.id().as_str(), main_frame_id);
- assert_eq!(oopif_parent.id().as_str(), main_frame_id);
- assert_eq!(same_parent.id(), oopif_parent.id());
-
- let same_session = same_frame.cdp_session().await.unwrap().id().to_owned();
- let oopif_session = oopif_frame.cdp_session().await.unwrap().id().to_owned();
- assert_eq!(same_session, main_session);
- assert_eq!(old_oopif_session, main_session);
- assert_eq!(oopif_session, new_oopif_session);
- assert_ne!(oopif_session, main_session);
-
- let same_location: Value = same_frame
- .evaluate("({url: location.href, origin: location.origin})")
- .await
- .unwrap();
- let oopif_location: Value = oopif_frame
- .evaluate("({url: location.href, origin: location.origin})")
- .await
- .unwrap();
- assert_eq!(
- same_location,
- json!({
- "url": same_frame_url,
- "origin": format!("http://127.0.0.1:{first_port}"),
- })
- );
- assert_eq!(
- oopif_location,
- json!({
- "url": oopif_frame_url,
- "origin": format!("http://localhost:{second_port}"),
- })
- );
-
- let children = [same_frame, oopif_frame];
- for (index, child) in children.iter().enumerate() {
- child
- .local_storage()
- .set("frame", format!("child-{index}"))
- .await
- .unwrap();
- assert_eq!(
- child.local_storage().get("frame").await.unwrap().as_deref(),
- Some(format!("child-{index}").as_str())
- );
- child
- .session_storage()
- .set("frame-session", format!("child-{index}"))
- .await
- .unwrap();
- assert_eq!(
- child
- .session_storage()
- .get("frame-session")
- .await
- .unwrap()
- .as_deref(),
- Some(format!("child-{index}").as_str())
- );
- }
-
- let exported = session
- .export_auth_state(&[page_two.clone(), page_one.clone()])
- .await
- .unwrap();
- assert_eq!(exported.origins().len(), 2);
- assert!(exported
- .origins()
- .windows(2)
- .all(|pair| pair[0].origin() < pair[1].origin()));
- page_one.local_storage().clear().await.unwrap();
- page_two.local_storage().clear().await.unwrap();
- session
- .import_auth_state(
- &exported,
- AuthStateImport::new(AuthImportMode::Merge)
- .page(page_one.clone())
- .page(page_two.clone()),
- )
- .await
- .unwrap();
- assert_eq!(
- page_one
- .local_storage()
- .get("one")
- .await
- .unwrap()
- .as_deref(),
- Some("value-one")
- );
- assert_eq!(
- page_two
- .local_storage()
- .get("two")
- .await
- .unwrap()
- .as_deref(),
- Some("value-two")
- );
- page_one
- .local_storage()
- .set("extra", "remove-me")
- .await
- .unwrap();
- session
- .set_cookie(
- BrowserCookie::new("extra", "remove-me")
- .url(format!("http://127.0.0.1:{first_port}/")),
- )
- .await
- .unwrap();
- session
- .import_auth_state(
- &exported,
- AuthStateImport::new(AuthImportMode::ReplaceAuthScope)
- .page(page_one.clone())
- .page(page_two.clone()),
- )
- .await
- .unwrap();
- assert_eq!(page_one.local_storage().get("extra").await.unwrap(), None);
- assert_eq!(
- page_one
- .local_storage()
- .get("one")
- .await
- .unwrap()
- .as_deref(),
- Some("value-one")
- );
- let replaced_cookies = session.cookies().await.unwrap();
- assert!(!replaced_cookies
- .iter()
- .any(|cookie| cookie.name() == "extra"));
- assert!(replaced_cookies
- .iter()
- .any(|cookie| cookie.name() == "context-cookie" && cookie.value() == "one"));
-
- let origin = format!("http://127.0.0.1:{first_port}");
- session
- .set_cookies(vec![
- BrowserCookie::new("sid", "delete-me")
- .url(format!("{origin}/app"))
- .path("/app"),
- BrowserCookie::new("sid", "keep-me")
- .url(format!("{origin}/other"))
- .path("/other"),
- ])
- .await
- .unwrap();
- let exact = session
- .cookies()
- .await
- .unwrap()
- .into_iter()
- .find(|cookie| cookie.name() == "sid" && cookie.path_value() == Some("/app"))
- .unwrap();
- session
- .delete_cookie(
- CookieDeletion::new("sid")
- .domain(exact.domain_value().unwrap())
- .path("/app"),
- )
- .await
- .unwrap();
- let remaining = session.cookies().await.unwrap();
- assert!(!remaining
- .iter()
- .any(|cookie| cookie.name() == "sid" && cookie.path_value() == Some("/app")));
- assert!(remaining.iter().any(|cookie| cookie.name() == "sid"
- && cookie.path_value() == Some("/other")
- && cookie.value() == "keep-me"));
-
- session
- .set_cookies(vec![
- BrowserCookie::new("host-neighbor", "delete-host")
- .url(format!("{origin}/scope"))
- .path("/scope"),
- BrowserCookie::new("host-neighbor", "keep-localhost")
- .url(format!("http://localhost:{second_port}/scope"))
- .path("/scope"),
- ])
- .await
- .unwrap();
- let host_cookie = session
- .cookies()
- .await
- .unwrap()
- .into_iter()
- .find(|cookie| cookie.name() == "host-neighbor" && cookie.value() == "delete-host")
- .unwrap();
- session
- .delete_cookie(
- CookieDeletion::new("host-neighbor")
- .domain(host_cookie.domain_value().unwrap())
- .path("/scope"),
- )
- .await
- .unwrap();
- let host_remaining = session.cookies().await.unwrap();
- assert!(!host_remaining
- .iter()
- .any(|cookie| cookie.name() == "host-neighbor" && cookie.value() == "delete-host"));
- assert!(host_remaining
- .iter()
- .any(|cookie| cookie.name() == "host-neighbor" && cookie.value() == "keep-localhost"));
-
- let closed_page = session
- .new_page(format!("{origin}/closed-preflight"))
- .await
- .unwrap();
- let closed_page_report = closed_page.close().await;
- assert!(
- closed_page_report.is_complete(),
- "closed-page cleanup failures: {:#?}; report: {closed_page_report:#?}",
- closed_page_report.failures()
- );
- let preflight_state = AuthenticationState::from_parts(
- vec![BrowserCookie::new("must-not-apply", "secret").url(format!("{origin}/"))],
- vec![OriginStorageState::new(origin.clone(), Vec::new())],
- );
- let preflight_error = session
- .import_auth_state(
- &preflight_state,
- AuthStateImport::new(AuthImportMode::Merge).page(closed_page),
- )
- .await
- .unwrap_err();
- assert_eq!(
- preflight_error.action_completed(),
- ActionCompletion::NotStarted
- );
- assert!(!session
- .cookies()
- .await
- .unwrap()
- .iter()
- .any(|cookie| cookie.name() == "must-not-apply"));
-
- let partial_state = AuthenticationState::from_parts(
- vec![BrowserCookie::new("partial-cookie", "applied").url(format!("{origin}/"))],
- vec![
- OriginStorageState::new(
- origin.clone(),
- (0..2_000)
- .map(|index| StorageEntry::new(format!("batch-{index}"), "value"))
- .collect(),
- ),
- OriginStorageState::new(
- format!("http://127.0.0.1:{second_port}"),
- vec![StorageEntry::new("must-not-land", "secret")],
- ),
- ],
- );
- let import_session = session.clone();
- let import_page_one = page_one.clone();
- let import_page_two = page_two.clone();
- let import = tokio::spawn(async move {
- import_session
- .import_auth_state(
- &partial_state,
- AuthStateImport::new(AuthImportMode::Merge)
- .page(import_page_one)
- .page(import_page_two),
- )
- .await
- });
- tokio::time::timeout(std::time::Duration::from_secs(5), async {
- loop {
- if session
- .cookies()
- .await
- .unwrap()
- .iter()
- .any(|cookie| cookie.name() == "partial-cookie")
- {
- break;
- }
- tokio::task::yield_now().await;
- }
- })
- .await
- .unwrap();
- page_two
- .goto(format!("http://127.0.0.1:{second_port}/invalidate-import"))
- .await
- .unwrap();
- let partial_error = import.await.unwrap().unwrap_err();
- assert_eq!(partial_error.action_completed(), ActionCompletion::Unknown);
- assert!(partial_error.to_string().contains("mutation batches"));
- assert!(!partial_error.to_string().contains("secret"));
- assert!(session
- .cookies()
- .await
- .unwrap()
- .iter()
- .any(|cookie| cookie.name() == "partial-cookie" && cookie.value() == "applied"));
- session
- .delete_cookie(CookieDeletion::new("partial-cookie").url(format!("{origin}/")))
- .await
- .unwrap();
-
+ async fn assert_partitioned_cookie_lifecycle(session: &BrowserSession, origin: &str) {
let partition = CookiePartitionKey {
top_level_site: "http://127.0.0.1".into(),
has_cross_site_ancestor: false,
@@ -2242,7 +1832,16 @@ mod tests {
assert_eq!(error.storage_failure(), Some(&StorageFailure::Unsupported));
}
}
+ }
+ async fn close_live_storage_fixture(
+ runtime: super::super::BrowserRuntime,
+ default_session: BrowserSession,
+ session: BrowserSession,
+ other_session: BrowserSession,
+ first_server: tokio::task::JoinHandle<()>,
+ second_server: tokio::task::JoinHandle<()>,
+ ) {
let cleanup_session = runtime
.isolated_session(
super::super::IsolatedSessionOptions::default().close_pages_before_context(true),
@@ -2285,4 +1884,483 @@ mod tests {
first_server.abort();
second_server.abort();
}
+
+ #[tokio::test]
+ #[ignore = "requires installed Chrome and loopback sockets"]
+ async fn live_chrome_storage_routes_contexts_origins_frames_and_page_session_storage() {
+ Box::pin(live_chrome_storage_scenario()).await;
+ }
+
+ async fn live_chrome_storage_scenario() {
+ let (second_port, second_server) = start_http_fixture(|path| match path {
+ "/oopif" => "oopif leafoopif storage".into(),
+ _ => format!(
+ "second storagesecond storage for {path}"
+ ),
+ })
+ .await;
+ let (first_port, first_server) = start_http_fixture(move |path| match path {
+ "/page-one" => format!(
+ "page one"
+ ),
+ "/same" => "same leafsame storage".into(),
+ _ => format!(
+ "first storagefirst storage for {path}"
+ ),
+ })
+ .await;
+ let runtime = super::super::BrowserRuntime::launch(
+ super::super::LaunchOptions::default()
+ .headless(true)
+ .arg("--site-per-process"),
+ )
+ .await
+ .unwrap();
+ let default_session = runtime.default_session().await.unwrap();
+ let default_url = format!("http://127.0.0.1:{first_port}/default");
+ let default_page = default_session.new_page("about:blank").await.unwrap();
+ fence_live_document(&default_page, &default_url).await;
+ default_page
+ .local_storage()
+ .set("default-sentinel", "preserve")
+ .await
+ .unwrap();
+ default_session
+ .set_cookie(
+ BrowserCookie::new("default-sentinel", "preserve")
+ .url(format!("http://127.0.0.1:{first_port}/")),
+ )
+ .await
+ .unwrap();
+ let session = runtime
+ .isolated_session(super::super::IsolatedSessionOptions::default())
+ .await
+ .unwrap();
+ let page_one_url = format!("http://127.0.0.1:{first_port}/page-one");
+ let same_frame_url = format!("http://127.0.0.1:{first_port}/same");
+ let oopif_frame_url = format!("http://localhost:{second_port}/oopif");
+ let page_one = session.new_page("about:blank").await.unwrap();
+ let mut page_one_events = page_one.subscribe_events().await.unwrap();
+ fence_live_document(&page_one, &page_one_url).await;
+ let page_two_url = format!("http://127.0.0.1:{second_port}/");
+ let page_two = session.new_page("about:blank").await.unwrap();
+ fence_live_document(&page_two, &page_two_url).await;
+ let page_same_origin_url = format!("http://127.0.0.1:{first_port}/other");
+ let page_same_origin = session.new_page("about:blank").await.unwrap();
+ fence_live_document(&page_same_origin, &page_same_origin_url).await;
+ let other_session = runtime
+ .isolated_session(super::super::IsolatedSessionOptions::default())
+ .await
+ .unwrap();
+ let other_page_url = format!("http://127.0.0.1:{first_port}/other-context");
+ let other_page = other_session.new_page("about:blank").await.unwrap();
+ fence_live_document(&other_page, &other_page_url).await;
+
+ Box::pin(assert_context_and_page_storage(LiveStorageScopes {
+ default_session: &default_session,
+ default_page: &default_page,
+ session: &session,
+ page_one: &page_one,
+ page_two: &page_two,
+ page_same_origin: &page_same_origin,
+ other_session: &other_session,
+ other_page: &other_page,
+ first_port,
+ }))
+ .await;
+
+ Box::pin(async {
+ let main = page_one.main_frame().await.unwrap();
+ let main_frame_id = main.id().as_str().to_owned();
+ let main_session = main.cdp_session().await.unwrap().id().to_owned();
+ let route_deadline = tokio::time::Instant::now() + std::time::Duration::from_secs(5);
+ let (oopif_frame_id, old_oopif_session, new_oopif_session, oopif_target_id) =
+ loop {
+ let envelope = tokio::time::timeout_at(route_deadline, page_one_events.next())
+ .await
+ .unwrap_or_else(|_| panic!("deadline waiting for the OOPIF FrameRouteChanged"))
+ .expect("page-one event stream closed before the OOPIF route changed")
+ .unwrap_or_else(|error| {
+ panic!("page-one event stream failed before the OOPIF route changed: {error}")
+ });
+ match envelope.into_event() {
+ super::super::PageEvent::FrameRouteChanged {
+ frame_id,
+ previous_session_id,
+ session_id,
+ target_id: Some(target_id),
+ } if session_id != main_session => {
+ break (
+ frame_id.as_str().to_owned(),
+ previous_session_id,
+ session_id,
+ target_id,
+ );
+ }
+ _ => {}
+ }
+ };
+ assert!(
+ !oopif_target_id.is_empty(),
+ "OOPIF route event must identify its target"
+ );
+
+ let frames = page_one.frames().await.unwrap();
+ let active_frames = frames
+ .into_iter()
+ .map(|frame| (frame.id().as_str().to_owned(), frame))
+ .collect::>();
+ assert_eq!(
+ active_frames.len(),
+ 3,
+ "page-one must have exactly its main frame and the two fixture leaf frames"
+ );
+ assert!(
+ active_frames.contains_key(&main_frame_id),
+ "active frame snapshot must contain the main frame"
+ );
+ let oopif_frame = active_frames
+ .get(&oopif_frame_id)
+ .expect("OOPIF route event must identify an active frame")
+ .clone();
+ let mut same_frames = active_frames
+ .iter()
+ .filter(|(frame_id, _)| {
+ frame_id.as_str() != main_frame_id && frame_id.as_str() != oopif_frame_id
+ })
+ .map(|(_, frame)| frame.clone());
+ let same_frame = same_frames
+ .next()
+ .expect("active frame snapshot must contain the same-process child");
+ assert!(
+ same_frames.next().is_none(),
+ "active frame snapshot must contain only one same-process child"
+ );
+ let same_parent = same_frame.parent().await.unwrap().unwrap();
+ let oopif_parent = oopif_frame.parent().await.unwrap().unwrap();
+ assert_eq!(same_parent.id().as_str(), main_frame_id);
+ assert_eq!(oopif_parent.id().as_str(), main_frame_id);
+ assert_eq!(same_parent.id(), oopif_parent.id());
+
+ let same_session = same_frame.cdp_session().await.unwrap().id().to_owned();
+ let oopif_session = oopif_frame.cdp_session().await.unwrap().id().to_owned();
+ assert_eq!(same_session, main_session);
+ assert_eq!(old_oopif_session, main_session);
+ assert_eq!(oopif_session, new_oopif_session);
+ assert_ne!(oopif_session, main_session);
+
+ let same_location: Value = same_frame
+ .evaluate("({url: location.href, origin: location.origin})")
+ .await
+ .unwrap();
+ let oopif_location: Value = oopif_frame
+ .evaluate("({url: location.href, origin: location.origin})")
+ .await
+ .unwrap();
+ assert_eq!(
+ same_location,
+ json!({
+ "url": same_frame_url,
+ "origin": format!("http://127.0.0.1:{first_port}"),
+ })
+ );
+ assert_eq!(
+ oopif_location,
+ json!({
+ "url": oopif_frame_url,
+ "origin": format!("http://localhost:{second_port}"),
+ })
+ );
+
+ let children = [same_frame, oopif_frame];
+ for (index, child) in children.iter().enumerate() {
+ child
+ .local_storage()
+ .set("frame", format!("child-{index}"))
+ .await
+ .unwrap();
+ assert_eq!(
+ child.local_storage().get("frame").await.unwrap().as_deref(),
+ Some(format!("child-{index}").as_str())
+ );
+ child
+ .session_storage()
+ .set("frame-session", format!("child-{index}"))
+ .await
+ .unwrap();
+ assert_eq!(
+ child
+ .session_storage()
+ .get("frame-session")
+ .await
+ .unwrap()
+ .as_deref(),
+ Some(format!("child-{index}").as_str())
+ );
+ }
+ })
+ .await;
+
+ Box::pin(async {
+ let exported = session
+ .export_auth_state(&[page_two.clone(), page_one.clone()])
+ .await
+ .unwrap();
+ assert_eq!(exported.origins().len(), 2);
+ assert!(exported
+ .origins()
+ .windows(2)
+ .all(|pair| pair[0].origin() < pair[1].origin()));
+ page_one.local_storage().clear().await.unwrap();
+ page_two.local_storage().clear().await.unwrap();
+ session
+ .import_auth_state(
+ &exported,
+ AuthStateImport::new(AuthImportMode::Merge)
+ .page(page_one.clone())
+ .page(page_two.clone()),
+ )
+ .await
+ .unwrap();
+ assert_eq!(
+ page_one
+ .local_storage()
+ .get("one")
+ .await
+ .unwrap()
+ .as_deref(),
+ Some("value-one")
+ );
+ assert_eq!(
+ page_two
+ .local_storage()
+ .get("two")
+ .await
+ .unwrap()
+ .as_deref(),
+ Some("value-two")
+ );
+ page_one
+ .local_storage()
+ .set("extra", "remove-me")
+ .await
+ .unwrap();
+ session
+ .set_cookie(
+ BrowserCookie::new("extra", "remove-me")
+ .url(format!("http://127.0.0.1:{first_port}/")),
+ )
+ .await
+ .unwrap();
+ session
+ .import_auth_state(
+ &exported,
+ AuthStateImport::new(AuthImportMode::ReplaceAuthScope)
+ .page(page_one.clone())
+ .page(page_two.clone()),
+ )
+ .await
+ .unwrap();
+ assert_eq!(page_one.local_storage().get("extra").await.unwrap(), None);
+ assert_eq!(
+ page_one
+ .local_storage()
+ .get("one")
+ .await
+ .unwrap()
+ .as_deref(),
+ Some("value-one")
+ );
+ let replaced_cookies = session.cookies().await.unwrap();
+ assert!(!replaced_cookies
+ .iter()
+ .any(|cookie| cookie.name() == "extra"));
+ assert!(replaced_cookies
+ .iter()
+ .any(|cookie| cookie.name() == "context-cookie" && cookie.value() == "one"));
+ })
+ .await;
+
+ let origin = format!("http://127.0.0.1:{first_port}");
+ Box::pin(async {
+ session
+ .set_cookies(vec![
+ BrowserCookie::new("sid", "delete-me")
+ .url(format!("{origin}/app"))
+ .path("/app"),
+ BrowserCookie::new("sid", "keep-me")
+ .url(format!("{origin}/other"))
+ .path("/other"),
+ ])
+ .await
+ .unwrap();
+ let exact = session
+ .cookies()
+ .await
+ .unwrap()
+ .into_iter()
+ .find(|cookie| cookie.name() == "sid" && cookie.path_value() == Some("/app"))
+ .unwrap();
+ session
+ .delete_cookie(
+ CookieDeletion::new("sid")
+ .domain(exact.domain_value().unwrap())
+ .path("/app"),
+ )
+ .await
+ .unwrap();
+ let remaining = session.cookies().await.unwrap();
+ assert!(!remaining
+ .iter()
+ .any(|cookie| cookie.name() == "sid" && cookie.path_value() == Some("/app")));
+ assert!(remaining.iter().any(|cookie| cookie.name() == "sid"
+ && cookie.path_value() == Some("/other")
+ && cookie.value() == "keep-me"));
+
+ session
+ .set_cookies(vec![
+ BrowserCookie::new("host-neighbor", "delete-host")
+ .url(format!("{origin}/scope"))
+ .path("/scope"),
+ BrowserCookie::new("host-neighbor", "keep-localhost")
+ .url(format!("http://localhost:{second_port}/scope"))
+ .path("/scope"),
+ ])
+ .await
+ .unwrap();
+ let host_cookie = session
+ .cookies()
+ .await
+ .unwrap()
+ .into_iter()
+ .find(|cookie| cookie.name() == "host-neighbor" && cookie.value() == "delete-host")
+ .unwrap();
+ session
+ .delete_cookie(
+ CookieDeletion::new("host-neighbor")
+ .domain(host_cookie.domain_value().unwrap())
+ .path("/scope"),
+ )
+ .await
+ .unwrap();
+ let host_remaining = session.cookies().await.unwrap();
+ assert!(!host_remaining
+ .iter()
+ .any(|cookie| cookie.name() == "host-neighbor" && cookie.value() == "delete-host"));
+ assert!(host_remaining.iter().any(
+ |cookie| cookie.name() == "host-neighbor" && cookie.value() == "keep-localhost"
+ ));
+ })
+ .await;
+
+ Box::pin(async {
+ let closed_page = session
+ .new_page(format!("{origin}/closed-preflight"))
+ .await
+ .unwrap();
+ let closed_page_report = closed_page.close().await;
+ assert!(
+ closed_page_report.is_complete(),
+ "closed-page cleanup failures: {:#?}; report: {closed_page_report:#?}",
+ closed_page_report.failures()
+ );
+ let preflight_state = AuthenticationState::from_parts(
+ vec![BrowserCookie::new("must-not-apply", "secret").url(format!("{origin}/"))],
+ vec![OriginStorageState::new(origin.clone(), Vec::new())],
+ );
+ let preflight_error = session
+ .import_auth_state(
+ &preflight_state,
+ AuthStateImport::new(AuthImportMode::Merge).page(closed_page),
+ )
+ .await
+ .unwrap_err();
+ assert_eq!(
+ preflight_error.action_completed(),
+ ActionCompletion::NotStarted
+ );
+ assert!(!session
+ .cookies()
+ .await
+ .unwrap()
+ .iter()
+ .any(|cookie| cookie.name() == "must-not-apply"));
+
+ let partial_state = AuthenticationState::from_parts(
+ vec![BrowserCookie::new("partial-cookie", "applied").url(format!("{origin}/"))],
+ vec![
+ OriginStorageState::new(
+ origin.clone(),
+ (0..2_000)
+ .map(|index| StorageEntry::new(format!("batch-{index}"), "value"))
+ .collect(),
+ ),
+ OriginStorageState::new(
+ format!("http://127.0.0.1:{second_port}"),
+ vec![StorageEntry::new("must-not-land", "secret")],
+ ),
+ ],
+ );
+ let import_session = session.clone();
+ let import_page_one = page_one.clone();
+ let import_page_two = page_two.clone();
+ let import = tokio::spawn(async move {
+ import_session
+ .import_auth_state(
+ &partial_state,
+ AuthStateImport::new(AuthImportMode::Merge)
+ .page(import_page_one)
+ .page(import_page_two),
+ )
+ .await
+ });
+ tokio::time::timeout(std::time::Duration::from_secs(5), async {
+ loop {
+ if session
+ .cookies()
+ .await
+ .unwrap()
+ .iter()
+ .any(|cookie| cookie.name() == "partial-cookie")
+ {
+ break;
+ }
+ tokio::task::yield_now().await;
+ }
+ })
+ .await
+ .unwrap();
+ page_two
+ .goto(format!("http://127.0.0.1:{second_port}/invalidate-import"))
+ .await
+ .unwrap();
+ let partial_error = import.await.unwrap().unwrap_err();
+ assert_eq!(partial_error.action_completed(), ActionCompletion::Unknown);
+ assert!(partial_error.to_string().contains("mutation batches"));
+ assert!(!partial_error.to_string().contains("secret"));
+ assert!(session
+ .cookies()
+ .await
+ .unwrap()
+ .iter()
+ .any(|cookie| cookie.name() == "partial-cookie" && cookie.value() == "applied"));
+ session
+ .delete_cookie(CookieDeletion::new("partial-cookie").url(format!("{origin}/")))
+ .await
+ .unwrap();
+ })
+ .await;
+
+ Box::pin(assert_partitioned_cookie_lifecycle(&session, &origin)).await;
+
+ Box::pin(close_live_storage_fixture(
+ runtime,
+ default_session,
+ session,
+ other_session,
+ first_server,
+ second_server,
+ ))
+ .await;
+ }
}
diff --git a/tests/runtime_context_session_chrome.rs b/tests/runtime_context_session_chrome.rs
index fe6ff2f..4ab9273 100644
--- a/tests/runtime_context_session_chrome.rs
+++ b/tests/runtime_context_session_chrome.rs
@@ -428,7 +428,7 @@ async fn chrome_nested_future_oopif_routes_publish_configured_facts_without_view
FixtureResponse::html("nested")
}))
.await;
- let nested_url = format!("{}/nested", nested.origin("nested.test"));
+ let nested_url = format!("{}/nested", nested.origin("nested.localhost"));
let child = LoopbackFixture::start(Arc::new(move |_| {
FixtureResponse::html(format!(
"child"
@@ -448,14 +448,13 @@ async fn chrome_nested_future_oopif_routes_publish_configured_facts_without_view
LaunchOptions::default()
.headless(true)
.user_data_dir(profile.path())
- .arg("--site-per-process")
- .arg("--host-resolver-rules=MAP *.test 127.0.0.1"),
+ .arg("--site-per-process"),
LaunchOptions::arg,
);
let runtime = BrowserRuntime::launch(options)
.await
.expect("launch private Chrome");
- let parent_origin = parent.origin("parent.test");
+ let parent_origin = parent.origin("localhost");
let session = runtime
.isolated_session(IsolatedSessionOptions::default().context(configured_route(1000, 740)))
.await
@@ -467,7 +466,7 @@ async fn chrome_nested_future_oopif_routes_publish_configured_facts_without_view
.await
.expect("subscribe before creating future OOPIF routes");
- let child_url = format!("{}/child", child.origin("child.test"));
+ let child_url = format!("{}/child", child.origin("127.0.0.1"));
let add_child = format!(
"(() => {{ const frame = document.createElement('iframe'); frame.src = {child_url:?}; document.body.append(frame); return true; }})()"
);
diff --git a/tests/runtime_tls_chrome.rs b/tests/runtime_tls_chrome.rs
index d73676c..a301efd 100644
--- a/tests/runtime_tls_chrome.rs
+++ b/tests/runtime_tls_chrome.rs
@@ -23,7 +23,7 @@ use tokio_rustls::TlsAcceptor;
use tokio_util::sync::CancellationToken;
const TEST_DEADLINE: Duration = Duration::from_secs(15);
-const TLS_HOST: &str = "tls.test";
+const TLS_HOST: &str = "localhost";
const TLS_MARKER: &str = "browserkit-task12-local-tls";
struct TlsFixture {
@@ -36,7 +36,7 @@ impl TlsFixture {
async fn start() -> Self {
let CertifiedKey { cert, key_pair } =
generate_simple_self_signed(vec![TLS_HOST.to_owned()])
- .expect("self-signed tls.test cert");
+ .expect("self-signed localhost cert");
let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(key_pair.serialize_der()));
let config = ServerConfig::builder()
.with_no_client_auth()
@@ -68,7 +68,18 @@ impl TlsFixture {
let Ok(stream) = acceptor.accept(stream).await else {
return;
};
- serve_marker(stream).await.expect("serve TLS marker response");
+ match serve_marker(stream).await {
+ Ok(()) => {}
+ Err(error)
+ if matches!(
+ error.kind(),
+ std::io::ErrorKind::ConnectionReset
+ | std::io::ErrorKind::ConnectionAborted
+ | std::io::ErrorKind::BrokenPipe
+ | std::io::ErrorKind::UnexpectedEof
+ ) => {}
+ Err(error) => panic!("serve TLS marker response: {error}"),
+ }
});
}
}
@@ -127,14 +138,13 @@ async fn serve_marker(
stream.shutdown().await
}
-fn chrome_args(port: u16) -> [String; 6] {
+fn chrome_args(port: u16) -> [String; 5] {
[
"--disable-background-networking".to_owned(),
"--disable-component-update".to_owned(),
"--disable-default-apps".to_owned(),
"--disable-sync".to_owned(),
format!("--explicitly-allowed-ports={port}"),
- format!("--host-resolver-rules=MAP {TLS_HOST} 127.0.0.1"),
]
}
@@ -228,9 +238,9 @@ async fn browser_footprint(runtime: &BrowserRuntime) -> (BTreeSet, BTree
}
#[tokio::test]
-#[ignore = "requires installed Chrome; uses a self-signed tls.test fixture, private profile, and loopback only"]
+#[ignore = "requires installed Chrome; uses a self-signed localhost fixture, private profile, and loopback only"]
async fn chrome_local_tls_launched_default_and_isolated_scopes_do_not_leak() {
- tokio::time::timeout(Duration::from_secs(90), launched_tls_scenario())
+ tokio::time::timeout(Duration::from_secs(90), Box::pin(launched_tls_scenario()))
.await
.expect("launched local TLS test deadline");
}
@@ -431,7 +441,7 @@ fn chrome_executable() -> PathBuf {
#[tokio::test]
#[ignore = "requires installed Chrome; attaches only to a dedicated private-profile process and loopback TLS"]
async fn chrome_local_tls_attached_default_preflight_and_isolated_scope() {
- tokio::time::timeout(Duration::from_secs(60), attached_tls_scenario())
+ tokio::time::timeout(Duration::from_secs(60), Box::pin(attached_tls_scenario()))
.await
.expect("attached local TLS test deadline");
}