mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Make the net monitor panel in FF's devtools show meaningful output.
0) Advertise support for the network monitor in the initial protocol communication. 1) Only notify the developer tools server about the final request in an HTTP transaction. 2) Add timing information for connecting to the HTTP server and sending the HTTP request. 3) Reduce duplication between various networkEventUpdate structures by creating a helper function that merges two JSON structures together. This also corrects the JSON structure so the devtools client interprets the output correctly. 4) Calculate various header size fields correctly. 5) Remove unnecessary usize->u32 casts by making the appropriate fields usize. 6) Add header values to request and response header messages. 7) Support triggering page reloads via the devtools client.
This commit is contained in:
parent
1f5b0008ac
commit
7bf2e19437
11 changed files with 252 additions and 155 deletions
|
@ -27,7 +27,10 @@ struct HttpRequest {
|
|||
method: Method,
|
||||
headers: Headers,
|
||||
body: Option<Vec<u8>>,
|
||||
startedDateTime: Tm
|
||||
startedDateTime: Tm,
|
||||
timeStamp: i64,
|
||||
connect_time: u64,
|
||||
send_time: u64,
|
||||
}
|
||||
|
||||
struct HttpResponse {
|
||||
|
@ -48,13 +51,14 @@ pub struct EventActor {
|
|||
pub url: String,
|
||||
pub method: String,
|
||||
pub startedDateTime: String,
|
||||
pub timeStamp: i64,
|
||||
pub isXHR: bool,
|
||||
pub private: bool
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseCookiesMsg {
|
||||
pub cookies: u32,
|
||||
pub cookies: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -64,7 +68,7 @@ pub struct ResponseStartMsg {
|
|||
pub remotePort: u32,
|
||||
pub status: String,
|
||||
pub statusText: String,
|
||||
pub headersSize: u32,
|
||||
pub headersSize: usize,
|
||||
pub discardResponseBody: bool,
|
||||
}
|
||||
|
||||
|
@ -79,29 +83,41 @@ pub struct ResponseContentMsg {
|
|||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResponseHeadersMsg {
|
||||
pub headers: u32,
|
||||
pub headersSize: u32,
|
||||
pub headers: usize,
|
||||
pub headersSize: usize,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RequestCookiesMsg {
|
||||
pub cookies: u32,
|
||||
pub cookies: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct RequestHeadersMsg {
|
||||
headers: usize,
|
||||
headersSize: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetRequestHeadersReply {
|
||||
from: String,
|
||||
headers: Vec<String>,
|
||||
headerSize: u8,
|
||||
headers: Vec<Header>,
|
||||
headerSize: usize,
|
||||
rawHeaders: String
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct Header {
|
||||
name: String,
|
||||
value: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetResponseHeadersReply {
|
||||
from: String,
|
||||
headers: Vec<String>,
|
||||
headerSize: u8,
|
||||
headers: Vec<Header>,
|
||||
headerSize: usize,
|
||||
rawHeaders: String
|
||||
}
|
||||
|
||||
|
@ -135,8 +151,8 @@ struct GetResponseCookiesReply {
|
|||
struct Timings {
|
||||
blocked: u32,
|
||||
dns: u32,
|
||||
connect: u32,
|
||||
send: u32,
|
||||
connect: u64,
|
||||
send: u64,
|
||||
wait: u32,
|
||||
receive: u32,
|
||||
}
|
||||
|
@ -145,16 +161,20 @@ struct Timings {
|
|||
struct GetEventTimingsReply {
|
||||
from: String,
|
||||
timings: Timings,
|
||||
totalTime: u32,
|
||||
totalTime: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SecurityInfo {
|
||||
state: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct GetSecurityInfoReply {
|
||||
from: String,
|
||||
seuritInfo: String,
|
||||
securityInfo: SecurityInfo,
|
||||
}
|
||||
|
||||
|
||||
impl Actor for NetworkEventActor {
|
||||
fn name(&self) -> String {
|
||||
self.name.clone()
|
||||
|
@ -167,19 +187,19 @@ impl Actor for NetworkEventActor {
|
|||
stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
"getRequestHeaders" => {
|
||||
// TODO: Pass the correct values for headers, headerSize, rawHeaders
|
||||
let headersSize = self.request.headers.len() as u8;
|
||||
let mut headerNames = Vec::new();
|
||||
let mut headers = Vec::new();
|
||||
let mut rawHeadersString = "".to_owned();
|
||||
let mut headersSize = 0;
|
||||
for item in self.request.headers.iter() {
|
||||
let name = item.name();
|
||||
let value = item.value_string();
|
||||
headerNames.push(name.to_owned());
|
||||
rawHeadersString = rawHeadersString + name + ":" + &value + "\r\n";
|
||||
headersSize += name.len() + value.len();
|
||||
headers.push(Header { name: name.to_owned(), value: value.to_owned() });
|
||||
}
|
||||
let msg = GetRequestHeadersReply {
|
||||
from: self.name(),
|
||||
headers: headerNames,
|
||||
headers: headers,
|
||||
headerSize: headersSize,
|
||||
rawHeaders: rawHeadersString,
|
||||
};
|
||||
|
@ -213,25 +233,32 @@ impl Actor for NetworkEventActor {
|
|||
ActorMessageStatus::Processed
|
||||
}
|
||||
"getResponseHeaders" => {
|
||||
if let Some(ref headers) = self.response.headers {
|
||||
let headersSize = headers.len() as u8;
|
||||
let mut headerNames = Vec::new();
|
||||
if let Some(ref response_headers) = self.response.headers {
|
||||
let mut headers = vec![];
|
||||
let mut rawHeadersString = "".to_owned();
|
||||
for item in headers.iter() {
|
||||
let mut headersSize = 0;
|
||||
for item in response_headers.iter() {
|
||||
let name = item.name();
|
||||
let value = item.value_string();
|
||||
headerNames.push(name.to_owned());
|
||||
rawHeadersString = rawHeadersString + name + ":" + &value + "\r\n";
|
||||
headers.push(Header {
|
||||
name: name.to_owned(),
|
||||
value: value.clone(),
|
||||
});
|
||||
headersSize += name.len() + value.len();
|
||||
rawHeadersString.push_str(name);
|
||||
rawHeadersString.push_str(":");
|
||||
rawHeadersString.push_str(&value);
|
||||
rawHeadersString.push_str("\r\n");
|
||||
}
|
||||
let msg = GetResponseHeadersReply {
|
||||
from: self.name(),
|
||||
headers: headerNames,
|
||||
headers: headers,
|
||||
headerSize: headersSize,
|
||||
rawHeaders: rawHeadersString,
|
||||
};
|
||||
stream.write_json_packet(&msg);
|
||||
}
|
||||
ActorMessageStatus::Processed
|
||||
ActorMessageStatus::Processed
|
||||
}
|
||||
"getResponseCookies" => {
|
||||
let mut cookies = Vec::new();
|
||||
|
@ -254,7 +281,7 @@ impl Actor for NetworkEventActor {
|
|||
let msg = GetResponseContentReply {
|
||||
from: self.name(),
|
||||
content: self.response.body.clone(),
|
||||
contentDiscarded: false,
|
||||
contentDiscarded: self.response.body.is_none(),
|
||||
};
|
||||
stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
|
@ -264,16 +291,17 @@ impl Actor for NetworkEventActor {
|
|||
let timingsObj = Timings {
|
||||
blocked: 0,
|
||||
dns: 0,
|
||||
connect: 0,
|
||||
send: 0,
|
||||
connect: self.request.connect_time,
|
||||
send: self.request.send_time,
|
||||
wait: 0,
|
||||
receive: 0,
|
||||
};
|
||||
let total = timingsObj.connect + timingsObj.send;
|
||||
// TODO: Send the correct values for all these fields.
|
||||
let msg = GetEventTimingsReply {
|
||||
from: self.name(),
|
||||
timings: timingsObj,
|
||||
totalTime: 0,
|
||||
totalTime: total,
|
||||
};
|
||||
stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
|
@ -282,7 +310,9 @@ impl Actor for NetworkEventActor {
|
|||
// TODO: Send the correct values for securityInfo.
|
||||
let msg = GetSecurityInfoReply {
|
||||
from: self.name(),
|
||||
seuritInfo: "".to_owned(),
|
||||
securityInfo: SecurityInfo {
|
||||
state: "insecure".to_owned()
|
||||
},
|
||||
};
|
||||
stream.write_json_packet(&msg);
|
||||
ActorMessageStatus::Processed
|
||||
|
@ -302,6 +332,9 @@ impl NetworkEventActor {
|
|||
headers: Headers::new(),
|
||||
body: None,
|
||||
startedDateTime: time::now(),
|
||||
timeStamp: time::get_time().sec,
|
||||
send_time: 0,
|
||||
connect_time: 0,
|
||||
},
|
||||
response: HttpResponse {
|
||||
headers: None,
|
||||
|
@ -317,6 +350,9 @@ impl NetworkEventActor {
|
|||
self.request.headers = request.headers.clone();
|
||||
self.request.body = request.body;
|
||||
self.request.startedDateTime = request.startedDateTime;
|
||||
self.request.timeStamp = request.timeStamp;
|
||||
self.request.connect_time = request.connect_time;
|
||||
self.request.send_time = request.send_time;
|
||||
}
|
||||
|
||||
pub fn add_response(&mut self, response: DevtoolsHttpResponse) {
|
||||
|
@ -332,6 +368,7 @@ impl NetworkEventActor {
|
|||
url: self.request.url.clone(),
|
||||
method: format!("{}", self.request.method),
|
||||
startedDateTime: format!("{}", self.request.startedDateTime.rfc3339()),
|
||||
timeStamp: self.request.timeStamp,
|
||||
isXHR: false,
|
||||
private: false,
|
||||
}
|
||||
|
@ -339,7 +376,7 @@ impl NetworkEventActor {
|
|||
|
||||
pub fn response_start(&self) -> ResponseStartMsg {
|
||||
// TODO: Send the correct values for all these fields.
|
||||
let hSizeOption = self.response.headers.as_ref().map(|headers| headers.len() as u32);
|
||||
let hSizeOption = self.response.headers.as_ref().map(|headers| headers.len());
|
||||
let hSize = hSizeOption.unwrap_or(0);
|
||||
let (status_code, status_message) = self.response.status.as_ref().
|
||||
map_or((0, "".to_owned()), |&RawStatus(ref code, ref text)| (*code, text.clone().into_owned()));
|
||||
|
@ -368,7 +405,7 @@ impl NetworkEventActor {
|
|||
mimeType: mString,
|
||||
contentSize: 0,
|
||||
transferredSize: 0,
|
||||
discardResponseBody: false,
|
||||
discardResponseBody: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -381,7 +418,7 @@ impl NetworkEventActor {
|
|||
};
|
||||
}
|
||||
ResponseCookiesMsg {
|
||||
cookies: cookies_size as u32,
|
||||
cookies: cookies_size,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -389,7 +426,7 @@ impl NetworkEventActor {
|
|||
let mut headers_size = 0;
|
||||
let mut headers_byte_count = 0;
|
||||
if let Some(ref headers) = self.response.headers {
|
||||
headers_size = headers.len() as u32;
|
||||
headers_size = headers.len();
|
||||
for item in headers.iter() {
|
||||
headers_byte_count += item.name().len() + item.value_string().len();
|
||||
}
|
||||
|
@ -397,21 +434,32 @@ impl NetworkEventActor {
|
|||
}
|
||||
ResponseHeadersMsg {
|
||||
headers: headers_size,
|
||||
headersSize: headers_byte_count as u32,
|
||||
headersSize: headers_byte_count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_headers(&self) -> RequestHeadersMsg {
|
||||
let size = self.request
|
||||
.headers
|
||||
.iter()
|
||||
.fold(0, |acc, h| acc + h.name().len() + h.value_string().len());
|
||||
RequestHeadersMsg {
|
||||
headers: self.request.headers.len(),
|
||||
headersSize: size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_cookies(&self) -> RequestCookiesMsg {
|
||||
let mut cookies_size = 0;
|
||||
if let Some(ref headers) = self.response.headers {
|
||||
cookies_size = match headers.get() {
|
||||
Some(&Cookie(ref cookie)) => cookie.len(),
|
||||
None => 0
|
||||
};
|
||||
}
|
||||
let cookies_size = match self.request.headers.get() {
|
||||
Some(&Cookie(ref cookie)) => cookie.len(),
|
||||
None => 0
|
||||
};
|
||||
RequestCookiesMsg {
|
||||
cookies: cookies_size as u32,
|
||||
cookies: cookies_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn total_time(&self) -> u64 {
|
||||
self.request.connect_time + self.request.send_time
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ use std::net::TcpStream;
|
|||
struct ActorTraits {
|
||||
sources: bool,
|
||||
highlightable: bool,
|
||||
customHighlighters: Vec<String>,
|
||||
customHighlighters: bool,
|
||||
networkMonitor: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
|
@ -117,7 +118,8 @@ impl RootActor {
|
|||
traits: ActorTraits {
|
||||
sources: true,
|
||||
highlightable: true,
|
||||
customHighlighters: vec!("BoxModelHighlighter".to_owned()),
|
||||
customHighlighters: true,
|
||||
networkMonitor: true
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
use actor::{Actor, ActorMessageStatus, ActorRegistry};
|
||||
use actors::console::ConsoleActor;
|
||||
use devtools_traits::DevtoolScriptControlMsg::WantsLiveNotifications;
|
||||
use devtools_traits::DevtoolScriptControlMsg::{self, WantsLiveNotifications};
|
||||
use protocol::JsonPacketStream;
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
|
@ -88,10 +88,19 @@ impl Actor for TabActor {
|
|||
fn handle_message(&self,
|
||||
registry: &ActorRegistry,
|
||||
msg_type: &str,
|
||||
_msg: &BTreeMap<String, Value>,
|
||||
msg: &BTreeMap<String, Value>,
|
||||
stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
|
||||
Ok(match msg_type {
|
||||
"reconfigure" => {
|
||||
if let Some(options) = msg.get("options").and_then(|o| o.as_object()) {
|
||||
if let Some(val) = options.get("performReload") {
|
||||
if val.as_boolean().unwrap_or(false) {
|
||||
let console_actor = registry.find::<ConsoleActor>(&self.console);
|
||||
let _ = console_actor.script_chan.send(
|
||||
DevtoolScriptControlMsg::Reload(console_actor.pipeline));
|
||||
}
|
||||
}
|
||||
}
|
||||
stream.write_json_packet(&ReconfigureReply { from: self.name() });
|
||||
ActorMessageStatus::Processed
|
||||
}
|
||||
|
|
|
@ -35,8 +35,7 @@ use actor::{Actor, ActorRegistry};
|
|||
use actors::console::ConsoleActor;
|
||||
use actors::framerate::FramerateActor;
|
||||
use actors::inspector::InspectorActor;
|
||||
use actors::network_event::{EventActor, NetworkEventActor, RequestCookiesMsg, ResponseCookiesMsg };
|
||||
use actors::network_event::{ResponseContentMsg, ResponseHeadersMsg, ResponseStartMsg };
|
||||
use actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg};
|
||||
use actors::performance::PerformanceActor;
|
||||
use actors::profiler::ProfilerActor;
|
||||
use actors::root::RootActor;
|
||||
|
@ -105,6 +104,24 @@ struct NetworkEventMsg {
|
|||
eventActor: EventActor,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct NetworkEventUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct EventTimingsUpdateMsg {
|
||||
totalTime: u64,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SecurityInfoUpdateMsg {
|
||||
state: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ResponseStartUpdateMsg {
|
||||
from: String,
|
||||
|
@ -114,60 +131,6 @@ struct ResponseStartUpdateMsg {
|
|||
response: ResponseStartMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ResponseContentUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
responseContent: ResponseContentMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ResponseCookiesUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
responseCookies: ResponseCookiesMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct ResponseHeadersUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
responseHeaders: ResponseHeadersMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct RequestCookiesUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
requestcookies: RequestCookiesMsg,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct EventTimingsUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
totalTime: u32,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SecurityInfoUpdateMsg {
|
||||
from: String,
|
||||
#[serde(rename = "type")]
|
||||
type_: String,
|
||||
updateType: String,
|
||||
securityState: String,
|
||||
}
|
||||
|
||||
/// Spin up a devtools server that listens for connections on the specified port.
|
||||
pub fn start_server(port: u16) -> Sender<DevtoolsControlMsg> {
|
||||
let (sender, receiver) = channel();
|
||||
|
@ -416,14 +379,22 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
|||
//Store the response information in the actor
|
||||
actor.add_response(httpresponse);
|
||||
|
||||
let msg7 = RequestCookiesUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "requestHeaders".to_owned(),
|
||||
};
|
||||
for stream in &mut connections {
|
||||
stream.write_merged_json_packet(&msg, &actor.request_headers());
|
||||
}
|
||||
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "requestCookies".to_owned(),
|
||||
requestcookies: actor.request_cookies(),
|
||||
};
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg7);
|
||||
stream.write_merged_json_packet(&msg, &actor.request_cookies());
|
||||
}
|
||||
|
||||
//Send a networkEventUpdate (responseStart) to the client
|
||||
|
@ -437,61 +408,56 @@ fn run_server(sender: Sender<DevtoolsControlMsg>,
|
|||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg);
|
||||
}
|
||||
let msg2 = EventTimingsUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "eventTimings".to_owned(),
|
||||
totalTime: 0
|
||||
};
|
||||
|
||||
let extra = EventTimingsUpdateMsg {
|
||||
totalTime: actor.total_time(),
|
||||
};
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg2);
|
||||
stream.write_merged_json_packet(&msg, &extra);
|
||||
}
|
||||
|
||||
let msg3 = SecurityInfoUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "securityInfo".to_owned(),
|
||||
securityState: "".to_owned(),
|
||||
};
|
||||
|
||||
let extra = SecurityInfoUpdateMsg {
|
||||
state: "insecure".to_owned(),
|
||||
};
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg3);
|
||||
stream.write_merged_json_packet(&msg, &extra);
|
||||
}
|
||||
|
||||
let msg4 = ResponseContentUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "responseContent".to_owned(),
|
||||
responseContent: actor.response_content(),
|
||||
};
|
||||
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg4);
|
||||
stream.write_merged_json_packet(&msg, &actor.response_content());
|
||||
}
|
||||
|
||||
let msg5 = ResponseCookiesUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "responseCookies".to_owned(),
|
||||
responseCookies: actor.response_cookies(),
|
||||
};
|
||||
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg5);
|
||||
stream.write_merged_json_packet(&msg, &actor.response_cookies());
|
||||
}
|
||||
|
||||
let msg6 = ResponseHeadersUpdateMsg {
|
||||
let msg = NetworkEventUpdateMsg {
|
||||
from: netevent_actor_name.clone(),
|
||||
type_: "networkEventUpdate".to_owned(),
|
||||
updateType: "responseHeaders".to_owned(),
|
||||
responseHeaders: actor.response_headers(),
|
||||
};
|
||||
|
||||
for stream in &mut connections {
|
||||
stream.write_json_packet(&msg6);
|
||||
stream.write_merged_json_packet(&msg, &actor.response_headers());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ pub struct Method {
|
|||
|
||||
pub trait JsonPacketStream {
|
||||
fn write_json_packet<T: Serialize>(&mut self, obj: &T);
|
||||
fn write_merged_json_packet<T: Serialize, U: Serialize>(&mut self, base: &T, extra: &U);
|
||||
fn read_json_packet(&mut self) -> Result<Option<Value>, String>;
|
||||
}
|
||||
|
||||
|
@ -38,6 +39,19 @@ impl JsonPacketStream for TcpStream {
|
|||
write!(self, "{}:{}", s.len(), s).unwrap();
|
||||
}
|
||||
|
||||
fn write_merged_json_packet<T: Serialize, U: Serialize>(&mut self, base: &T, extra: &U) {
|
||||
let mut obj = serde_json::to_value(base);
|
||||
let obj = obj.as_object_mut().unwrap();
|
||||
let extra = serde_json::to_value(extra);
|
||||
let extra = extra.as_object().unwrap();
|
||||
|
||||
for (key, value) in extra {
|
||||
obj.insert(key.to_owned(), value.to_owned());
|
||||
}
|
||||
|
||||
self.write_json_packet(obj);
|
||||
}
|
||||
|
||||
fn read_json_packet(&mut self) -> Result<Option<Value>, String> {
|
||||
// https://wiki.mozilla.org/Remote_Debugging_Protocol_Stream_Transport
|
||||
// In short, each JSON packet is [ascii length]:[JSON data of given length]
|
||||
|
|
|
@ -214,6 +214,8 @@ pub enum DevtoolScriptControlMsg {
|
|||
/// Request a callback directed at the given actor name from the next animation frame
|
||||
/// executed in the given pipeline.
|
||||
RequestAnimationFrame(PipelineId, String),
|
||||
/// Direct the given pipeline to reload the current page.
|
||||
Reload(PipelineId),
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize)]
|
||||
|
@ -292,7 +294,10 @@ pub struct HttpRequest {
|
|||
pub headers: Headers,
|
||||
pub body: Option<Vec<u8>>,
|
||||
pub pipeline_id: PipelineId,
|
||||
pub startedDateTime: Tm
|
||||
pub startedDateTime: Tm,
|
||||
pub timeStamp: i64,
|
||||
pub connect_time: u64,
|
||||
pub send_time: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
|
|
|
@ -816,7 +816,7 @@ fn http_network_fetch(request: Rc<Request>,
|
|||
|
||||
let mut response = Response::new();
|
||||
match wrapped_response {
|
||||
Ok(mut res) => {
|
||||
Ok((mut res, _)) => {
|
||||
response.url = Some(res.response.url.clone());
|
||||
response.status = Some(res.response.status);
|
||||
response.headers = res.response.headers.clone();
|
||||
|
|
|
@ -119,6 +119,10 @@ impl HttpState {
|
|||
}
|
||||
}
|
||||
|
||||
fn precise_time_ms() -> u64 {
|
||||
time::precise_time_ns() / (1000 * 1000)
|
||||
}
|
||||
|
||||
fn load_for_consumer(load_data: LoadData,
|
||||
start_chan: LoadConsumer,
|
||||
classifier: Arc<MIMEClassifier>,
|
||||
|
@ -552,21 +556,34 @@ enum Decoder {
|
|||
Plain(Box<HttpResponse>)
|
||||
}
|
||||
|
||||
fn send_request_to_devtools(devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
request_id: String,
|
||||
fn prepare_devtools_request(request_id: String,
|
||||
url: Url,
|
||||
method: Method,
|
||||
headers: Headers,
|
||||
body: Option<Vec<u8>>,
|
||||
pipeline_id: PipelineId, now: Tm) {
|
||||
if let Some(ref chan) = devtools_chan {
|
||||
let request = DevtoolsHttpRequest {
|
||||
url: url, method: method, headers: headers, body: body, pipeline_id: pipeline_id, startedDateTime: now };
|
||||
let net_event = NetworkEvent::HttpRequest(request);
|
||||
pipeline_id: PipelineId,
|
||||
now: Tm,
|
||||
connect_time: u64,
|
||||
send_time: u64) -> ChromeToDevtoolsControlMsg {
|
||||
let request = DevtoolsHttpRequest {
|
||||
url: url,
|
||||
method: method,
|
||||
headers: headers,
|
||||
body: body,
|
||||
pipeline_id: pipeline_id,
|
||||
startedDateTime: now,
|
||||
timeStamp: now.to_timespec().sec,
|
||||
connect_time: connect_time,
|
||||
send_time: send_time,
|
||||
};
|
||||
let net_event = NetworkEvent::HttpRequest(request);
|
||||
|
||||
let msg = ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event);
|
||||
chan.send(DevtoolsControlMsg::FromChrome(msg)).unwrap();
|
||||
}
|
||||
ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event)
|
||||
}
|
||||
|
||||
fn send_request_to_devtools(msg: ChromeToDevtoolsControlMsg,
|
||||
devtools_chan: &Sender<DevtoolsControlMsg>) {
|
||||
devtools_chan.send(DevtoolsControlMsg::FromChrome(msg)).unwrap();
|
||||
}
|
||||
|
||||
fn send_response_to_devtools(devtools_chan: Option<Sender<DevtoolsControlMsg>>,
|
||||
|
@ -701,10 +718,12 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>,
|
|||
iters: u32,
|
||||
devtools_chan: &Option<Sender<DevtoolsControlMsg>>,
|
||||
request_id: &str)
|
||||
-> Result<A::R, LoadError> where A: HttpRequest + 'static {
|
||||
-> Result<(A::R, Option<ChromeToDevtoolsControlMsg>), LoadError>
|
||||
where A: HttpRequest + 'static {
|
||||
let null_data = None;
|
||||
let response;
|
||||
let connection_url = replace_hosts(&url);
|
||||
let mut msg;
|
||||
|
||||
// loop trying connections in connection pool
|
||||
// they may have grown stale (disconnected), in which case we'll get
|
||||
|
@ -742,22 +761,36 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>,
|
|||
info!("{:?}", data);
|
||||
}
|
||||
|
||||
let connect_start = precise_time_ms();
|
||||
|
||||
let req = try!(request_factory.create(connection_url.clone(), method.clone(),
|
||||
headers.clone()));
|
||||
|
||||
let connect_end = precise_time_ms();
|
||||
|
||||
if cancel_listener.is_cancelled() {
|
||||
return Err(LoadError::new(connection_url.clone(), LoadErrorType::Cancelled));
|
||||
}
|
||||
|
||||
let send_start = precise_time_ms();
|
||||
|
||||
let maybe_response = req.send(request_body);
|
||||
|
||||
if let Some(pipeline_id) = *pipeline_id {
|
||||
send_request_to_devtools(
|
||||
devtools_chan.clone(), request_id.clone().into(),
|
||||
url.clone(), method.clone(), headers,
|
||||
request_body.clone(), pipeline_id, time::now()
|
||||
);
|
||||
}
|
||||
let send_end = precise_time_ms();
|
||||
|
||||
msg = if devtools_chan.is_some() {
|
||||
if let Some(pipeline_id) = *pipeline_id {
|
||||
Some(prepare_devtools_request(
|
||||
request_id.clone().into(),
|
||||
url.clone(), method.clone(), headers,
|
||||
request_body.clone(), pipeline_id, time::now(),
|
||||
connect_end - connect_start, send_end - send_start))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
response = match maybe_response {
|
||||
Ok(r) => r,
|
||||
|
@ -775,7 +808,7 @@ pub fn obtain_response<A>(request_factory: &HttpRequestFactory<R=A>,
|
|||
break;
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
Ok((response, msg))
|
||||
}
|
||||
|
||||
pub trait UIProvider {
|
||||
|
@ -914,9 +947,10 @@ pub fn load<A, B>(load_data: &LoadData,
|
|||
request_headers.set(auth_header.clone());
|
||||
}
|
||||
|
||||
let response = try!(obtain_response(request_factory, &doc_url, &method, &request_headers,
|
||||
&cancel_listener, &load_data.data, &load_data.method,
|
||||
&load_data.pipeline_id, iters, &devtools_chan, &request_id));
|
||||
let (response, msg) =
|
||||
try!(obtain_response(request_factory, &doc_url, &method, &request_headers,
|
||||
&cancel_listener, &load_data.data, &load_data.method,
|
||||
&load_data.pipeline_id, iters, &devtools_chan, &request_id));
|
||||
|
||||
process_response_headers(&response, &doc_url, &http_state.cookie_jar, &http_state.hsts_list, &load_data);
|
||||
|
||||
|
@ -1006,6 +1040,11 @@ pub fn load<A, B>(load_data: &LoadData,
|
|||
HttpsState::None
|
||||
};
|
||||
|
||||
// Only notify the devtools about the final request that received a response.
|
||||
if let Some(msg) = msg {
|
||||
send_request_to_devtools(msg, devtools_chan.as_ref().unwrap());
|
||||
}
|
||||
|
||||
// --- Tell devtools that we got a response
|
||||
// Send an HttpResponse message to devtools with the corresponding request_id
|
||||
// TODO: Send this message even when the load fails?
|
||||
|
|
|
@ -10,6 +10,7 @@ use dom::bindings::codegen::Bindings::CSSStyleDeclarationBinding::CSSStyleDeclar
|
|||
use dom::bindings::codegen::Bindings::DOMRectBinding::DOMRectMethods;
|
||||
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
|
||||
use dom::bindings::codegen::Bindings::ElementBinding::ElementMethods;
|
||||
use dom::bindings::codegen::Bindings::LocationBinding::LocationMethods;
|
||||
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||
use dom::bindings::conversions::{FromJSValConvertible, jsstring_to_str};
|
||||
use dom::bindings::global::GlobalRef;
|
||||
|
@ -250,3 +251,11 @@ pub fn handle_request_animation_frame(context: &BrowsingContext,
|
|||
devtools_sender.send(msg).unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
pub fn handle_reload(context: &BrowsingContext,
|
||||
id: PipelineId) {
|
||||
let context = context.find(id).expect("There is no such context");
|
||||
let win = context.active_window();
|
||||
let location = win.Location();
|
||||
location.Reload();
|
||||
}
|
||||
|
|
|
@ -1021,6 +1021,8 @@ impl ScriptThread {
|
|||
devtools::handle_drop_timeline_markers(&context, marker_types),
|
||||
DevtoolScriptControlMsg::RequestAnimationFrame(pipeline_id, name) =>
|
||||
devtools::handle_request_animation_frame(&context, pipeline_id, name),
|
||||
DevtoolScriptControlMsg::Reload(pipeline_id) =>
|
||||
devtools::handle_reload(&context, pipeline_id),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -503,7 +503,10 @@ fn test_request_and_response_data_with_network_messages() {
|
|||
headers: headers,
|
||||
body: None,
|
||||
pipeline_id: pipeline_id,
|
||||
startedDateTime: devhttprequest.startedDateTime
|
||||
startedDateTime: devhttprequest.startedDateTime,
|
||||
timeStamp: devhttprequest.timeStamp,
|
||||
connect_time: devhttprequest.connect_time,
|
||||
send_time: devhttprequest.send_time,
|
||||
};
|
||||
|
||||
let content = "Yay!";
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue