Send WillNavigate earlier during navigation startup (#37778)

The will-navigate message tells the devtools client to expect a
navigation for a browsing context. This makes the network monitor clear
any previous entries and show the requests for the new page that is
loaded. In order to support this correctly, we need to send the
navigation notification from the constellation instead of the script
thread, otherwise we silently ignore navigations triggered by the
browser URL bar.




Testing: Ran servo in devtools mode , now the requests appear for new
loaded page
Fixes: https://github.com/servo/servo/issues/37334

---------

Signed-off-by: Uthman Yahaya Baba <uthmanyahayababa@gmail.com>
This commit is contained in:
Usman Yahaya Baba 2025-07-05 12:35:37 +01:00 committed by GitHub
parent 864c877be5
commit 2ad5b24225
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 197 additions and 112 deletions

View file

@ -130,7 +130,7 @@ servo-media-gstreamer = { git = "https://github.com/servo/media" }
servo-tracing = { path = "components/servo_tracing" } servo-tracing = { path = "components/servo_tracing" }
servo_arc = { git = "https://github.com/servo/stylo", branch = "2025-07-01" } servo_arc = { git = "https://github.com/servo/stylo", branch = "2025-07-01" }
smallbitvec = "2.6.0" smallbitvec = "2.6.0"
smallvec = { version = "1.15", features = ["union"] } smallvec = { version = "1.15", features = ["union", "serde"] }
static_assertions = "1.1" static_assertions = "1.1"
string_cache = "0.8" string_cache = "0.8"
string_cache_codegen = "0.5" string_cache_codegen = "0.5"

View file

@ -3635,6 +3635,13 @@ where
}, },
}; };
if let Some(ref chan) = self.devtools_sender {
let state = NavigationState::Start(load_data.url.clone());
let _ = chan.send(DevtoolsControlMsg::FromScript(
ScriptToDevtoolsControlMsg::Navigate(browsing_context_id, state),
));
}
match parent_pipeline_id { match parent_pipeline_id {
Some(parent_pipeline_id) => { Some(parent_pipeline_id) => {
// Find the script thread for the pipeline containing the iframe // Find the script thread for the pipeline containing the iframe

View file

@ -41,6 +41,7 @@ pub struct NetworkEventActor {
pub total_time: Duration, pub total_time: Duration,
pub security_state: String, pub security_state: String,
pub event_timing: Option<Timings>, pub event_timing: Option<Timings>,
pub watcher_name: String,
} }
#[derive(Clone, Serialize)] #[derive(Clone, Serialize)]
@ -342,7 +343,7 @@ impl Actor for NetworkEventActor {
} }
impl NetworkEventActor { impl NetworkEventActor {
pub fn new(name: String, resource_id: u64) -> NetworkEventActor { pub fn new(name: String, resource_id: u64, watcher_name: String) -> NetworkEventActor {
NetworkEventActor { NetworkEventActor {
name, name,
resource_id, resource_id,
@ -367,6 +368,7 @@ impl NetworkEventActor {
total_time: Duration::ZERO, total_time: Duration::ZERO,
security_state: "insecure".to_owned(), security_state: "insecure".to_owned(),
event_timing: None, event_timing: None,
watcher_name,
} }
} }

View file

@ -14,9 +14,11 @@ use std::collections::HashMap;
use std::net::TcpStream; use std::net::TcpStream;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use base::id::BrowsingContextId;
use log::warn; use log::warn;
use serde::Serialize; use serde::Serialize;
use serde_json::{Map, Value}; use serde_json::{Map, Value};
use servo_url::ServoUrl;
use self::network_parent::{NetworkParentActor, NetworkParentActorMsg}; use self::network_parent::{NetworkParentActor, NetworkParentActorMsg};
use super::breakpoint::BreakpointListActor; use super::breakpoint::BreakpointListActor;
@ -33,7 +35,7 @@ use crate::actors::watcher::thread_configuration::{
}; };
use crate::protocol::JsonPacketStream; use crate::protocol::JsonPacketStream;
use crate::resource::{ResourceArrayType, ResourceAvailable}; use crate::resource::{ResourceArrayType, ResourceAvailable};
use crate::{EmptyReplyMsg, StreamId, WorkerActor}; use crate::{EmptyReplyMsg, IdMap, StreamId, WorkerActor};
pub mod network_parent; pub mod network_parent;
pub mod target_configuration; pub mod target_configuration;
@ -79,7 +81,7 @@ impl SessionContext {
("local-storage", false), ("local-storage", false),
("session-storage", false), ("session-storage", false),
("platform-message", false), ("platform-message", false),
("network-event", false), ("network-event", true),
("network-event-stacktrace", false), ("network-event-stacktrace", false),
("reflow", false), ("reflow", false),
("stylesheet", false), ("stylesheet", false),
@ -192,6 +194,19 @@ pub struct WatcherActor {
session_context: SessionContext, session_context: SessionContext,
} }
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct WillNavigateMessage {
#[serde(rename = "browsingContextID")]
browsing_context_id: u32,
inner_window_id: u32,
name: String,
time: u128,
is_frame_switching: bool,
#[serde(rename = "newURI")]
new_uri: ServoUrl,
}
impl Actor for WatcherActor { impl Actor for WatcherActor {
fn name(&self) -> String { fn name(&self) -> String {
self.name.clone() self.name.clone()
@ -322,6 +337,7 @@ impl Actor for WatcherActor {
} }
}, },
"console-message" | "error-message" => {}, "console-message" | "error-message" => {},
"network-event" => {},
_ => warn!("resource {} not handled yet", resource), _ => warn!("resource {} not handled yet", resource),
} }
@ -385,6 +401,12 @@ impl Actor for WatcherActor {
} }
} }
impl ResourceAvailable for WatcherActor {
fn actor_name(&self) -> String {
self.name.clone()
}
}
impl WatcherActor { impl WatcherActor {
pub fn new( pub fn new(
actors: &mut ActorRegistry, actors: &mut ActorRegistry,
@ -422,4 +444,33 @@ impl WatcherActor {
}, },
} }
} }
pub fn emit_will_navigate(
&self,
browsing_context_id: BrowsingContextId,
url: ServoUrl,
connections: &mut Vec<TcpStream>,
id_map: &mut IdMap,
) {
let msg = WillNavigateMessage {
browsing_context_id: id_map.browsing_context_id(browsing_context_id).value(),
inner_window_id: 0, // TODO: set this to the correct value
name: "will-navigate".to_string(),
time: SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis(),
is_frame_switching: false, // TODO: Implement frame switching
new_uri: url,
};
for stream in connections {
self.resource_array(
msg.clone(),
"document-event".to_string(),
ResourceArrayType::Available,
stream,
);
}
}
} }

View file

@ -45,6 +45,7 @@ use crate::actors::process::ProcessActor;
use crate::actors::root::RootActor; use crate::actors::root::RootActor;
use crate::actors::source::SourceActor; use crate::actors::source::SourceActor;
use crate::actors::thread::ThreadActor; use crate::actors::thread::ThreadActor;
use crate::actors::watcher::WatcherActor;
use crate::actors::worker::{WorkerActor, WorkerType}; use crate::actors::worker::{WorkerActor, WorkerType};
use crate::id::IdMap; use crate::id::IdMap;
use crate::network_handler::handle_network_event; use crate::network_handler::handle_network_event;
@ -289,11 +290,7 @@ impl DevtoolsInstance {
connections.push(stream.try_clone().unwrap()); connections.push(stream.try_clone().unwrap());
} }
let pipeline_id = match network_event { self.handle_network_event(connections, request_id, network_event);
NetworkEvent::HttpResponse(ref response) => response.pipeline_id,
NetworkEvent::HttpRequest(ref request) => request.pipeline_id,
};
self.handle_network_event(connections, pipeline_id, request_id, network_event);
}, },
DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::ServerExitMsg) => break, DevtoolsControlMsg::FromChrome(ChromeToDevtoolsControlMsg::ServerExitMsg) => break,
} }
@ -313,11 +310,23 @@ impl DevtoolsInstance {
fn handle_navigate(&self, browsing_context_id: BrowsingContextId, state: NavigationState) { fn handle_navigate(&self, browsing_context_id: BrowsingContextId, state: NavigationState) {
let actor_name = self.browsing_contexts.get(&browsing_context_id).unwrap(); let actor_name = self.browsing_contexts.get(&browsing_context_id).unwrap();
self.actors let actors = self.actors.lock().unwrap();
.lock() let actor = actors.find::<BrowsingContextActor>(actor_name);
.unwrap() let mut id_map = self.id_map.lock().expect("Mutex poisoned");
.find::<BrowsingContextActor>(actor_name) if let NavigationState::Start(url) = &state {
.navigate(state, &mut self.id_map.lock().expect("Mutex poisoned")); let mut connections = Vec::<TcpStream>::new();
for stream in self.connections.values() {
connections.push(stream.try_clone().unwrap());
}
let watcher_actor = actors.find::<WatcherActor>(&actor.watcher);
watcher_actor.emit_will_navigate(
browsing_context_id,
url.clone(),
&mut connections,
&mut id_map,
);
};
actor.navigate(state, &mut id_map);
} }
// We need separate actor representations for each script global that exists; // We need separate actor representations for each script global that exists;
@ -479,31 +488,39 @@ impl DevtoolsInstance {
fn handle_network_event( fn handle_network_event(
&mut self, &mut self,
connections: Vec<TcpStream>, connections: Vec<TcpStream>,
pipeline_id: PipelineId,
request_id: String, request_id: String,
network_event: NetworkEvent, network_event: NetworkEvent,
) { ) {
let netevent_actor_name = self.find_network_event_actor(request_id); let browsing_context_id = match &network_event {
NetworkEvent::HttpRequest(req) => req.browsing_context_id,
NetworkEvent::HttpResponse(resp) => resp.browsing_context_id,
};
let Some(id) = self.pipelines.get(&pipeline_id) else { let Some(browsing_context_actor_name) = self.browsing_contexts.get(&browsing_context_id)
return; else {
};
let Some(browsing_context_actor_name) = self.browsing_contexts.get(id) else {
return; return;
}; };
let watcher_name = self
.actors
.lock()
.unwrap()
.find::<BrowsingContextActor>(browsing_context_actor_name)
.watcher
.clone();
let netevent_actor_name = self.find_network_event_actor(request_id, watcher_name);
handle_network_event( handle_network_event(
Arc::clone(&self.actors), Arc::clone(&self.actors),
netevent_actor_name, netevent_actor_name,
connections, connections,
network_event, network_event,
browsing_context_actor_name.to_string(),
) )
} }
// Find the name of NetworkEventActor corresponding to request_id // Find the name of NetworkEventActor corresponding to request_id
// Create a new one if it does not exist, add it to the actor_requests hashmap // Create a new one if it does not exist, add it to the actor_requests hashmap
fn find_network_event_actor(&mut self, request_id: String) -> String { fn find_network_event_actor(&mut self, request_id: String, watcher_name: String) -> String {
let mut actors = self.actors.lock().unwrap(); let mut actors = self.actors.lock().unwrap();
match self.actor_requests.entry(request_id) { match self.actor_requests.entry(request_id) {
Occupied(name) => { Occupied(name) => {
@ -514,7 +531,7 @@ impl DevtoolsInstance {
let resource_id = self.next_resource_id; let resource_id = self.next_resource_id;
self.next_resource_id += 1; self.next_resource_id += 1;
let actor_name = actors.new_name("netevent"); let actor_name = actors.new_name("netevent");
let actor = NetworkEventActor::new(actor_name.clone(), resource_id); let actor = NetworkEventActor::new(actor_name.clone(), resource_id, watcher_name);
entry.insert(actor_name.clone()); entry.insert(actor_name.clone());
actors.register(Box::new(actor)); actors.register(Box::new(actor));
actor_name actor_name

View file

@ -9,8 +9,8 @@ use devtools_traits::NetworkEvent;
use serde::Serialize; use serde::Serialize;
use crate::actor::ActorRegistry; use crate::actor::ActorRegistry;
use crate::actors::browsing_context::BrowsingContextActor;
use crate::actors::network_event::NetworkEventActor; use crate::actors::network_event::NetworkEventActor;
use crate::actors::watcher::WatcherActor;
use crate::resource::{ResourceArrayType, ResourceAvailable}; use crate::resource::{ResourceArrayType, ResourceAvailable};
#[derive(Clone, Serialize)] #[derive(Clone, Serialize)]
@ -26,22 +26,20 @@ pub(crate) fn handle_network_event(
netevent_actor_name: String, netevent_actor_name: String,
mut connections: Vec<TcpStream>, mut connections: Vec<TcpStream>,
network_event: NetworkEvent, network_event: NetworkEvent,
browsing_context_actor_name: String,
) { ) {
let mut actors = actors.lock().unwrap(); let mut actors = actors.lock().unwrap();
let actor = actors.find_mut::<NetworkEventActor>(&netevent_actor_name);
let watcher_name = actor.watcher_name.clone();
match network_event { match network_event {
NetworkEvent::HttpRequest(httprequest) => { NetworkEvent::HttpRequest(httprequest) => {
let (event_actor, resource_updates) = { actor.add_request(httprequest);
let actor = actors.find_mut::<NetworkEventActor>(&netevent_actor_name);
actor.add_request(httprequest); let event_actor = actor.event_actor();
(actor.event_actor(), actor.resource_updates()) let resource_updates = actor.resource_updates();
}; let watcher_actor = actors.find::<WatcherActor>(&watcher_name);
let browsing_context_actor =
actors.find::<BrowsingContextActor>(&browsing_context_actor_name);
for stream in &mut connections { for stream in &mut connections {
// Notify that a new network event has started watcher_actor.resource_array(
browsing_context_actor.resource_array(
event_actor.clone(), event_actor.clone(),
"network-event".to_string(), "network-event".to_string(),
ResourceArrayType::Available, ResourceArrayType::Available,
@ -49,7 +47,7 @@ pub(crate) fn handle_network_event(
); );
// Also push initial resource update (request headers, cookies) // Also push initial resource update (request headers, cookies)
browsing_context_actor.resource_array( watcher_actor.resource_array(
resource_updates.clone(), resource_updates.clone(),
"network-event".to_string(), "network-event".to_string(),
ResourceArrayType::Updated, ResourceArrayType::Updated,
@ -58,18 +56,13 @@ pub(crate) fn handle_network_event(
} }
}, },
NetworkEvent::HttpResponse(httpresponse) => { NetworkEvent::HttpResponse(httpresponse) => {
// Scope mutable borrow // Store the response information in the actor
let resource = { actor.add_response(httpresponse);
let actor = actors.find_mut::<NetworkEventActor>(&netevent_actor_name); let resource = actor.resource_updates();
// Store the response information in the actor let watcher_actor = actors.find::<WatcherActor>(&watcher_name);
actor.add_response(httpresponse);
actor.resource_updates()
};
let browsing_context_actor =
actors.find::<BrowsingContextActor>(&browsing_context_actor_name);
for stream in &mut connections { for stream in &mut connections {
browsing_context_actor.resource_array( watcher_actor.resource_array(
resource.clone(), resource.clone(),
"network-event".to_string(), "network-event".to_string(),
ResourceArrayType::Updated, ResourceArrayType::Updated,

View file

@ -9,7 +9,7 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use async_recursion::async_recursion; use async_recursion::async_recursion;
use base::cross_process_instant::CrossProcessInstant; use base::cross_process_instant::CrossProcessInstant;
use base::id::{HistoryStateId, PipelineId}; use base::id::{BrowsingContextId, HistoryStateId, PipelineId};
use crossbeam_channel::Sender; use crossbeam_channel::Sender;
use devtools_traits::{ use devtools_traits::{
ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest, ChromeToDevtoolsControlMsg, DevtoolsControlMsg, HttpRequest as DevtoolsHttpRequest,
@ -398,6 +398,7 @@ fn prepare_devtools_request(
connect_time: Duration, connect_time: Duration,
send_time: Duration, send_time: Duration,
is_xhr: bool, is_xhr: bool,
browsing_context_id: BrowsingContextId,
) -> ChromeToDevtoolsControlMsg { ) -> ChromeToDevtoolsControlMsg {
let started_date_time = SystemTime::now(); let started_date_time = SystemTime::now();
let request = DevtoolsHttpRequest { let request = DevtoolsHttpRequest {
@ -414,6 +415,7 @@ fn prepare_devtools_request(
connect_time, connect_time,
send_time, send_time,
is_xhr, is_xhr,
browsing_context_id,
}; };
let net_event = NetworkEvent::HttpRequest(request); let net_event = NetworkEvent::HttpRequest(request);
@ -435,12 +437,14 @@ fn send_response_to_devtools(
headers: Option<HeaderMap>, headers: Option<HeaderMap>,
status: HttpStatus, status: HttpStatus,
pipeline_id: PipelineId, pipeline_id: PipelineId,
browsing_context_id: BrowsingContextId,
) { ) {
let response = DevtoolsHttpResponse { let response = DevtoolsHttpResponse {
headers, headers,
status, status,
body: None, body: None,
pipeline_id, pipeline_id,
browsing_context_id,
}; };
let net_event_response = NetworkEvent::HttpResponse(response); let net_event_response = NetworkEvent::HttpResponse(response);
@ -536,6 +540,7 @@ async fn obtain_response(
is_xhr: bool, is_xhr: bool,
context: &FetchContext, context: &FetchContext,
fetch_terminated: UnboundedSender<bool>, fetch_terminated: UnboundedSender<bool>,
browsing_context_id: Option<BrowsingContextId>,
) -> Result<(HyperResponse<Decoder>, Option<ChromeToDevtoolsControlMsg>), NetworkError> { ) -> Result<(HyperResponse<Decoder>, Option<ChromeToDevtoolsControlMsg>), NetworkError> {
{ {
let mut headers = request_headers.clone(); let mut headers = request_headers.clone();
@ -716,21 +721,27 @@ async fn obtain_response(
let msg = if let Some(request_id) = request_id { let msg = if let Some(request_id) = request_id {
if let Some(pipeline_id) = pipeline_id { if let Some(pipeline_id) = pipeline_id {
Some(prepare_devtools_request( if let Some(browsing_context_id) = browsing_context_id {
request_id, Some(prepare_devtools_request(
closure_url, request_id,
method.clone(), closure_url,
headers, method.clone(),
Some(devtools_bytes.lock().unwrap().clone()), headers,
pipeline_id, Some(devtools_bytes.lock().unwrap().clone()),
(connect_end - connect_start).unsigned_abs(), pipeline_id,
(send_end - send_start).unsigned_abs(), (connect_end - connect_start).unsigned_abs(),
is_xhr, (send_end - send_start).unsigned_abs(),
)) is_xhr,
// TODO: ^This is not right, connect_start is taken before contructing the browsing_context_id,
// request and connect_end at the end of it. send_start is takend before the ))
// connection too. I'm not sure it's currently possible to get the time at the } else {
// point between the connection and the start of a request. debug!("Not notifying devtools (no browsing_context_id)");
None
}
// TODO: ^This is not right, connect_start is taken before contructing the
// request and connect_end at the end of it. send_start is takend before the
// connection too. I'm not sure it's currently possible to get the time at the
// point between the connection and the start of a request.
} else { } else {
debug!("Not notifying devtools (no pipeline_id)"); debug!("Not notifying devtools (no pipeline_id)");
None None
@ -1887,6 +1898,8 @@ async fn http_network_fetch(
let _ = fetch_terminated_sender.send(false); let _ = fetch_terminated_sender.send(false);
} }
let browsing_context_id = request.target_webview_id.map(|id| id.0);
let response_future = obtain_response( let response_future = obtain_response(
&context.state.client, &context.state.client,
&url, &url,
@ -1903,6 +1916,7 @@ async fn http_network_fetch(
is_xhr, is_xhr,
context, context,
fetch_terminated_sender, fetch_terminated_sender,
browsing_context_id,
); );
let pipeline_id = request.pipeline_id; let pipeline_id = request.pipeline_id;
@ -2008,13 +2022,14 @@ async fn http_network_fetch(
// --- Tell devtools that we got a response // --- Tell devtools that we got a response
// Send an HttpResponse message to devtools with the corresponding request_id // Send an HttpResponse message to devtools with the corresponding request_id
if let Some(pipeline_id) = pipeline_id { if let (Some(pipeline_id), Some(browsing_context_id)) = (pipeline_id, browsing_context_id) {
send_response_to_devtools( send_response_to_devtools(
&sender, &sender,
request_id.unwrap(), request_id.unwrap(),
meta_headers.map(Serde::into_inner), meta_headers.map(Serde::into_inner),
meta_status, meta_status,
pipeline_id, pipeline_id,
browsing_context_id,
); );
} }
} }

View file

@ -4,6 +4,7 @@
use std::ops::Deref; use std::ops::Deref;
use base::id::TEST_WEBVIEW_ID;
use headers::{ContentType, HeaderMapExt}; use headers::{ContentType, HeaderMapExt};
use hyper_serde::Serde; use hyper_serde::Serde;
use mime::{self, Mime}; use mime::{self, Mime};
@ -24,7 +25,7 @@ fn assert_parse(
use net_traits::request::RequestBuilder; use net_traits::request::RequestBuilder;
let url = ServoUrl::parse(url).unwrap(); let url = ServoUrl::parse(url).unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.pipeline_id(None) .pipeline_id(None)
.build(); .build();

View file

@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, Weak}; use std::sync::{Arc, Mutex, Weak};
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use base::id::TEST_PIPELINE_ID; use base::id::{TEST_PIPELINE_ID, TEST_WEBVIEW_ID};
use content_security_policy as csp; use content_security_policy as csp;
use crossbeam_channel::{Sender, unbounded}; use crossbeam_channel::{Sender, unbounded};
use devtools_traits::{HttpRequest as DevtoolsHttpRequest, HttpResponse as DevtoolsHttpResponse}; use devtools_traits::{HttpRequest as DevtoolsHttpRequest, HttpResponse as DevtoolsHttpResponse};
@ -66,7 +66,7 @@ fn test_fetch_response_is_not_network_error() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -80,7 +80,7 @@ fn test_fetch_response_is_not_network_error() {
#[test] #[test]
fn test_fetch_on_bad_port_is_network_error() { fn test_fetch_on_bad_port_is_network_error() {
let url = ServoUrl::parse("http://www.example.org:6667").unwrap(); let url = ServoUrl::parse("http://www.example.org:6667").unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -102,7 +102,7 @@ fn test_fetch_response_body_matches_const_message() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -122,7 +122,7 @@ fn test_fetch_response_body_matches_const_message() {
#[test] #[test]
fn test_fetch_aboutblank() { fn test_fetch_aboutblank() {
let url = ServoUrl::parse("about:blank").unwrap(); let url = ServoUrl::parse("about:blank").unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
@ -188,7 +188,7 @@ fn test_fetch_blob() {
); );
let url = ServoUrl::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap(); let url = ServoUrl::parse(&format!("blob:{}{}", origin.as_str(), id.simple())).unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(origin.origin()) .origin(origin.origin())
.build(); .build();
@ -230,7 +230,7 @@ fn test_file() {
.unwrap(); .unwrap();
let url = ServoUrl::from_file_path(path.clone()).unwrap(); let url = ServoUrl::from_file_path(path.clone()).unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
@ -273,7 +273,7 @@ fn test_file() {
#[test] #[test]
fn test_fetch_ftp() { fn test_fetch_ftp() {
let url = ServoUrl::parse("ftp://not-supported").unwrap(); let url = ServoUrl::parse("ftp://not-supported").unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -283,7 +283,7 @@ fn test_fetch_ftp() {
#[test] #[test]
fn test_fetch_bogus_scheme() { fn test_fetch_bogus_scheme() {
let url = ServoUrl::parse("bogus://whatever").unwrap(); let url = ServoUrl::parse("bogus://whatever").unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -338,7 +338,12 @@ fn test_cors_preflight_fetch() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let target_url = url.clone().join("a.html").unwrap(); let target_url = url.clone().join("a.html").unwrap();
let mut request = RequestBuilder::new(None, url, Referrer::ReferrerUrl(target_url)).build(); let mut request = RequestBuilder::new(
Some(TEST_WEBVIEW_ID),
url,
Referrer::ReferrerUrl(target_url),
)
.build();
request.referrer_policy = ReferrerPolicy::Origin; request.referrer_policy = ReferrerPolicy::Origin;
request.use_cors_preflight = true; request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode; request.mode = RequestMode::CorsMode;
@ -395,7 +400,7 @@ fn test_cors_preflight_cache_fetch() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build(); let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url, Referrer::NoReferrer).build();
request.use_cors_preflight = true; request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode; request.mode = RequestMode::CorsMode;
let wrapped_request0 = request.clone(); let wrapped_request0 = request.clone();
@ -464,7 +469,7 @@ fn test_cors_preflight_fetch_network_error() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build(); let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url, Referrer::NoReferrer).build();
request.method = Method::from_bytes(b"CHICKEN").unwrap(); request.method = Method::from_bytes(b"CHICKEN").unwrap();
request.use_cors_preflight = true; request.use_cors_preflight = true;
request.mode = RequestMode::CorsMode; request.mode = RequestMode::CorsMode;
@ -493,7 +498,7 @@ fn test_fetch_response_is_basic_filtered() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -560,7 +565,7 @@ fn test_fetch_response_is_cors_filtered() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
// an origin mis-match will stop it from defaulting to a basic filtered response // an origin mis-match will stop it from defaulting to a basic filtered response
let mut request = RequestBuilder::new(None, url, Referrer::NoReferrer).build(); let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url, Referrer::NoReferrer).build();
request.mode = RequestMode::CorsMode; request.mode = RequestMode::CorsMode;
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
let _ = server.close(); let _ = server.close();
@ -596,7 +601,7 @@ fn test_fetch_response_is_opaque_filtered() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
// an origin mis-match will fall through to an Opaque filtered response // an origin mis-match will fall through to an Opaque filtered response
let request = RequestBuilder::new(None, url, Referrer::NoReferrer).build(); let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url, Referrer::NoReferrer).build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
let _ = server.close(); let _ = server.close();
@ -644,7 +649,7 @@ fn test_fetch_response_is_opaque_redirect_filtered() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
request.redirect_mode = RedirectMode::Manual; request.redirect_mode = RedirectMode::Manual;
@ -680,9 +685,10 @@ fn test_fetch_with_local_urls_only() {
let (server, server_url) = make_server(handler); let (server, server_url) = make_server(handler);
let do_fetch = |url: ServoUrl| { let do_fetch = |url: ServoUrl| {
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let mut request =
.origin(url.origin()) RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.build(); .origin(url.origin())
.build();
// Set the flag. // Set the flag.
request.local_urls_only = true; request.local_urls_only = true;
@ -748,7 +754,7 @@ fn test_fetch_with_hsts() {
HstsEntry::new("localhost".to_owned(), IncludeSubdomains::NotIncluded, None).unwrap(), HstsEntry::new("localhost".to_owned(), IncludeSubdomains::NotIncluded, None).unwrap(),
); );
} }
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
// Set the flag. // Set the flag.
@ -802,7 +808,7 @@ fn test_load_adds_host_to_hsts_list_when_url_is_https() {
context.state.override_manager.add_override(certificate); context.state.override_manager.add_override(certificate);
} }
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET) .method(Method::GET)
.body(None) .body(None)
.destination(Destination::Document) .destination(Destination::Document)
@ -862,7 +868,7 @@ fn test_fetch_self_signed() {
protocols: Arc::new(ProtocolRegistry::default()), protocols: Arc::new(ProtocolRegistry::default()),
}; };
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET) .method(Method::GET)
.body(None) .body(None)
.destination(Destination::Document) .destination(Destination::Document)
@ -883,7 +889,7 @@ fn test_fetch_self_signed() {
context.state.override_manager.add_override(certificate); context.state.override_manager.add_override(certificate);
} }
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET) .method(Method::GET)
.body(None) .body(None)
.destination(Destination::Document) .destination(Destination::Document)
@ -908,7 +914,7 @@ fn test_fetch_with_sri_network_error() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
// To calulate hash use : // To calulate hash use :
@ -934,7 +940,7 @@ fn test_fetch_with_sri_sucess() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let mut request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let mut request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
// To calulate hash use : // To calulate hash use :
@ -976,7 +982,7 @@ fn test_fetch_blocked_nosniff() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.destination(destination) .destination(destination)
.build(); .build();
@ -1023,7 +1029,7 @@ fn setup_server_and_fetch(message: &'static [u8], redirect_cap: u32) -> Response
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -1113,7 +1119,7 @@ fn test_fetch_redirect_updates_method_runner(
let (server, url) = crate::make_server(handler); let (server, url) = crate::make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.method(method) .method(method)
.build(); .build();
@ -1198,7 +1204,7 @@ fn test_fetch_async_returns_complete_response() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
@ -1218,7 +1224,7 @@ fn test_opaque_filtered_fetch_async_returns_complete_response() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
// an origin mis-match will fall through to an Opaque filtered response // an origin mis-match will fall through to an Opaque filtered response
let request = RequestBuilder::new(None, url, Referrer::NoReferrer).build(); let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url, Referrer::NoReferrer).build();
let fetch_response = fetch(request, None); let fetch_response = fetch(request, None);
let _ = server.close(); let _ = server.close();
@ -1252,7 +1258,7 @@ fn test_opaque_redirect_filtered_fetch_async_returns_complete_response() {
}; };
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.redirect_mode(RedirectMode::Manual) .redirect_mode(RedirectMode::Manual)
.build(); .build();
@ -1277,7 +1283,7 @@ fn test_fetch_with_devtools() {
let (server, url) = make_server(handler); let (server, url) = make_server(handler);
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.redirect_mode(RedirectMode::Manual) .redirect_mode(RedirectMode::Manual)
.pipeline_id(Some(TEST_PIPELINE_ID)) .pipeline_id(Some(TEST_PIPELINE_ID))
@ -1334,6 +1340,7 @@ fn test_fetch_with_devtools() {
connect_time: devhttprequest.connect_time, connect_time: devhttprequest.connect_time,
send_time: devhttprequest.send_time, send_time: devhttprequest.send_time,
is_xhr: true, is_xhr: true,
browsing_context_id: TEST_WEBVIEW_ID.0,
}; };
let content = "Yay!"; let content = "Yay!";
@ -1350,6 +1357,7 @@ fn test_fetch_with_devtools() {
status: HttpStatus::default(), status: HttpStatus::default(),
body: None, body: None,
pipeline_id: TEST_PIPELINE_ID, pipeline_id: TEST_PIPELINE_ID,
browsing_context_id: TEST_WEBVIEW_ID.0,
}; };
assert_eq!(devhttprequest, httprequest); assert_eq!(devhttprequest, httprequest);
@ -1417,7 +1425,7 @@ fn test_fetch_request_intercepted() {
}; };
let url = ServoUrl::parse("http://www.example.org").unwrap(); let url = ServoUrl::parse("http://www.example.org").unwrap();
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.origin(url.origin()) .origin(url.origin())
.build(); .build();
let response = fetch_with_context(request, &mut context); let response = fetch_with_context(request, &mut context);

View file

@ -252,7 +252,7 @@ fn test_request_and_response_data_with_network_messages() {
let mut request_headers = HeaderMap::new(); let mut request_headers = HeaderMap::new();
request_headers.typed_insert(Host::from("bar.foo".parse::<Authority>().unwrap())); request_headers.typed_insert(Host::from("bar.foo".parse::<Authority>().unwrap()));
let request = RequestBuilder::new(None, url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), url.clone(), Referrer::NoReferrer)
.method(Method::GET) .method(Method::GET)
.headers(request_headers) .headers(request_headers)
.body(None) .body(None)
@ -327,6 +327,7 @@ fn test_request_and_response_data_with_network_messages() {
connect_time: devhttprequest.connect_time, connect_time: devhttprequest.connect_time,
send_time: devhttprequest.send_time, send_time: devhttprequest.send_time,
is_xhr: false, is_xhr: false,
browsing_context_id: TEST_WEBVIEW_ID.0,
}; };
let content = "Yay!"; let content = "Yay!";
@ -348,6 +349,7 @@ fn test_request_and_response_data_with_network_messages() {
status: HttpStatus::default(), status: HttpStatus::default(),
body: None, body: None,
pipeline_id: TEST_PIPELINE_ID, pipeline_id: TEST_PIPELINE_ID,
browsing_context_id: TEST_WEBVIEW_ID.0,
}; };
assert_eq!(devhttprequest, httprequest); assert_eq!(devhttprequest, httprequest);
@ -407,7 +409,7 @@ fn test_redirected_request_to_devtools() {
}; };
let (pre_server, pre_url) = make_server(pre_handler); let (pre_server, pre_url) = make_server(pre_handler);
let request = RequestBuilder::new(None, pre_url.clone(), Referrer::NoReferrer) let request = RequestBuilder::new(Some(TEST_WEBVIEW_ID), pre_url.clone(), Referrer::NoReferrer)
.method(Method::POST) .method(Method::POST)
.destination(Destination::Document) .destination(Destination::Document)
.pipeline_id(Some(TEST_PIPELINE_ID)) .pipeline_id(Some(TEST_PIPELINE_ID))

View file

@ -2657,12 +2657,7 @@ impl Window {
}; };
// Step 13 // Step 13
ScriptThread::navigate( ScriptThread::navigate(pipeline_id, load_data, resolved_history_handling);
window_proxy.browsing_context_id(),
pipeline_id,
load_data,
resolved_history_handling,
);
}; };
} }

View file

@ -596,7 +596,6 @@ impl ScriptThread {
/// Step 13 of <https://html.spec.whatwg.org/multipage/#navigate> /// Step 13 of <https://html.spec.whatwg.org/multipage/#navigate>
pub(crate) fn navigate( pub(crate) fn navigate(
browsing_context: BrowsingContextId,
pipeline_id: PipelineId, pipeline_id: PipelineId,
mut load_data: LoadData, mut load_data: LoadData,
history_handling: NavigationHistoryBehavior, history_handling: NavigationHistoryBehavior,
@ -639,13 +638,6 @@ impl ScriptThread {
.dom_manipulation_task_source() .dom_manipulation_task_source()
.queue(task); .queue(task);
} else { } else {
if let Some(ref sender) = script_thread.senders.devtools_server_sender {
let _ = sender.send(ScriptToDevtoolsControlMsg::Navigate(
browsing_context,
NavigationState::Start(load_data.url.clone()),
));
}
script_thread script_thread
.senders .senders
.pipeline_to_constellation_sender .pipeline_to_constellation_sender

View file

@ -444,6 +444,7 @@ pub struct HttpRequest {
pub connect_time: Duration, pub connect_time: Duration,
pub send_time: Duration, pub send_time: Duration,
pub is_xhr: bool, pub is_xhr: bool,
pub browsing_context_id: BrowsingContextId,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -452,6 +453,7 @@ pub struct HttpResponse {
pub status: HttpStatus, pub status: HttpStatus,
pub body: Option<Vec<u8>>, pub body: Option<Vec<u8>>,
pub pipeline_id: PipelineId, pub pipeline_id: PipelineId,
pub browsing_context_id: BrowsingContextId,
} }
#[derive(Debug)] #[derive(Debug)]