diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2015-12-21 21:17:25 +0530 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2015-12-21 21:17:25 +0530 |
commit | a8783ad184ab6167803af44f4abf16754c410c2a (patch) | |
tree | 95668f8e57602487433baedc87fc22c9fbb850d8 | |
parent | 552df7e79e283621b93028501a3362d698916f6b (diff) | |
parent | f889b1ccd7849e594d66a27e5c0fd8095e7242ec (diff) | |
download | servo-a8783ad184ab6167803af44f4abf16754c410c2a.tar.gz servo-a8783ad184ab6167803af44f4abf16754c410c2a.zip |
Auto merge of #8845 - akumar21NCSU:master, r=jdm
M1502: Expand HTTP request response monitoring-2
<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8845)
<!-- Reviewable:end -->
-rw-r--r-- | components/devtools/actors/network_event.rs | 283 | ||||
-rw-r--r-- | components/devtools/lib.rs | 125 | ||||
-rw-r--r-- | components/devtools_traits/lib.rs | 2 | ||||
-rw-r--r-- | components/net/http_loader.rs | 20 | ||||
-rw-r--r-- | tests/unit/net/http_loader.rs | 2 |
5 files changed, 405 insertions, 27 deletions
diff --git a/components/devtools/actors/network_event.rs b/components/devtools/actors/network_event.rs index 262e1e4696b..317dc096157 100644 --- a/components/devtools/actors/network_event.rs +++ b/components/devtools/actors/network_event.rs @@ -12,17 +12,21 @@ use actor::{Actor, ActorMessageStatus, ActorRegistry}; use devtools_traits::HttpRequest as DevtoolsHttpRequest; use devtools_traits::HttpResponse as DevtoolsHttpResponse; use hyper::header::Headers; +use hyper::header::{ContentType, Cookie}; use hyper::http::RawStatus; use hyper::method::Method; use protocol::JsonPacketStream; use rustc_serialize::json; use std::net::TcpStream; +use time; +use time::Tm; struct HttpRequest { url: String, method: Method, headers: Headers, body: Option<Vec<u8>>, + startedDateTime: Tm } struct HttpResponse { @@ -48,6 +52,11 @@ pub struct EventActor { } #[derive(RustcEncodable)] +pub struct ResponseCookiesMsg { + pub cookies: u32, +} + +#[derive(RustcEncodable)] pub struct ResponseStartMsg { pub httpVersion: String, pub remoteAddress: String, @@ -59,6 +68,27 @@ pub struct ResponseStartMsg { } #[derive(RustcEncodable)] +pub struct ResponseContentMsg { + pub mimeType: String, + pub contentSize: u32, + pub transferredSize: u32, + pub discardResponseBody: bool, +} + + +#[derive(RustcEncodable)] +pub struct ResponseHeadersMsg { + pub headers: u32, + pub headersSize: u32, +} + + +#[derive(RustcEncodable)] +pub struct RequestCookiesMsg { + pub cookies: u32, +} + +#[derive(RustcEncodable)] struct GetRequestHeadersReply { from: String, headers: Vec<String>, @@ -66,6 +96,64 @@ struct GetRequestHeadersReply { rawHeaders: String } +#[derive(RustcEncodable)] +struct GetResponseHeadersReply { + from: String, + headers: Vec<String>, + headerSize: u8, + rawHeaders: String +} + +#[derive(RustcEncodable)] +struct GetResponseContentReply { + from: String, + content: Option<Vec<u8>>, + contentDiscarded: bool, +} + +#[derive(RustcEncodable)] +struct GetRequestPostDataReply { + from: String, + postData: Option<Vec<u8>>, + postDataDiscarded: bool +} + +#[derive(RustcEncodable)] +struct GetRequestCookiesReply { + from: String, + cookies: Vec<u8> +} + +#[derive(RustcEncodable)] +struct GetResponseCookiesReply { + from: String, + cookies: Vec<u8> +} + +#[derive(RustcEncodable)] +struct Timings { + blocked: u32, + dns: u32, + connect: u32, + send: u32, + wait: u32, + receive: u32, +} + +#[derive(RustcEncodable)] +struct GetEventTimingsReply { + from: String, + timings: Timings, + totalTime: u32, +} + +#[derive(RustcEncodable)] +struct GetSecurityInfoReply { + from: String, + seuritInfo: String, +} + + impl Actor for NetworkEventActor { fn name(&self) -> String { self.name.clone() @@ -79,29 +167,124 @@ impl Actor for NetworkEventActor { 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 rawHeadersString = "".to_owned(); + 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"; + } let msg = GetRequestHeadersReply { from: self.name(), - headers: Vec::new(), - headerSize: 10, - rawHeaders: "Raw headers".to_owned(), + headers: headerNames, + headerSize: headersSize, + rawHeaders: rawHeadersString, }; stream.write_json_packet(&msg); ActorMessageStatus::Processed } "getRequestCookies" => { - ActorMessageStatus::Ignored + let mut cookies = Vec::new(); + if let Some(req_cookies) = self.request.headers.get_raw("Cookie") { + for cookie in &*req_cookies { + if let Ok(cookie_value) = String::from_utf8(cookie.clone()) { + cookies = cookie_value.into_bytes(); + } + } + } + + let msg = GetRequestCookiesReply { + from: self.name(), + cookies: cookies, + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed } "getRequestPostData" => { - ActorMessageStatus::Ignored + let msg = GetRequestPostDataReply { + from: self.name(), + postData: self.request.body.clone(), + postDataDiscarded: false, + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed } "getResponseHeaders" => { - ActorMessageStatus::Ignored + if let Some(ref headers) = self.response.headers { + let headersSize = headers.len() as u8; + let mut headerNames = Vec::new(); + let mut rawHeadersString = "".to_owned(); + for item in headers.iter() { + let name = item.name(); + let value = item.value_string(); + headerNames.push(name.to_owned()); + rawHeadersString = rawHeadersString + name + ":" + &value + "\r\n"; + } + let msg = GetResponseHeadersReply { + from: self.name(), + headers: headerNames, + headerSize: headersSize, + rawHeaders: rawHeadersString, + }; + stream.write_json_packet(&msg); + } + ActorMessageStatus::Processed } "getResponseCookies" => { - ActorMessageStatus::Ignored + let mut cookies = Vec::new(); + if let Some(res_cookies) = self.request.headers.get_raw("set-cookie") { + for cookie in &*res_cookies { + if let Ok(cookie_value) = String::from_utf8(cookie.clone()) { + cookies = cookie_value.into_bytes(); + } + } + } + + let msg = GetResponseCookiesReply { + from: self.name(), + cookies: cookies, + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed } "getResponseContent" => { - ActorMessageStatus::Ignored + let msg = GetResponseContentReply { + from: self.name(), + content: self.response.body.clone(), + contentDiscarded: false, + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed + } + "getEventTimings" => { + // TODO: This is a fake timings msg + let timingsObj = Timings { + blocked: 0, + dns: 0, + connect: 0, + send: 0, + wait: 0, + receive: 0, + }; + // TODO: Send the correct values for all these fields. + let msg = GetEventTimingsReply { + from: self.name(), + timings: timingsObj, + totalTime: 0, + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed + } + "getSecurityInfo" => { + // TODO: Send the correct values for securityInfo. + let msg = GetSecurityInfoReply { + from: self.name(), + seuritInfo: "".to_owned(), + }; + stream.write_json_packet(&msg); + ActorMessageStatus::Processed } _ => ActorMessageStatus::Ignored }) @@ -116,7 +299,8 @@ impl NetworkEventActor { url: String::new(), method: Method::Get, headers: Headers::new(), - body: None + body: None, + startedDateTime: time::now(), }, response: HttpResponse { headers: None, @@ -131,6 +315,7 @@ impl NetworkEventActor { self.request.method = request.method.clone(); self.request.headers = request.headers.clone(); self.request.body = request.body; + self.request.startedDateTime = request.startedDateTime; } pub fn add_response(&mut self, response: DevtoolsHttpResponse) { @@ -145,7 +330,7 @@ impl NetworkEventActor { actor: self.name(), url: self.request.url.clone(), method: format!("{}", self.request.method), - startedDateTime: "2015-04-22T20:47:08.545Z".to_owned(), + startedDateTime: format!("{}", self.request.startedDateTime.rfc3339()), isXHR: false, private: false, } @@ -153,15 +338,83 @@ impl NetworkEventActor { pub fn response_start(&self) -> ResponseStartMsg { // TODO: Send the correct values for all these fields. - // This is a fake message. + let hSizeOption = self.response.headers.as_ref().map(|headers| headers.len() as u32); + let hSize = hSizeOption.unwrap_or(0); + let (status_code, status_message) = + self.response.status.as_ref().map(|&RawStatus(ref code, ref text)| (*code, text.clone().into_owned())). + unwrap_or((0, "".to_owned())); + // TODO: Send the correct values for remoteAddress and remotePort and http_version. ResponseStartMsg { httpVersion: "HTTP/1.1".to_owned(), remoteAddress: "63.245.217.43".to_owned(), remotePort: 443, - status: "200".to_owned(), - statusText: "OK".to_owned(), - headersSize: 337, - discardResponseBody: true + status: status_code.to_string(), + statusText: status_message, + headersSize: hSize, + discardResponseBody: false } } + + pub fn response_content(&self) -> ResponseContentMsg { + let mut mString = "".to_owned(); + if let Some(ref headers) = self.response.headers { + mString = match headers.get() { + Some(&ContentType(ref mime)) => mime.to_string(), + None => "".to_owned() + }; + } + // TODO: Set correct values when response's body is sent to the devtools in http_loader. + ResponseContentMsg { + mimeType: mString, + contentSize: 0, + transferredSize: 0, + discardResponseBody: false, + } + } + + pub fn response_cookies(&self) -> ResponseCookiesMsg { + + 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 + }; + } + ResponseCookiesMsg { + cookies: cookies_size as u32, + } + } + + pub fn response_headers(&self) -> ResponseHeadersMsg { + + 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; + for item in headers.iter() { + headers_byte_count += item.name().len() + item.value_string().len(); + } + + } + ResponseHeadersMsg { + headers: headers_size, + headersSize: headers_byte_count as u32, + } + } + + 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 + }; + } + RequestCookiesMsg { + cookies: cookies_size as u32, + } + } + } diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 5d1a34b52e9..85d360e701c 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -35,7 +35,8 @@ use actor::{Actor, ActorRegistry}; use actors::console::ConsoleActor; use actors::framerate::FramerateActor; use actors::inspector::InspectorActor; -use actors::network_event::{EventActor, NetworkEventActor, ResponseStartMsg}; +use actors::network_event::{EventActor, NetworkEventActor, RequestCookiesMsg, ResponseCookiesMsg }; +use actors::network_event::{ResponseContentMsg, ResponseHeadersMsg, ResponseStartMsg }; use actors::performance::PerformanceActor; use actors::profiler::ProfilerActor; use actors::root::RootActor; @@ -102,13 +103,61 @@ struct NetworkEventMsg { } #[derive(RustcEncodable)] -struct NetworkEventUpdateMsg { +struct ResponseStartUpdateMsg { from: String, __type__: String, updateType: String, response: ResponseStartMsg, } +#[derive(RustcEncodable)] +struct ResponseContentUpdateMsg { + from: String, + __type__: String, + updateType: String, + responseContent: ResponseContentMsg, +} + +#[derive(RustcEncodable)] +struct ResponseCookiesUpdateMsg { + from: String, + __type__: String, + updateType: String, + responseCookies: ResponseCookiesMsg, +} + +#[derive(RustcEncodable)] +struct ResponseHeadersUpdateMsg { + from: String, + __type__: String, + updateType: String, + responseHeaders: ResponseHeadersMsg, +} + +#[derive(RustcEncodable)] +struct RequestCookiesUpdateMsg { + from: String, + __type__: String, + updateType: String, + requestcookies: RequestCookiesMsg, +} + +#[derive(RustcEncodable)] +struct EventTimingsUpdateMsg { + from: String, + __type__: String, + updateType: String, + totalTime: u32, +} + +#[derive(RustcEncodable)] +struct SecurityInfoUpdateMsg { + from: String, + __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(); @@ -348,14 +397,25 @@ fn run_server(sender: Sender<DevtoolsControlMsg>, for stream in &mut connections { stream.write_json_packet(&msg); } + } NetworkEvent::HttpResponse(httpresponse) => { //Store the response information in the actor actor.add_response(httpresponse); + let msg7 = RequestCookiesUpdateMsg { + 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); + } + //Send a networkEventUpdate (responseStart) to the client - let msg = NetworkEventUpdateMsg { - from: netevent_actor_name, + let msg = ResponseStartUpdateMsg { + from: netevent_actor_name.clone(), __type__: "networkEventUpdate".to_owned(), updateType: "responseStart".to_owned(), response: actor.response_start() @@ -364,9 +424,62 @@ fn run_server(sender: Sender<DevtoolsControlMsg>, for stream in &mut connections { stream.write_json_packet(&msg); } + let msg2 = EventTimingsUpdateMsg { + from: netevent_actor_name.clone(), + __type__: "networkEventUpdate".to_owned(), + updateType: "eventTimings".to_owned(), + totalTime: 0 + }; + + for stream in &mut connections { + stream.write_json_packet(&msg2); + } + + let msg3 = SecurityInfoUpdateMsg { + from: netevent_actor_name.clone(), + __type__: "networkEventUpdate".to_owned(), + updateType: "securityInfo".to_owned(), + securityState: "".to_owned(), + }; + + for stream in &mut connections { + stream.write_json_packet(&msg3); + } + + let msg4 = ResponseContentUpdateMsg { + 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); + } + + let msg5 = ResponseCookiesUpdateMsg { + 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); + } + + let msg6 = ResponseHeadersUpdateMsg { + 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); + } + } - //TODO: Send the other types of update messages at appropriate times - // requestHeaders, requestCookies, responseHeaders, securityInfo, etc } } diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index 9b43581b72a..b914e8dfda2 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -34,6 +34,7 @@ use msg::constellation_msg::PipelineId; use rustc_serialize::{Decodable, Decoder}; use std::net::TcpStream; use time::Duration; +use time::Tm; use url::Url; // Information would be attached to NewGlobal to be received and show in devtools. @@ -264,6 +265,7 @@ pub struct HttpRequest { pub headers: Headers, pub body: Option<Vec<u8>>, pub pipeline_id: PipelineId, + pub startedDateTime: Tm } #[derive(Debug, PartialEq)] diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index d222e6fb11d..3a64c959570 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -37,6 +37,8 @@ use std::error::Error; use std::io::{self, Read, Write}; use std::sync::mpsc::Sender; use std::sync::{Arc, RwLock}; +use time; +use time::Tm; use url::Url; use util::resource_files::resources_dir_path; use util::task::spawn_named; @@ -174,7 +176,9 @@ pub trait HttpResponse: Read { fn headers(&self) -> &Headers; fn status(&self) -> StatusCode; fn status_raw(&self) -> &RawStatus; - + fn http_version(&self) -> String { + return "HTTP/1.1".to_owned() + } fn content_encoding(&self) -> Option<Encoding> { self.headers().get::<ContentEncoding>().and_then(|h| { match *h { @@ -192,6 +196,7 @@ pub trait HttpResponse: Read { } } + struct WrappedHttpResponse { response: Response } @@ -203,6 +208,8 @@ impl Read for WrappedHttpResponse { } } + + impl HttpResponse for WrappedHttpResponse { fn headers(&self) -> &Headers { &self.response.headers @@ -215,6 +222,10 @@ impl HttpResponse for WrappedHttpResponse { fn status_raw(&self) -> &RawStatus { self.response.status_raw() } + + fn http_version(&self) -> String { + self.response.version.to_string() + } } pub trait HttpRequestFactory { @@ -468,11 +479,11 @@ fn send_request_to_devtools(devtools_chan: Option<Sender<DevtoolsControlMsg>>, method: Method, headers: Headers, body: Option<Vec<u8>>, - pipeline_id: PipelineId) { + 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 }; + url: url, method: method, headers: headers, body: body, pipeline_id: pipeline_id, startedDateTime: now }; let net_event = NetworkEvent::HttpRequest(request); let msg = ChromeToDevtoolsControlMsg::NetworkEvent(request_id, net_event); @@ -660,12 +671,11 @@ pub fn load<A>(load_data: LoadData, req.send(&None) } }; - if let Some(pipeline_id) = load_data.pipeline_id { send_request_to_devtools( devtools_chan.clone(), request_id.clone(), url.clone(), method.clone(), request_headers.clone(), - cloned_data, pipeline_id + cloned_data, pipeline_id, time::now() ); } diff --git a/tests/unit/net/http_loader.rs b/tests/unit/net/http_loader.rs index ed541b67046..75f334cd487 100644 --- a/tests/unit/net/http_loader.rs +++ b/tests/unit/net/http_loader.rs @@ -460,13 +460,13 @@ fn test_request_and_response_data_with_network_messages() { ]); headers.set(accept); headers.set(UserAgent(DEFAULT_USER_AGENT.to_owned())); - let httprequest = DevtoolsHttpRequest { url: url, method: Method::Get, headers: headers, body: None, pipeline_id: pipeline_id, + startedDateTime: devhttprequest.startedDateTime }; let content = "Yay!"; |