From 9f4a88bc48a8402dac272cea0bb3d9b7a6c37b32 Mon Sep 17 00:00:00 2001 From: Himaja Date: Tue, 21 Apr 2015 19:34:07 -0400 Subject: [PATCH] Initial changes for devtools support for logging HTTP requests. Add a NetworkEventActor to devtools/actors/ Authors: Ashritha Mohan Ram Himaja Valavala Anand Chandrasekar Yiyang Wang --- components/devtools/Cargo.toml | 4 ++ components/devtools/actors/network_event.rs | 68 ++++++++++++++++++ components/devtools/lib.rs | 79 +++++++++++++++++++++ components/devtools_traits/Cargo.toml | 1 + components/devtools_traits/lib.rs | 9 ++- components/net/Cargo.toml | 3 + components/net/http_loader.rs | 19 ++++- components/net/lib.rs | 1 + components/net/resource_task.rs | 12 ++-- components/servo/lib.rs | 2 +- 10 files changed, 189 insertions(+), 9 deletions(-) create mode 100644 components/devtools/actors/network_event.rs diff --git a/components/devtools/Cargo.toml b/components/devtools/Cargo.toml index 6503aa125cb..683c4c49e7d 100644 --- a/components/devtools/Cargo.toml +++ b/components/devtools/Cargo.toml @@ -16,6 +16,10 @@ path = "../msg" [dependencies.util] path = "../util" +[dependencies] +url = "0.2.16" +hyper = "0.3" + [dependencies] time = "*" rustc-serialize = "0.3" diff --git a/components/devtools/actors/network_event.rs b/components/devtools/actors/network_event.rs new file mode 100644 index 00000000000..24e63f6a5b4 --- /dev/null +++ b/components/devtools/actors/network_event.rs @@ -0,0 +1,68 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/// Liberally derived from the [Firefox JS implementation](http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/webconsole.js). +/// Mediates interaction between the remote web console and equivalent functionality (object +/// inspection, JS evaluation, autocompletion) in Servo. + +extern crate hyper; +extern crate url; + +use actor::{Actor, ActorRegistry}; +use protocol::JsonPacketStream; + +use devtools_traits::DevtoolScriptControlMsg; +use msg::constellation_msg::PipelineId; + +use collections::BTreeMap; +use core::cell::RefCell; +use rustc_serialize::json::{self, Json, ToJson}; +use std::net::TcpStream; +use std::num::Float; +use std::sync::mpsc::{channel, Sender}; + +use url::Url; +use hyper::header::Headers; +use hyper::http::RawStatus; +use hyper::method::Method; + +#[derive(RustcEncodable)] +pub struct HttpRequest { + pub url: Url, + //method: Method, + //headers: Headers, + pub body: Option>, +} + +#[derive(RustcEncodable)] +pub struct NetworkEventActor { + pub name: String, + pub request: HttpRequest, +} + +impl Actor for NetworkEventActor { + fn name(&self) -> String { + self.name.clone() + } + + fn handle_message(&self, + _registry: &ActorRegistry, + msg_type: &str, + msg: &json::Object, + stream: &mut TcpStream) -> Result { + Ok(match msg_type { + + "getRequestHeaders" => { + //stream.write_json_packet(&msg); + true + } + + "getRequestCookies" => { + true + } + + _ => false + }) + } +} diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 348c4fdeb12..220c10b63b9 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -25,9 +25,13 @@ extern crate rustc_serialize; extern crate msg; extern crate time; extern crate util; +extern crate url; +extern crate hyper; use actor::{Actor, ActorRegistry}; use actors::console::ConsoleActor; +use actors::network_event::NetworkEventActor; +use actors::network_event::{HttpRequest}; use actors::worker::WorkerActor; use actors::inspector::InspectorActor; use actors::root::RootActor; @@ -49,6 +53,12 @@ use std::net::{TcpListener, TcpStream, Shutdown}; use std::sync::{Arc, Mutex}; use time::precise_time_ns; +use url::Url; + +use hyper::header::Headers; +use hyper::http::RawStatus; +use hyper::method::Method; + mod actor; /// Corresponds to http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/ mod actors { @@ -60,6 +70,7 @@ mod actors { pub mod tab; pub mod timeline; pub mod worker; + pub mod network_event; } mod protocol; @@ -80,6 +91,22 @@ struct ConsoleMsg { columnNumber: u32, } +#[derive(RustcEncodable)] +struct NetworkEventMsg { + from: String, + __type__: String, + eventActor: EventActor, +} + +#[derive(RustcEncodable)] +struct EventActor { + actor: NetworkEventActor, + url: String, + method: String, + startedDateTime: String, + isXHR: String, +} + /// Spin up a devtools server that listens for connections on the specified port. pub fn start_server(port: u16) -> Sender { let (sender, receiver) = channel(); @@ -252,6 +279,49 @@ fn run_server(sender: Sender, return console_actor_name; } + fn handle_network_event(actors: Arc>, + connections: RefCell>, + url: Url, + method: Method, + headers: Headers, + body: Option>) { + + //println!("handle_network_event"); + let mut actors = actors.lock().unwrap(); + + /* TODO: Maintain a HashMap that maps request/response ID to actor name. + * Check if the map contains the ID of the request/response message. + * If no actor exists, create a new one. + * Store to stream(s) to the actor and retrieve them. + */ + + let actor = NetworkEventActor { + name: actors.new_name("network_event"), + request: HttpRequest { + url: url.clone(), + //method: method.clone(), + //headers: headers.clone(), + body: body.clone() + }, + }; + + let msg = NetworkEventMsg { + from: actor.name.clone(), + __type__: "networkEvent".to_string(), + eventActor: EventActor { + actor: actor, + url: url.serialize(), + method: "".to_string(), + startedDateTime: "".to_string(), + isXHR: "false".to_string(), + }, + }; + + for stream in connections.borrow_mut().iter_mut() { + stream.write_json_packet(&msg); + } + } + spawn_named("DevtoolsClientAcceptor".to_owned(), move || { // accept connections and process them, spawning a new task for each one for stream in listener.incoming() { @@ -276,6 +346,15 @@ fn run_server(sender: Sender, Ok(DevtoolsControlMsg::SendConsoleMessage(id, console_message)) => handle_console_message(actors.clone(), id, console_message, &actor_pipelines), + + Ok(DevtoolsControlMsg::HttpRequest(url, method, headers, body)) => { + //println!("run_server: HttpRequest"); + let connections = RefCell::new(Vec::::new()); + let mut stream = accepted_connections.get_mut(0).unwrap(); + connections.borrow_mut().push(stream.try_clone().unwrap()); + handle_network_event(actors.clone(), connections, url, method, headers, body); + } + _ => break, } } diff --git a/components/devtools_traits/Cargo.toml b/components/devtools_traits/Cargo.toml index 0788d874c3a..586c8ecf82f 100644 --- a/components/devtools_traits/Cargo.toml +++ b/components/devtools_traits/Cargo.toml @@ -15,6 +15,7 @@ path = "../util" [dependencies] url = "0.2.16" +hyper = "0.3" [dependencies] time = "*" diff --git a/components/devtools_traits/lib.rs b/components/devtools_traits/lib.rs index 9be18bf5e19..df7eb0ac632 100644 --- a/components/devtools_traits/lib.rs +++ b/components/devtools_traits/lib.rs @@ -14,6 +14,7 @@ extern crate msg; extern crate rustc_serialize; extern crate url; +extern crate hyper; extern crate util; extern crate time; @@ -22,6 +23,10 @@ use msg::constellation_msg::{PipelineId, WorkerId}; use util::str::DOMString; use url::Url; +use hyper::header::Headers; +use hyper::http::RawStatus; +use hyper::method::Method; + use std::net::TcpStream; use std::sync::mpsc::{Sender, Receiver}; @@ -41,7 +46,9 @@ pub enum DevtoolsControlMsg { AddClient(TcpStream), NewGlobal((PipelineId, Option), Sender, DevtoolsPageInfo), SendConsoleMessage(PipelineId, ConsoleMessage), - ServerExitMsg + ServerExitMsg, + HttpRequest(Url, Method, Headers, Option>), + HttpResponse(Option, RawStatus, Vec) } /// Serialized JS return values diff --git a/components/net/Cargo.toml b/components/net/Cargo.toml index cb4c6038b43..2f39830279e 100644 --- a/components/net/Cargo.toml +++ b/components/net/Cargo.toml @@ -13,6 +13,9 @@ path = "../net_traits" [dependencies.util] path = "../util" +[dependencies.devtools_traits] +path = "../devtools_traits" + [dependencies.geom] git = "https://github.com/servo/rust-geom" diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index dec8727daad..9d36e9f247d 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -4,6 +4,7 @@ use net_traits::{ControlMsg, CookieSource, LoadData, Metadata, LoadConsumer}; use net_traits::ProgressMsg::{Payload, Done}; +use devtools_traits::{DevtoolsControlMsg}; use mime_classifier::MIMEClassifier; use resource_task::{start_sending_opt, start_sending_sniffed_opt}; @@ -31,10 +32,10 @@ use url::{Url, UrlParser}; use std::borrow::ToOwned; use std::boxed::FnBox; -pub fn factory(cookies_chan: Sender) +pub fn factory(cookies_chan: Sender, devtools_chan: Option>) -> Box) + Send> { box move |load_data, senders, classifier| { - spawn_named("http_loader".to_owned(), move || load(load_data, senders, classifier, cookies_chan)) + spawn_named("http_loader".to_owned(), move || load(load_data, senders, classifier, cookies_chan, devtools_chan)) } } @@ -66,7 +67,8 @@ fn read_block(reader: &mut R) -> Result { } } -fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc, cookies_chan: Sender) { +fn load(mut load_data: LoadData, start_chan: LoadConsumer, classifier: Arc, + cookies_chan: Sender, devtools_chan: Option>) { // FIXME: At the time of writing this FIXME, servo didn't have any central // location for configuration. If you're reading this and such a // repository DOES exist, please update this constant to use it. @@ -197,6 +199,17 @@ reason: \"certificate verify failed\" }]))"; info!("{:?}", load_data.data); } +/* + match devtools_chan { + Some(chan) => chan.send(DevtoolsControlMsg::HttpRequest(load_data.url.clone(), load_data.method.clone(), load_data.headers.clone(), load_data.data.clone())).unwrap(), + None => {} + } +*/ + + println!("load"); + devtools_chan.as_ref().map(|chan| chan.send(DevtoolsControlMsg::HttpRequest(load_data.url.clone(), load_data.method.clone(), load_data.headers.clone(), load_data.data.clone())).unwrap()); + + // Avoid automatically sending request body if a redirect has occurred. let writer = match load_data.data { Some(ref data) if iters == 1 => { diff --git a/components/net/lib.rs b/components/net/lib.rs index 8ab60ead069..b64c38b0f49 100644 --- a/components/net/lib.rs +++ b/components/net/lib.rs @@ -16,6 +16,7 @@ extern crate net_traits; extern crate cookie as cookie_rs; +extern crate devtools_traits; extern crate collections; extern crate flate2; extern crate geom; diff --git a/components/net/resource_task.rs b/components/net/resource_task.rs index cac46cbce8b..ac463503a1b 100644 --- a/components/net/resource_task.rs +++ b/components/net/resource_task.rs @@ -18,6 +18,7 @@ use net_traits::ProgressMsg::Done; use util::opts; use util::task::spawn_named; +use devtools_traits::{DevtoolsControlMsg}; use hyper::header::{ContentType, Header, SetCookie, UserAgent}; use hyper::mime::{Mime, TopLevel, SubLevel}; @@ -31,6 +32,7 @@ use std::str::FromStr; use std::sync::Arc; use std::sync::mpsc::{channel, Receiver, Sender}; + static mut HOST_TABLE: Option<*mut HashMap> = None; pub fn global_init() { @@ -136,11 +138,11 @@ pub fn start_sending_opt(start_chan: LoadConsumer, metadata: Metadata) -> Result } /// Create a ResourceTask -pub fn new_resource_task(user_agent: Option) -> ResourceTask { +pub fn new_resource_task(user_agent: Option, devtools_chan: Option>) -> ResourceTask { let (setup_chan, setup_port) = channel(); let setup_chan_clone = setup_chan.clone(); spawn_named("ResourceManager".to_owned(), move || { - ResourceManager::new(setup_port, user_agent, setup_chan_clone).start(); + ResourceManager::new(setup_port, user_agent, setup_chan_clone, devtools_chan).start(); }); setup_chan } @@ -185,17 +187,19 @@ struct ResourceManager { cookie_storage: CookieStorage, resource_task: Sender, mime_classifier: Arc, + devtools_chan: Option> } impl ResourceManager { fn new(from_client: Receiver, user_agent: Option, - resource_task: Sender) -> ResourceManager { + resource_task: Sender, devtools_channel: Option>) -> ResourceManager { ResourceManager { from_client: from_client, user_agent: user_agent, cookie_storage: CookieStorage::new(), resource_task: resource_task, mime_classifier: Arc::new(MIMEClassifier::new()), + devtools_chan: devtools_channel } } } @@ -246,7 +250,7 @@ impl ResourceManager { let loader = match &*load_data.url.scheme { "file" => from_factory(file_loader::factory), - "http" | "https" | "view-source" => http_loader::factory(self.resource_task.clone()), + "http" | "https" | "view-source" => http_loader::factory(self.resource_task.clone(), self.devtools_chan.clone()), "data" => from_factory(data_loader::factory), "about" => from_factory(about_loader::factory), _ => { diff --git a/components/servo/lib.rs b/components/servo/lib.rs index f3837112a82..df86056cace 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -155,7 +155,7 @@ fn create_constellation(opts: opts::Opts, use std::env; // Create a Servo instance. - let resource_task = new_resource_task(opts.user_agent.clone()); + let resource_task = new_resource_task(opts.user_agent.clone(), devtools_chan.clone()); let image_cache_task = new_image_cache_task(resource_task.clone()); let font_cache_task = FontCacheTask::new(resource_task.clone());