diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 796ebb85c31..1ad6bb526d6 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1861,7 +1861,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.2.3" -source = "git+https://github.com/jgraham/webdriver-rust.git#80b3fdf3f7412066268e00df25087200cbb47cca" +source = "git+https://github.com/jgraham/webdriver-rust.git#1b5007fbea3caf302cb215dbc2ad21e0402344eb" dependencies = [ "hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1874,10 +1874,12 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ + "hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "png 0.1.0 (git+https://github.com/servo/rust-png)", + "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", diff --git a/components/webdriver_server/Cargo.toml b/components/webdriver_server/Cargo.toml index 61a7f2ba361..85285808a8e 100644 --- a/components/webdriver_server/Cargo.toml +++ b/components/webdriver_server/Cargo.toml @@ -29,5 +29,7 @@ features = [ "serde_serialization" ] [dependencies] log = "0.3" +hyper = "0.6" rustc-serialize = "0.3.4" +regex = "0.1.33" uuid = "0.1" diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs index 3913f04d329..df0d3c928f1 100644 --- a/components/webdriver_server/lib.rs +++ b/components/webdriver_server/lib.rs @@ -18,37 +18,45 @@ extern crate util; extern crate rustc_serialize; extern crate uuid; extern crate ipc_channel; +extern crate regex; +extern crate hyper; +use hyper::method::Method::{self, Post}; +use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; use msg::constellation_msg::Msg as ConstellationMsg; use msg::constellation_msg::{ConstellationChan, LoadData, FrameId, PipelineId}; use msg::constellation_msg::{NavigationDirection, WebDriverCommandMsg}; use msg::webdriver_msg::{WebDriverFrameId, WebDriverScriptCommand, WebDriverJSError, WebDriverJSResult, LoadStatus}; - -use ipc_channel::ipc::{self, IpcSender, IpcReceiver}; -use url::Url; -use util::task::spawn_named; -use uuid::Uuid; -use webdriver::command::{GetParameters, JavascriptCommandParameters, LocatorParameters}; -use webdriver::command::{SwitchToFrameParameters, TimeoutsParameters}; -use webdriver::command::{WebDriverMessage, WebDriverCommand}; -use webdriver::common::{LocatorStrategy, WebElement}; -use webdriver::error::{WebDriverResult, WebDriverError, ErrorStatus}; -use webdriver::response::{WebDriverResponse, NewSessionResponse, ValueResponse}; -use webdriver::server::{self, WebDriverHandler, Session}; - +use regex::Captures; use rustc_serialize::base64::{Config, ToBase64, CharacterSet, Newline}; use rustc_serialize::json::{Json, ToJson}; use std::borrow::ToOwned; use std::collections::BTreeMap; use std::net::SocketAddr; - use std::thread::{self, sleep_ms}; +use url::Url; +use util::prefs::{get_pref, set_pref}; +use util::task::spawn_named; +use uuid::Uuid; +use webdriver::command::{GetParameters, JavascriptCommandParameters, LocatorParameters}; +use webdriver::command::{SwitchToFrameParameters, TimeoutsParameters, Parameters}; +use webdriver::command::{WebDriverMessage, WebDriverCommand, WebDriverExtensionCommand}; +use webdriver::common::{LocatorStrategy, WebElement}; +use webdriver::error::{WebDriverResult, WebDriverError, ErrorStatus}; +use webdriver::httpapi::{WebDriverExtensionRoute}; +use webdriver::response::{WebDriverResponse, NewSessionResponse, ValueResponse}; +use webdriver::server::{self, WebDriverHandler, Session}; + +fn extension_routes() -> Vec<(Method, &'static str, ServoExtensionRoute)> { + return vec![(Post, "/session/{sessionId}/servo/prefs/get", ServoExtensionRoute::GetPrefs), + (Post, "/session/{sessionId}/servo/prefs/set", ServoExtensionRoute::SetPrefs)] +} pub fn start_server(port: u16, constellation_chan: ConstellationChan) { let handler = Handler::new(constellation_chan); - spawn_named("WebdriverHttpServer".to_owned(), move || { - server::start(SocketAddr::new("0.0.0.0".parse().unwrap(), port), handler); + server::start(SocketAddr::new("0.0.0.0".parse().unwrap(), port), handler, + extension_routes()); }); } @@ -65,6 +73,119 @@ struct Handler { implicit_wait_timeout: u32 } +#[derive(Clone, Copy, PartialEq)] +enum ServoExtensionRoute { + GetPrefs, + SetPrefs, +} + +impl WebDriverExtensionRoute for ServoExtensionRoute { + type Command = ServoExtensionCommand; + + fn command(&self, + _captures: &Captures, + body_data: &Json) -> WebDriverResult> { + let command = match self { + &ServoExtensionRoute::GetPrefs => { + let parameters: GetPrefsParameters = try!(Parameters::from_json(&body_data)); + ServoExtensionCommand::GetPrefs(parameters) + } + &ServoExtensionRoute::SetPrefs => { + let parameters: SetPrefsParameters = try!(Parameters::from_json(&body_data)); + ServoExtensionCommand::SetPrefs(parameters) + } + }; + Ok(WebDriverCommand::Extension(command)) + } +} + +#[derive(Clone, PartialEq)] +enum ServoExtensionCommand { + GetPrefs(GetPrefsParameters), + SetPrefs(SetPrefsParameters) +} + +impl WebDriverExtensionCommand for ServoExtensionCommand { + fn parameters_json(&self) -> Option { + match self { + &ServoExtensionCommand::GetPrefs(ref x) => Some(x.to_json()), + &ServoExtensionCommand::SetPrefs(ref x) => Some(x.to_json()) + } + } +} + +#[derive(Clone, PartialEq)] +struct GetPrefsParameters { + prefs: Vec +} + +impl Parameters for GetPrefsParameters { + fn from_json(body: &Json) -> WebDriverResult { + let data = try!(body.as_object().ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Message body was not an object"))); + let prefs_value = try!(data.get("prefs").ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Missing prefs key"))); + let items = try!(prefs_value.as_array().ok_or( + WebDriverError::new( + ErrorStatus::InvalidArgument, + "prefs was not an array"))); + let params = try!(items.iter().map(|x| x.as_string().map(|y| y.to_owned()).ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Pref is not a string"))).collect::, _>>()); + Ok(GetPrefsParameters { + prefs: params + }) + } +} + +impl ToJson for GetPrefsParameters { + fn to_json(&self) -> Json { + let mut data = BTreeMap::new(); + data.insert("prefs".to_owned(), self.prefs.to_json()); + Json::Object(data) + } +} + +#[derive(Clone, PartialEq)] +struct SetPrefsParameters { + prefs: Vec<(String, bool)> +} + +impl Parameters for SetPrefsParameters { + fn from_json(body: &Json) -> WebDriverResult { + let data = try!(body.as_object().ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Message body was not an object"))); + let items = try!(try!(data.get("prefs").ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Missing prefs key"))).as_object().ok_or( + WebDriverError::new( + ErrorStatus::InvalidArgument, + "prefs was not an array"))); + let mut params = Vec::with_capacity(items.len()); + for (name, val) in items.iter() { + let value = try!(val.as_boolean().ok_or( + WebDriverError::new(ErrorStatus::InvalidArgument, + "Pref is not a bool"))); + let key = name.to_owned(); + params.push((key, value)); + } + Ok(SetPrefsParameters { + prefs: params + }) + } +} + +impl ToJson for SetPrefsParameters { + fn to_json(&self) -> Json { + let mut data = BTreeMap::new(); + data.insert("prefs".to_owned(), self.prefs.to_json()); + Json::Object(data) + } +} + impl WebDriverSession { pub fn new() -> WebDriverSession { WebDriverSession { @@ -505,12 +626,29 @@ impl Handler { let encoded = img_vec.to_base64(config); Ok(WebDriverResponse::Generic(ValueResponse::new(encoded.to_json()))) } + + fn handle_get_prefs(&self, + parameters: &GetPrefsParameters) -> WebDriverResult { + let prefs = parameters.prefs + .iter() + .map(|item| (item.clone(), get_pref(item).to_json())) + .collect::>(); + Ok(WebDriverResponse::Generic(ValueResponse::new(prefs.to_json()))) + } + + fn handle_set_prefs(&self, + parameters: &SetPrefsParameters) -> WebDriverResult { + for &(ref key, ref value) in parameters.prefs.iter() { + set_pref(key, *value); + } + Ok(WebDriverResponse::Void) + } } -impl WebDriverHandler for Handler { +impl WebDriverHandler for Handler { fn handle_command(&mut self, _session: &Option, - msg: &WebDriverMessage) -> WebDriverResult { + msg: &WebDriverMessage) -> WebDriverResult { // Unless we are trying to create a new session, we need to ensure that a // session has previously been created @@ -542,6 +680,12 @@ impl WebDriverHandler for Handler { WebDriverCommand::ExecuteAsyncScript(ref x) => self.handle_execute_async_script(x), WebDriverCommand::SetTimeouts(ref x) => self.handle_set_timeouts(x), WebDriverCommand::TakeScreenshot => self.handle_take_screenshot(), + WebDriverCommand::Extension(ref extension) => { + match extension { + &ServoExtensionCommand::GetPrefs(ref x) => self.handle_get_prefs(x), + &ServoExtensionCommand::SetPrefs(ref x) => self.handle_set_prefs(x), + } + } _ => Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, "Command not implemented")) } diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index deabeebe15f..3f1932ed98d 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -1795,7 +1795,7 @@ dependencies = [ [[package]] name = "webdriver" version = "0.2.3" -source = "git+https://github.com/jgraham/webdriver-rust.git#80b3fdf3f7412066268e00df25087200cbb47cca" +source = "git+https://github.com/jgraham/webdriver-rust.git#1b5007fbea3caf302cb215dbc2ad21e0402344eb" dependencies = [ "hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1808,10 +1808,12 @@ dependencies = [ name = "webdriver_server" version = "0.0.1" dependencies = [ + "hyper 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "msg 0.0.1", "png 0.1.0 (git+https://github.com/servo/rust-png)", + "regex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "url 0.2.37 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1",