diff --git a/components/devtools/actors/console.rs b/components/devtools/actors/console.rs index fd0bd184bfa..871399b6e61 100644 --- a/components/devtools/actors/console.rs +++ b/components/devtools/actors/console.rs @@ -30,7 +30,7 @@ use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::object::ObjectActor; use crate::actors::worker::WorkerActor; use crate::protocol::JsonPacketStream; -use crate::resource::ResourceAvailable; +use crate::resource::{ResourceArrayType, ResourceAvailable}; use crate::{StreamId, UniqueId}; trait EncodableConsoleMessage { @@ -261,13 +261,12 @@ impl ConsoleActor { .push(CachedConsoleMessage::PageError(page_error.clone())); if id == self.current_unique_id(registry) { if let Root::BrowsingContext(bc) = &self.root { - registry - .find::(bc) - .resource_available( - PageErrorWrapper { page_error }, - "error-message".into(), - stream, - ) + registry.find::(bc).resource_array( + PageErrorWrapper { page_error }, + "error-message".into(), + ResourceArrayType::Available, + stream, + ) }; } } @@ -287,9 +286,12 @@ impl ConsoleActor { .push(CachedConsoleMessage::ConsoleLog(log_message.clone())); if id == self.current_unique_id(registry) { if let Root::BrowsingContext(bc) = &self.root { - registry - .find::(bc) - .resource_available(log_message, "console-message".into(), stream) + registry.find::(bc).resource_array( + log_message, + "console-message".into(), + ResourceArrayType::Available, + stream, + ) }; } } diff --git a/components/devtools/actors/network_event.rs b/components/devtools/actors/network_event.rs index f95ee733045..579f1c073cd 100644 --- a/components/devtools/actors/network_event.rs +++ b/components/devtools/actors/network_event.rs @@ -21,7 +21,8 @@ use crate::actor::{Actor, ActorMessageStatus, ActorRegistry}; use crate::network_handler::Cause; use crate::protocol::JsonPacketStream; -struct HttpRequest { +#[derive(Clone)] +pub struct HttpRequest { url: String, method: Method, headers: HeaderMap, @@ -32,7 +33,8 @@ struct HttpRequest { send_time: Duration, } -struct HttpResponse { +#[derive(Clone)] +pub struct HttpResponse { headers: Option, status: HttpStatus, body: Option>, @@ -40,9 +42,27 @@ struct HttpResponse { pub struct NetworkEventActor { pub name: String, - request: HttpRequest, - response: HttpResponse, - is_xhr: bool, + pub request: HttpRequest, + pub response: HttpResponse, + pub is_xhr: bool, + pub response_content: Option, + pub response_start: Option, + pub response_cookies: Option, + pub response_headers: Option, + pub request_cookies: Option, + pub request_headers: Option, + pub total_time: Duration, + pub security_state: String, + pub event_timing: Option, +} + +#[derive(Clone, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct NetworkEventResource { + pub resource_id: u64, + pub resource_updates: Map, + pub browsing_context_id: u64, + pub inner_window_id: u64, } #[derive(Clone, Serialize)] @@ -157,7 +177,7 @@ struct GetResponseCookiesReply { } #[derive(Serialize)] -struct Timings { +pub struct Timings { blocked: u32, dns: u32, connect: u64, @@ -336,27 +356,39 @@ impl Actor for NetworkEventActor { impl NetworkEventActor { pub fn new(name: String) -> NetworkEventActor { + let request = HttpRequest { + url: String::new(), + method: Method::GET, + headers: HeaderMap::new(), + body: None, + started_date_time: SystemTime::now(), + time_stamp: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_secs() as i64, + send_time: Duration::ZERO, + connect_time: Duration::ZERO, + }; + let response = HttpResponse { + headers: None, + status: HttpStatus::default(), + body: None, + }; + NetworkEventActor { name, - request: HttpRequest { - url: String::new(), - method: Method::GET, - headers: HeaderMap::new(), - body: None, - started_date_time: SystemTime::now(), - time_stamp: SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap_or_default() - .as_secs() as i64, - send_time: Duration::ZERO, - connect_time: Duration::ZERO, - }, - response: HttpResponse { - headers: None, - status: HttpStatus::default(), - body: None, - }, + request: request.clone(), + response: response.clone(), is_xhr: false, + response_content: None, + response_start: None, + response_cookies: None, + response_headers: None, + request_cookies: None, + request_headers: None, + total_time: Self::total_time(&request), + security_state: "insecure".to_owned(), // Default security state + event_timing: None, } } @@ -417,12 +449,13 @@ impl NetworkEventActor { } } - pub fn response_start(&self) -> ResponseStartMsg { + #[allow(dead_code)] + pub fn response_start(response: &HttpResponse) -> ResponseStartMsg { // TODO: Send the correct values for all these fields. - let h_size_option = self.response.headers.as_ref().map(|headers| headers.len()); - let h_size = h_size_option.unwrap_or(0); - let status = &self.response.status; - // TODO: Send the correct values for remoteAddress and remotePort and http_version. + let h_size = response.headers.as_ref().map(|h| h.len()).unwrap_or(0); + let status = &response.status; + + // TODO: Send the correct values for remoteAddress and remotePort and http_version ResponseStartMsg { http_version: "HTTP/1.1".to_owned(), remote_address: "63.245.217.43".to_owned(), @@ -434,26 +467,29 @@ impl NetworkEventActor { } } - pub fn response_content(&self) -> ResponseContentMsg { - let mut m_string = "".to_owned(); - if let Some(ref headers) = self.response.headers { - m_string = match headers.typed_get::() { + #[allow(dead_code)] + pub fn response_content(response: &HttpResponse) -> ResponseContentMsg { + let mime_type = if let Some(ref headers) = response.headers { + match headers.typed_get::() { Some(ct) => ct.to_string(), - _ => "".to_owned(), - }; - } + None => "".to_string(), + } + } else { + "".to_string() + }; // TODO: Set correct values when response's body is sent to the devtools in http_loader. ResponseContentMsg { - mime_type: m_string, + mime_type, content_size: 0, transferred_size: 0, discard_response_body: true, } } - pub fn response_cookies(&self) -> ResponseCookiesMsg { + #[allow(dead_code)] + pub fn response_cookies(response: &HttpResponse) -> ResponseCookiesMsg { let mut cookies_size = 0; - if let Some(ref headers) = self.response.headers { + if let Some(ref headers) = response.headers { cookies_size = match headers.typed_get::() { Some(ref cookie) => cookie.len(), _ => 0, @@ -464,10 +500,11 @@ impl NetworkEventActor { } } - pub fn response_headers(&self) -> ResponseHeadersMsg { + #[allow(dead_code)] + pub fn response_headers(response: &HttpResponse) -> ResponseHeadersMsg { let mut headers_size = 0; let mut headers_byte_count = 0; - if let Some(ref headers) = self.response.headers { + if let Some(ref headers) = response.headers { headers_size = headers.len(); for (name, value) in headers.iter() { headers_byte_count += name.as_str().len() + value.len(); @@ -479,18 +516,20 @@ impl NetworkEventActor { } } - pub fn request_headers(&self) -> RequestHeadersMsg { - let size = self.request.headers.iter().fold(0, |acc, (name, value)| { + #[allow(dead_code)] + pub fn request_headers(request: &HttpRequest) -> RequestHeadersMsg { + let size = request.headers.iter().fold(0, |acc, (name, value)| { acc + name.as_str().len() + value.len() }); RequestHeadersMsg { - headers: self.request.headers.len(), + headers: request.headers.len(), headers_size: size, } } - pub fn request_cookies(&self) -> RequestCookiesMsg { - let cookies_size = match self.request.headers.typed_get::() { + #[allow(dead_code)] + pub fn request_cookies(request: &HttpRequest) -> RequestCookiesMsg { + let cookies_size = match request.headers.typed_get::() { Some(ref cookie) => cookie.len(), _ => 0, }; @@ -499,7 +538,78 @@ impl NetworkEventActor { } } - pub fn total_time(&self) -> Duration { - self.request.connect_time + self.request.send_time + pub fn total_time(request: &HttpRequest) -> Duration { + request.connect_time + request.send_time + } + + fn insert_serialized_map(map: &mut Map, obj: &Option) { + if let Some(value) = obj { + if let Ok(Value::Object(serialized)) = serde_json::to_value(value) { + for (key, val) in serialized { + map.insert(key, val); + } + } + } + } + + pub fn resource_updates(&self) -> NetworkEventResource { + let mut resource_updates = Map::new(); + + resource_updates.insert( + "requestCookiesAvailable".to_owned(), + Value::Bool(self.request_cookies.is_some()), + ); + + resource_updates.insert( + "requestHeadersAvailable".to_owned(), + Value::Bool(self.request_headers.is_some()), + ); + + resource_updates.insert( + "responseHeadersAvailable".to_owned(), + Value::Bool(self.response_headers.is_some()), + ); + resource_updates.insert( + "responseCookiesAvailable".to_owned(), + Value::Bool(self.response_cookies.is_some()), + ); + resource_updates.insert( + "responseStartAvailable".to_owned(), + Value::Bool(self.response_start.is_some()), + ); + resource_updates.insert( + "responseContentAvailable".to_owned(), + Value::Bool(self.response_content.is_some()), + ); + + resource_updates.insert( + "totalTime".to_string(), + Value::from(self.total_time.as_secs_f64()), + ); + + resource_updates.insert( + "securityState".to_string(), + Value::String(self.security_state.clone()), + ); + resource_updates.insert( + "eventTimingsAvailable".to_owned(), + Value::Bool(self.event_timing.is_some()), + ); + + Self::insert_serialized_map(&mut resource_updates, &self.response_content); + Self::insert_serialized_map(&mut resource_updates, &self.response_headers); + Self::insert_serialized_map(&mut resource_updates, &self.response_cookies); + Self::insert_serialized_map(&mut resource_updates, &self.request_headers); + Self::insert_serialized_map(&mut resource_updates, &self.request_cookies); + Self::insert_serialized_map(&mut resource_updates, &self.response_start); + Self::insert_serialized_map(&mut resource_updates, &self.event_timing); + + // TODO: Set the correct values for these fields + NetworkEventResource { + resource_id: 0, + resource_updates, + browsing_context_id: 0, + inner_window_id: 0, + } } } diff --git a/components/devtools/actors/watcher.rs b/components/devtools/actors/watcher.rs index 964d1b3e006..d00d698ce95 100644 --- a/components/devtools/actors/watcher.rs +++ b/components/devtools/actors/watcher.rs @@ -32,7 +32,7 @@ use crate::actors::watcher::thread_configuration::{ ThreadConfigurationActor, ThreadConfigurationActorMsg, }; use crate::protocol::JsonPacketStream; -use crate::resource::ResourceAvailable; +use crate::resource::{ResourceArrayType, ResourceAvailable}; use crate::{EmptyReplyMsg, StreamId, WorkerActor}; pub mod network_parent; @@ -292,14 +292,20 @@ impl Actor for WatcherActor { title: Some(target.title.borrow().clone()), url: Some(target.url.borrow().clone()), }; - target.resource_available(event, "document-event".into(), stream); + target.resource_array( + event, + "document-event".into(), + ResourceArrayType::Available, + stream, + ); } }, "source" => { let thread_actor = registry.find::(&target.thread); - target.resources_available( + target.resources_array( thread_actor.source_manager.source_forms(registry), "source".into(), + ResourceArrayType::Available, stream, ); @@ -307,9 +313,10 @@ impl Actor for WatcherActor { let worker = registry.find::(worker_name); let thread = registry.find::(&worker.thread); - worker.resources_available( + worker.resources_array( thread.source_manager.source_forms(registry), "source".into(), + ResourceArrayType::Available, stream, ); } diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index ade2e1442e3..0adbf0ded36 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -29,7 +29,7 @@ use devtools_traits::{ use embedder_traits::{AllowOrDeny, EmbedderMsg, EmbedderProxy}; use ipc_channel::ipc::{self, IpcSender}; use log::trace; -use resource::ResourceAvailable; +use resource::{ResourceArrayType, ResourceAvailable}; use serde::Serialize; use servo_rand::RngCore; @@ -540,7 +540,12 @@ impl DevtoolsInstance { let worker_actor = actors.find::(worker_actor_name); for stream in self.connections.values_mut() { - worker_actor.resource_available(&source_form, "source".into(), stream); + worker_actor.resource_array( + &source_form, + "source".into(), + ResourceArrayType::Available, + stream, + ); } } else { let Some(browsing_context_id) = self.pipelines.get(&pipeline_id) else { @@ -563,7 +568,12 @@ impl DevtoolsInstance { let browsing_context = actors.find::(actor_name); for stream in self.connections.values_mut() { - browsing_context.resource_available(&source_form, "source".into(), stream); + browsing_context.resource_array( + &source_form, + "source".into(), + ResourceArrayType::Available, + stream, + ); } } } diff --git a/components/devtools/network_handler.rs b/components/devtools/network_handler.rs index 8e63269f6da..5d513a2a724 100644 --- a/components/devtools/network_handler.rs +++ b/components/devtools/network_handler.rs @@ -11,30 +11,8 @@ use serde::Serialize; use crate::actor::ActorRegistry; use crate::actors::browsing_context::BrowsingContextActor; use crate::actors::network_event::NetworkEventActor; -use crate::resource::ResourceAvailable; +use crate::resource::{ResourceArrayType, ResourceAvailable}; -#[derive(Clone, Serialize)] -struct ResourcesUpdatedArray { - updates: Vec, -} - -#[derive(Clone, Serialize)] -struct UpdateEntry { - #[serde(rename = "updateType")] - update_type: String, - data: serde_json::Value, -} - -#[derive(Serialize)] -#[serde(rename_all = "camelCase")] -struct EventTimingsUpdateMsg { - total_time: u64, -} - -#[derive(Serialize)] -struct SecurityInfoUpdateMsg { - state: String, -} #[derive(Clone, Serialize)] pub struct Cause { #[serde(rename = "type")] @@ -63,9 +41,10 @@ pub(crate) fn handle_network_event( let browsing_context_actor = actors.find::(&browsing_context_actor_name); for stream in &mut connections { - browsing_context_actor.resource_available( + browsing_context_actor.resource_array( event_actor.clone(), "network-event".to_string(), + ResourceArrayType::Available, stream, ); } @@ -76,56 +55,16 @@ pub(crate) fn handle_network_event( let actor = actors.find_mut::(&netevent_actor_name); // Store the response information in the actor actor.add_response(httpresponse); - ResourcesUpdatedArray { - updates: vec![ - UpdateEntry { - update_type: "requestHeaders".to_owned(), - data: serde_json::to_value(actor.request_headers()).unwrap(), - }, - UpdateEntry { - update_type: "requestCookies".to_owned(), - data: serde_json::to_value(actor.request_cookies()).unwrap(), - }, - UpdateEntry { - update_type: "responseStart".to_owned(), - data: serde_json::to_value(actor.response_start()).unwrap(), - }, - UpdateEntry { - update_type: "eventTimings".to_owned(), - data: serde_json::to_value(EventTimingsUpdateMsg { - total_time: actor.total_time().as_millis() as u64, - }) - .unwrap(), - }, - UpdateEntry { - update_type: "securityInfo".to_owned(), - data: serde_json::to_value(SecurityInfoUpdateMsg { - state: "insecure".to_owned(), - }) - .unwrap(), - }, - UpdateEntry { - update_type: "responseContent".to_owned(), - data: serde_json::to_value(actor.response_content()).unwrap(), - }, - UpdateEntry { - update_type: "responseCookies".to_owned(), - data: serde_json::to_value(actor.response_cookies()).unwrap(), - }, - UpdateEntry { - update_type: "responseHeaders".to_owned(), - data: serde_json::to_value(actor.response_headers()).unwrap(), - }, - ], - } + actor.resource_updates() }; let browsing_context_actor = actors.find::(&browsing_context_actor_name); for stream in &mut connections { - browsing_context_actor.resource_available( + browsing_context_actor.resource_array( resource.clone(), - "resources-updated".to_string(), + "network-event".to_string(), + ResourceArrayType::Updated, stream, ); } diff --git a/components/devtools/resource.rs b/components/devtools/resource.rs index 4e6aa4042b8..a4ae5f5d39e 100644 --- a/components/devtools/resource.rs +++ b/components/devtools/resource.rs @@ -8,6 +8,11 @@ use serde::Serialize; use crate::protocol::JsonPacketStream; +pub enum ResourceArrayType { + Available, + Updated, +} + #[derive(Serialize)] pub(crate) struct ResourceAvailableReply { pub from: String, @@ -19,24 +24,29 @@ pub(crate) struct ResourceAvailableReply { pub(crate) trait ResourceAvailable { fn actor_name(&self) -> String; - fn resource_available( + fn resource_array( &self, resource: T, resource_type: String, + array_type: ResourceArrayType, stream: &mut TcpStream, ) { - self.resources_available(vec![resource], resource_type, stream); + self.resources_array(vec![resource], resource_type, array_type, stream); } - fn resources_available( + fn resources_array( &self, resources: Vec, resource_type: String, + array_type: ResourceArrayType, stream: &mut TcpStream, ) { let msg = ResourceAvailableReply:: { from: self.actor_name(), - type_: "resources-available-array".into(), + type_: match array_type { + ResourceArrayType::Available => "resources-available-array".to_string(), + ResourceArrayType::Updated => "resources-updated-array".to_string(), + }, array: vec![(resource_type, resources)], };