webdriver: Move some things around
authorJames Graham <james@hoppipolla.co.uk>
Fri, 16 Jan 2015 18:36:48 +0000
changeset 427999 770a2902d676b4e7d47f67c48e9a6c7949ac1d4f
parent 427998 850210710e1ee3ffde812e3ec0f13227605bdaaf
child 428000 0c676b6c173ab293311a4e2de385780671538f0b
push id7761
push userjlund@mozilla.com
push dateFri, 15 Sep 2017 00:19:52 +0000
treeherdermozilla-beta@c38455951db4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone57.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
webdriver: Move some things around Source-Repo: https://github.com/mozilla/webdriver-rust Source-Revision: b945401deb6e45fce5ddbb1ab8c30b5b2686cc2c
testing/webdriver/src/command.rs
testing/webdriver/src/common.rs
testing/webdriver/src/httpapi.rs
testing/webdriver/src/httpserver.rs
testing/webdriver/src/lib.rs
testing/webdriver/src/messagebuilder.rs
testing/webdriver/src/response.rs
testing/webdriver/src/server.rs
--- a/testing/webdriver/src/command.rs
+++ b/testing/webdriver/src/command.rs
@@ -1,16 +1,15 @@
 use std::collections::BTreeMap;
 use rustc_serialize::json::{ToJson, Json};
 use regex::Captures;
 
-use common::{Nullable, WebElement, FrameId, LocatorStrategy};
+use common::{Date, Nullable, WebElement, FrameId, LocatorStrategy};
 use error::{WebDriverResult, WebDriverError, ErrorStatus};
-use response::Date; //TODO: Put all these types in a specific file
-use messagebuilder::MatchType;
+use httpapi::Route;
 
 
 #[derive(PartialEq)]
 pub enum WebDriverCommand {
     NewSession,
     DeleteSession,
     Get(GetParameters),
     GetCurrentUrl,
@@ -64,191 +63,191 @@ pub struct WebDriverMessage {
 impl WebDriverMessage {
     pub fn new(session_id: Option<String>, command: WebDriverCommand) -> WebDriverMessage {
         WebDriverMessage {
             session_id: session_id,
             command: command
         }
     }
 
-    pub fn from_http(match_type: MatchType, params: &Captures, body: &str) -> WebDriverResult<WebDriverMessage> {
+    pub fn from_http(match_type: Route, params: &Captures, body: &str) -> WebDriverResult<WebDriverMessage> {
         let session_id = WebDriverMessage::get_session_id(params);
         let body_data = if body != "" {
             debug!("Got request body {}", body);
             match Json::from_str(body) {
                 Ok(x) => x,
                 Err(_) => return Err(WebDriverError::new(ErrorStatus::UnknownError,
                                                          format!("Failed to decode request body as json: {}", body).as_slice()))
             }
         } else {
             Json::Null
         };
         let command = match match_type {
-            MatchType::NewSession => WebDriverCommand::NewSession,
-            MatchType::DeleteSession => WebDriverCommand::DeleteSession,
-            MatchType::Get => {
+            Route::NewSession => WebDriverCommand::NewSession,
+            Route::DeleteSession => WebDriverCommand::DeleteSession,
+            Route::Get => {
                 let parameters: GetParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::Get(parameters)
             },
-            MatchType::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
-            MatchType::GoBack => WebDriverCommand::GoBack,
-            MatchType::GoForward => WebDriverCommand::GoForward,
-            MatchType::Refresh => WebDriverCommand::Refresh,
-            MatchType::GetTitle => WebDriverCommand::GetTitle,
-            MatchType::GetWindowHandle => WebDriverCommand::GetWindowHandle,
-            MatchType::GetWindowHandles => WebDriverCommand::GetWindowHandles,
-            MatchType::Close => WebDriverCommand::Close,
-            MatchType::SetTimeouts => {
+            Route::GetCurrentUrl => WebDriverCommand::GetCurrentUrl,
+            Route::GoBack => WebDriverCommand::GoBack,
+            Route::GoForward => WebDriverCommand::GoForward,
+            Route::Refresh => WebDriverCommand::Refresh,
+            Route::GetTitle => WebDriverCommand::GetTitle,
+            Route::GetWindowHandle => WebDriverCommand::GetWindowHandle,
+            Route::GetWindowHandles => WebDriverCommand::GetWindowHandles,
+            Route::Close => WebDriverCommand::Close,
+            Route::SetTimeouts => {
                 let parameters: TimeoutsParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::SetTimeouts(parameters)
             },
-            MatchType::SetWindowSize => {
+            Route::SetWindowSize => {
                 let parameters: WindowSizeParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::SetWindowSize(parameters)
             },
-            MatchType::GetWindowSize => WebDriverCommand::GetWindowSize,
-            MatchType::MaximizeWindow => WebDriverCommand::MaximizeWindow,
-            MatchType::SwitchToWindow => {
+            Route::GetWindowSize => WebDriverCommand::GetWindowSize,
+            Route::MaximizeWindow => WebDriverCommand::MaximizeWindow,
+            Route::SwitchToWindow => {
                 let parameters: SwitchToWindowParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::SwitchToWindow(parameters)
             }
-            MatchType::SwitchToFrame => {
+            Route::SwitchToFrame => {
                 let parameters: SwitchToFrameParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::SwitchToFrame(parameters)
             },
-            MatchType::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
-            MatchType::FindElement => {
+            Route::SwitchToParentFrame => WebDriverCommand::SwitchToParentFrame,
+            Route::FindElement => {
                 let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::FindElement(parameters)
             },
-            MatchType::FindElements => {
+            Route::FindElements => {
                 let parameters: LocatorParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::FindElements(parameters)
             },
-            MatchType::IsDisplayed => {
+            Route::IsDisplayed => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::IsDisplayed(element)
             },
-            MatchType::IsSelected => {
+            Route::IsSelected => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::IsSelected(element)
             },
-            MatchType::GetElementAttribute => {
+            Route::GetElementAttribute => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 let attr = try_opt!(params.name("name"),
                                     ErrorStatus::InvalidArgument,
                                     "Missing name parameter").to_string();
                 WebDriverCommand::GetElementAttribute(element, attr)
             },
-            MatchType::GetCSSValue => {
+            Route::GetCSSValue => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 let property = try_opt!(params.name("propertyName"),
                                         ErrorStatus::InvalidArgument,
                                         "Missing propertyName parameter").to_string();
                 WebDriverCommand::GetCSSValue(element, property)
             },
-            MatchType::GetElementText => {
+            Route::GetElementText => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::GetElementText(element)
             },
-            MatchType::GetElementTagName => {
+            Route::GetElementTagName => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::GetElementTagName(element)
             },
-            MatchType::GetElementRect => {
+            Route::GetElementRect => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::GetElementRect(element)
             },
-            MatchType::IsEnabled => {
+            Route::IsEnabled => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::IsEnabled(element)
             },
-            MatchType::ElementClick => {
+            Route::ElementClick => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::ElementClick(element)
             },
-            MatchType::ElementTap => {
+            Route::ElementTap => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::ElementTap(element)
             },
-            MatchType::ElementClear => {
+            Route::ElementClear => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 WebDriverCommand::ElementClear(element)
             },
-            MatchType::ElementSendKeys => {
+            Route::ElementSendKeys => {
                 let element_id = try_opt!(params.name("elementId"),
                                           ErrorStatus::InvalidArgument,
                                           "Missing elementId parameter");
                 let element = WebElement::new(element_id.to_string());
                 let parameters: SendKeysParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::ElementSendKeys(element, parameters)
             },
-            MatchType::ExecuteScript => {
+            Route::ExecuteScript => {
                 let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::ExecuteScript(parameters)
             },
-            MatchType::ExecuteAsyncScript => {
+            Route::ExecuteAsyncScript => {
                 let parameters: JavascriptCommandParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::ExecuteAsyncScript(parameters)
             },
-            MatchType::GetCookie => {
+            Route::GetCookie => {
                 let parameters: GetCookieParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::GetCookie(parameters)
             },
-            MatchType::AddCookie => {
+            Route::AddCookie => {
                 let parameters: AddCookieParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::AddCookie(parameters)
             },
-            MatchType::DismissAlert => {
+            Route::DismissAlert => {
                 WebDriverCommand::DismissAlert
             },
-            MatchType::AcceptAlert => {
+            Route::AcceptAlert => {
                 WebDriverCommand::AcceptAlert
             },
-            MatchType::GetAlertText => {
+            Route::GetAlertText => {
                 WebDriverCommand::GetAlertText
             },
-            MatchType::SendAlertText => {
+            Route::SendAlertText => {
                 let parameters: SendAlertTextParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::SendAlertText(parameters)
             }
-            MatchType::TakeScreenshot => {
+            Route::TakeScreenshot => {
                 let parameters: TakeScreenshotParameters = try!(Parameters::from_json(&body_data));
                 WebDriverCommand::TakeScreenshot(parameters)
             }
         };
         Ok(WebDriverMessage::new(session_id, command))
     }
 
     fn get_session_id(params: &Captures) -> Option<String> {
--- a/testing/webdriver/src/common.rs
+++ b/testing/webdriver/src/common.rs
@@ -3,16 +3,31 @@ use rustc_serialize::json::{Json, ToJson
 use rustc_serialize::{Encodable, Encoder};
 use std::collections::BTreeMap;
 use std::error::{Error, FromError};
 
 use error::{WebDriverResult, WebDriverError, ErrorStatus};
 
 static ELEMENT_KEY: &'static str = "element-6066-11e4-a52e-4f735466cecf";
 
+#[derive(RustcEncodable, PartialEq, Show)]
+pub struct Date(u64);
+
+impl Date {
+    pub fn new(timestamp: u64) -> Date {
+        Date(timestamp)
+    }
+}
+
+impl ToJson for Date {
+    fn to_json(&self) -> Json {
+        let &Date(x) = self;
+        x.to_json()
+    }
+}
 
 #[derive(PartialEq, Clone, Show)]
 pub enum Nullable<T: ToJson> {
     Value(T),
     Null
 }
 
 impl<T: ToJson> Nullable<T> {
new file mode 100644
--- /dev/null
+++ b/testing/webdriver/src/httpapi.rs
@@ -0,0 +1,184 @@
+use regex::{Regex, Captures};
+
+use hyper::method::Method;
+use hyper::method::Method::{Get, Post, Delete};
+
+use command::{WebDriverMessage};
+use error::{WebDriverResult, WebDriverError, ErrorStatus};
+
+static routes: [(Method, &'static str, Route); 41] = [
+    (Post, "/session", Route::NewSession),
+    (Delete, "/session/{sessionId}", Route::DeleteSession),
+    (Post, "/session/{sessionId}/url", Route::Get),
+    (Get, "/session/{sessionId}/url", Route::GetCurrentUrl),
+    (Post, "/session/{sessionId}/back", Route::GoBack),
+    (Post, "/session/{sessionId}/forward", Route::GoForward),
+    (Post, "/session/{sessionId}/refresh", Route::Refresh),
+    (Get, "/session/{sessionId}/title", Route::GetTitle),
+    (Get, "/session/{sessionId}/window_handle", Route::GetWindowHandle),
+    (Get, "/session/{sessionId}/window_handles", Route::GetWindowHandles),
+    (Delete, "/session/{sessionId}/window_handle", Route::Close),
+    (Post, "/session/{sessionId}/window/size", Route::SetWindowSize),
+    (Get, "/session/{sessionId}/window/size", Route::GetWindowSize),
+    (Post, "/session/{sessionId}/window/maximize", Route::MaximizeWindow),
+    (Post, "/session/{sessionId}/window", Route::SwitchToWindow),
+    (Post, "/session/{sessionId}/frame", Route::SwitchToFrame),
+    (Post, "/session/{sessionId}/frame/parent", Route::SwitchToParentFrame),
+    (Post, "/session/{sessionId}/element", Route::FindElement),
+    (Post, "/session/{sessionId}/elements", Route::FindElements),
+    (Get, "/session/{sessionId}/element/{elementId}/displayed", Route::IsDisplayed),
+    (Get, "/session/{sessionId}/element/{elementId}/selected", Route::IsSelected),
+    (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", Route::GetElementAttribute),
+    (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", Route::GetCSSValue),
+    (Get, "/session/{sessionId}/element/{elementId}/text", Route::GetElementText),
+    (Get, "/session/{sessionId}/element/{elementId}/name", Route::GetElementTagName),
+    (Get, "/session/{sessionId}/element/{elementId}/rect", Route::GetElementRect),
+    (Get, "/session/{sessionId}/element/{elementId}/enabled", Route::IsEnabled),
+    (Post, "/session/{sessionId}/execute", Route::ExecuteScript),
+    (Post, "/session/{sessionId}/execute_async", Route::ExecuteAsyncScript),
+    (Get, "/session/{sessionId}/cookie", Route::GetCookie),
+    (Post, "/session/{sessionId}/cookie", Route::AddCookie),
+    (Post, "/session/{sessionId}/timeouts", Route::SetTimeouts),
+    //(Post, "/session/{sessionId}/actions", Route::Actions),
+    (Post, "/session/{sessionId}/element/{elementId}/click", Route::ElementClick),
+    (Post, "/session/{sessionId}/element/{elementId}/tap", Route::ElementTap),
+    (Post, "/session/{sessionId}/element/{elementId}/clear", Route::ElementClear),
+    (Post, "/session/{sessionId}/element/{elementId}/sendKeys", Route::ElementSendKeys),
+    (Post, "/session/{sessionId}/dismiss_alert", Route::DismissAlert),
+    (Post, "/session/{sessionId}/accept_alert", Route::AcceptAlert),
+    (Get, "/session/{sessionId}/alert_text", Route::GetAlertText),
+    (Post, "/session/{sessionId}/alert_text", Route::SendAlertText),
+    (Get, "/session/{sessionId}/screenshot", Route::TakeScreenshot)
+];
+
+#[derive(Clone, Copy)]
+pub enum Route {
+    NewSession,
+    DeleteSession,
+    Get,
+    GetCurrentUrl,
+    GoBack,
+    GoForward,
+    Refresh,
+    GetTitle,
+    GetWindowHandle,
+    GetWindowHandles,
+    Close,
+    SetWindowSize,
+    GetWindowSize,
+    MaximizeWindow,
+    SwitchToWindow,
+    SwitchToFrame,
+    SwitchToParentFrame,
+    FindElement,
+    FindElements,
+    IsDisplayed,
+    IsSelected,
+    GetElementAttribute,
+    GetCSSValue,
+    GetElementText,
+    GetElementTagName,
+    GetElementRect,
+    IsEnabled,
+    ExecuteScript,
+    ExecuteAsyncScript,
+    GetCookie,
+    AddCookie,
+    SetTimeouts,
+    //Actions XXX - once I understand the spec, perhaps
+    ElementClick,
+    ElementTap,
+    ElementClear,
+    ElementSendKeys,
+    DismissAlert,
+    AcceptAlert,
+    GetAlertText,
+    SendAlertText,
+    TakeScreenshot
+}
+
+#[derive(Clone)]
+struct RequestMatcher {
+    method: Method,
+    path_regexp: Regex,
+    match_type: Route
+}
+
+impl RequestMatcher {
+    pub fn new(method: Method, path: &str, match_type: Route) -> RequestMatcher {
+        let path_regexp = RequestMatcher::compile_path(path);
+        RequestMatcher {
+            method: method,
+            path_regexp: path_regexp,
+            match_type: match_type
+        }
+    }
+
+    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
+        let captures = self.path_regexp.captures(path);
+        (method == self.method, captures)
+    }
+
+    fn compile_path(path: &str) -> Regex {
+        let mut rv = String::new();
+        rv.push_str("^");
+        let mut components = path.split('/');
+        for component in components {
+            if component.starts_with("{") {
+                if !component.ends_with("}") {
+                    panic!("Invalid url pattern")
+                }
+                rv.push_str(format!("(?P<{}>[^/]+)/", &component[1..component.len()-1]).as_slice());
+            } else {
+                rv.push_str(format!("{}/", component).as_slice());
+            }
+        }
+        //Remove the trailing /
+        rv.pop();
+        rv.push_str("$");
+        //This will fail at runtime if the regexp is invalid
+        Regex::new(rv.as_slice()).unwrap()
+    }
+}
+
+pub struct WebDriverHttpApi {
+    routes: Vec<(Method, RequestMatcher)>
+}
+
+impl WebDriverHttpApi {
+    pub fn new() -> WebDriverHttpApi {
+        let mut rv = WebDriverHttpApi {
+            routes: vec![]
+        };
+        debug!("Creating routes");
+        for &(ref method, ref url, ref match_type) in routes.iter() {
+            rv.add(method.clone(), *url, *match_type);
+        };
+        rv
+    }
+
+    fn add(&mut self, method: Method, path: &str, match_type: Route) {
+        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
+        self.routes.push((method, http_matcher));
+    }
+
+    pub fn decode_request(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage> {
+        let mut error = ErrorStatus::UnknownPath;
+        for &(ref match_method, ref matcher) in self.routes.iter() {
+            if method == *match_method {
+                let (method_match, captures) = matcher.get_match(method.clone(), path);
+                if captures.is_some() {
+                    if method_match {
+                        return WebDriverMessage::from_http(matcher.match_type,
+                                                           &captures.unwrap(),
+                                                           body)
+                    } else {
+                        error = ErrorStatus::UnknownMethod;
+                    }
+                }
+            }
+        }
+        Err(WebDriverError::new(error,
+                                format!("{} {} did not match a known command", method, path).as_slice()))
+    }
+}
--- a/testing/webdriver/src/lib.rs
+++ b/testing/webdriver/src/lib.rs
@@ -5,19 +5,19 @@
 #[macro_use] extern crate log;
 extern crate "rustc-serialize" as rustc_serialize;
 extern crate core;
 extern crate hyper;
 extern crate regex;
 
 
 #[macro_use] pub mod macros;
-mod messagebuilder;
+mod common;
+mod httpapi;
 pub mod command;
-pub mod common;
 pub mod error;
-pub mod httpserver;
+pub mod server;
 pub mod response;
 
 
 #[test]
 fn it_works() {
 }
deleted file mode 100644
--- a/testing/webdriver/src/messagebuilder.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-use regex::{Regex, Captures};
-
-use hyper::method::Method;
-use hyper::method::Method::{Get, Post, Delete};
-
-use command::{WebDriverMessage};
-use error::{WebDriverResult, WebDriverError, ErrorStatus};
-
-#[derive(Clone, Copy)]
-pub enum MatchType {
-    NewSession,
-    DeleteSession,
-    Get,
-    GetCurrentUrl,
-    GoBack,
-    GoForward,
-    Refresh,
-    GetTitle,
-    GetWindowHandle,
-    GetWindowHandles,
-    Close,
-    SetWindowSize,
-    GetWindowSize,
-    MaximizeWindow,
-    SwitchToWindow,
-    SwitchToFrame,
-    SwitchToParentFrame,
-    FindElement,
-    FindElements,
-    IsDisplayed,
-    IsSelected,
-    GetElementAttribute,
-    GetCSSValue,
-    GetElementText,
-    GetElementTagName,
-    GetElementRect,
-    IsEnabled,
-    ExecuteScript,
-    ExecuteAsyncScript,
-    GetCookie,
-    AddCookie,
-    SetTimeouts,
-    //Actions XXX - once I understand the spec, perhaps
-    ElementClick,
-    ElementTap,
-    ElementClear,
-    ElementSendKeys,
-    DismissAlert,
-    AcceptAlert,
-    GetAlertText,
-    SendAlertText,
-    TakeScreenshot
-}
-
-#[derive(Clone)]
-pub struct RequestMatcher {
-    method: Method,
-    path_regexp: Regex,
-    match_type: MatchType
-}
-
-impl RequestMatcher {
-    pub fn new(method: Method, path: &str, match_type: MatchType) -> RequestMatcher {
-        let path_regexp = RequestMatcher::compile_path(path);
-        RequestMatcher {
-            method: method,
-            path_regexp: path_regexp,
-            match_type: match_type
-        }
-    }
-
-    pub fn get_match<'t>(&'t self, method: Method, path: &'t str) -> (bool, Option<Captures>) {
-        let captures = self.path_regexp.captures(path);
-        (method == self.method, captures)
-    }
-
-    fn compile_path(path: &str) -> Regex {
-        let mut rv = String::new();
-        rv.push_str("^");
-        let mut components = path.split('/');
-        for component in components {
-            if component.starts_with("{") {
-                if !component.ends_with("}") {
-                    panic!("Invalid url pattern")
-                }
-                rv.push_str(format!("(?P<{}>[^/]+)/", &component[1..component.len()-1]).as_slice());
-            } else {
-                rv.push_str(format!("{}/", component).as_slice());
-            }
-        }
-        //Remove the trailing /
-        rv.pop();
-        rv.push_str("$");
-        //This will fail at runtime if the regexp is invalid
-        Regex::new(rv.as_slice()).unwrap()
-    }
-}
-
-pub struct MessageBuilder {
-    http_matchers: Vec<(Method, RequestMatcher)>
-}
-
-impl MessageBuilder {
-    pub fn new() -> MessageBuilder {
-        MessageBuilder {
-            http_matchers: vec![]
-        }
-    }
-
-    pub fn from_http(&self, method: Method, path: &str, body: &str) -> WebDriverResult<WebDriverMessage> {
-        let mut error = ErrorStatus::UnknownPath;
-        for &(ref match_method, ref matcher) in self.http_matchers.iter() {
-            if method == *match_method {
-                let (method_match, captures) = matcher.get_match(method.clone(), path);
-                if captures.is_some() {
-                    if method_match {
-                        return WebDriverMessage::from_http(matcher.match_type,
-                                                           &captures.unwrap(),
-                                                           body)
-                    } else {
-                        error = ErrorStatus::UnknownMethod;
-                    }
-                }
-            }
-        }
-        Err(WebDriverError::new(error,
-                                format!("{} {} did not match a known command", method, path).as_slice()))
-    }
-
-    pub fn add(&mut self, method: Method, path: &str, match_type: MatchType) {
-        let http_matcher = RequestMatcher::new(method.clone(), path, match_type);
-        self.http_matchers.push((method, http_matcher));
-    }
-}
-
-pub fn get_builder() -> MessageBuilder {
-    let mut builder = MessageBuilder::new();
-    let matchers = vec![(Post, "/session", MatchType::NewSession),
-                        (Delete, "/session/{sessionId}", MatchType::DeleteSession),
-                        (Post, "/session/{sessionId}/url", MatchType::Get),
-                        (Get, "/session/{sessionId}/url", MatchType::GetCurrentUrl),
-                        (Post, "/session/{sessionId}/back", MatchType::GoBack),
-                        (Post, "/session/{sessionId}/forward", MatchType::GoForward),
-                        (Post, "/session/{sessionId}/refresh", MatchType::Refresh),
-                        (Get, "/session/{sessionId}/title", MatchType::GetTitle),
-                        (Get, "/session/{sessionId}/window_handle", MatchType::GetWindowHandle),
-                        (Get, "/session/{sessionId}/window_handles", MatchType::GetWindowHandles),
-                        (Delete, "/session/{sessionId}/window_handle", MatchType::Close),
-                        (Post, "/session/{sessionId}/window/size", MatchType::SetWindowSize),
-                        (Get, "/session/{sessionId}/window/size", MatchType::GetWindowSize),
-                        (Post, "/session/{sessionId}/window/maximize", MatchType::MaximizeWindow),
-                        (Post, "/session/{sessionId}/window", MatchType::SwitchToWindow),
-                        (Post, "/session/{sessionId}/frame", MatchType::SwitchToFrame),
-                        (Post, "/session/{sessionId}/frame/parent", MatchType::SwitchToParentFrame),
-                        (Post, "/session/{sessionId}/element", MatchType::FindElement),
-                        (Post, "/session/{sessionId}/elements", MatchType::FindElements),
-                        (Get, "/session/{sessionId}/element/{elementId}/displayed", MatchType::IsDisplayed),
-                        (Get, "/session/{sessionId}/element/{elementId}/selected", MatchType::IsSelected),
-                        (Get, "/session/{sessionId}/element/{elementId}/attribute/{name}", MatchType::GetElementAttribute),
-                        (Get, "/session/{sessionId}/element/{elementId}/css/{propertyName}", MatchType::GetCSSValue),
-                        (Get, "/session/{sessionId}/element/{elementId}/text", MatchType::GetElementText),
-                        (Get, "/session/{sessionId}/element/{elementId}/name", MatchType::GetElementTagName),
-                        (Get, "/session/{sessionId}/element/{elementId}/rect", MatchType::GetElementRect),
-                        (Get, "/session/{sessionId}/element/{elementId}/enabled", MatchType::IsEnabled),
-                        (Post, "/session/{sessionId}/execute", MatchType::ExecuteScript),
-                        (Post, "/session/{sessionId}/execute_async", MatchType::ExecuteAsyncScript),
-                        (Get, "/session/{sessionId}/cookie", MatchType::GetCookie),
-                        (Post, "/session/{sessionId}/cookie", MatchType::AddCookie),
-                        (Post, "/session/{sessionId}/timeouts", MatchType::SetTimeouts),
-                        //(Post, "/session/{sessionId}/actions", MatchType::Actions),
-                        (Post, "/session/{sessionId}/element/{elementId}/click", MatchType::ElementClick),
-                        (Post, "/session/{sessionId}/element/{elementId}/tap", MatchType::ElementTap),
-                        (Post, "/session/{sessionId}/element/{elementId}/clear", MatchType::ElementClear),
-                        (Post, "/session/{sessionId}/element/{elementId}/sendKeys", MatchType::ElementSendKeys),
-                        (Post, "/session/{sessionId}/dismiss_alert", MatchType::DismissAlert),
-                        (Post, "/session/{sessionId}/accept_alert", MatchType::AcceptAlert),
-                        (Get, "/session/{sessionId}/alert_text", MatchType::GetAlertText),
-                        (Post, "/session/{sessionId}/alert_text", MatchType::SendAlertText),
-                        (Get, "/session/{sessionId}/screenshot", MatchType::TakeScreenshot)
-                        ];
-    debug!("Creating routes");
-    for &(ref method, ref url, ref match_type) in matchers.iter() {
-        builder.add(method.clone(), *url, *match_type);
-    }
-    builder
-}
--- a/testing/webdriver/src/response.rs
+++ b/testing/webdriver/src/response.rs
@@ -1,12 +1,12 @@
 use rustc_serialize::json;
 use rustc_serialize::json::ToJson;
 
-use common::Nullable;
+use common::{Nullable, Date};
 
 #[derive(Show)]
 pub enum WebDriverResponse {
     NewSession(NewSessionResponse),
     DeleteSession,
     WindowSize(WindowSizeResponse),
     ElementRect(ElementRectResponse),
     Cookie(CookieResponse),
@@ -85,32 +85,16 @@ impl ElementRectResponse {
             x: x,
             y: y,
             width: width,
             height: height
         }
     }
 }
 
-#[derive(RustcEncodable, PartialEq, Show)]
-pub struct Date(u64);
-
-impl Date {
-    pub fn new(timestamp: u64) -> Date {
-        Date(timestamp)
-    }
-}
-
-impl ToJson for Date {
-    fn to_json(&self) -> json::Json {
-        let &Date(x) = self;
-        x.to_json()
-    }
-}
-
 //TODO: some of these fields are probably supposed to be optional
 #[derive(RustcEncodable, PartialEq, Show)]
 pub struct Cookie {
     name: String,
     value: String,
     path: Nullable<String>,
     domain: Nullable<String>,
     expiry: Nullable<Date>,
rename from testing/webdriver/src/httpserver.rs
rename to testing/webdriver/src/server.rs
--- a/testing/webdriver/src/httpserver.rs
+++ b/testing/webdriver/src/server.rs
@@ -6,17 +6,17 @@ use std::thread::Thread;
 
 use hyper::header::common::ContentLength;
 use hyper::method::Method;
 use hyper::server::{Server, Handler, Request, Response};
 use hyper::uri::RequestUri::AbsolutePath;
 
 use command::{WebDriverMessage, WebDriverCommand};
 use error::{WebDriverResult, WebDriverError, ErrorStatus};
-use messagebuilder::{get_builder, MessageBuilder};
+use httpapi::WebDriverHttpApi;
 use response::WebDriverResponse;
 
 enum DispatchMessage {
     HandleWebDriver(WebDriverMessage, Sender<WebDriverResult<WebDriverResponse>>),
     Quit
 }
 
 #[derive(PartialEq, Clone)]
@@ -131,24 +131,24 @@ impl<T: WebDriverHandler> Dispatcher<T> 
                 }
             }
         }
     }
 }
 
 struct HttpHandler {
     chan: Mutex<Sender<DispatchMessage>>,
-    builder: Mutex<MessageBuilder>
+    api: Mutex<WebDriverHttpApi>
 }
 
 impl HttpHandler {
-    fn new(builder: MessageBuilder, chan: Sender<DispatchMessage>) -> HttpHandler {
+    fn new(api: WebDriverHttpApi, chan: Sender<DispatchMessage>) -> HttpHandler {
         HttpHandler {
             chan: Mutex::new(chan),
-            builder: Mutex::new(builder)
+            api: Mutex::new(api)
         }
     }
 }
 
 impl Handler for HttpHandler {
     fn handle(&self, req: Request, res: Response) {
         let mut req = req;
         let mut res = res;
@@ -158,19 +158,19 @@ impl Handler for HttpHandler {
             _ => "".to_string()
         };
         debug!("Got request {} {:?}", req.method, req.uri);
         match req.uri {
             AbsolutePath(path) => {
                 let msg_result = {
                     // The fact that this locks for basically the whole request doesn't
                     // matter as long as we are only handling one request at a time.
-                    match self.builder.lock() {
-                        Ok(ref builder) => {
-                            builder.from_http(req.method, path.as_slice(), body.as_slice())
+                    match self.api.lock() {
+                        Ok(ref api) => {
+                            api.decode_request(req.method, path.as_slice(), body.as_slice())
                         },
                         Err(_) => return
                     }
                 };
                 let (status, resp_body) = match msg_result {
                     Ok(message) => {
                         let (send_res, recv_res) = channel();
                         match self.chan.lock() {
@@ -227,12 +227,12 @@ pub fn start<T: WebDriverHandler>(ip_add
     let server = Server::http(ip_address, port);
 
     let (msg_send, msg_recv) = channel();
 
     Thread::spawn(move || {
         let mut dispatcher = Dispatcher::new(handler);
         dispatcher.run(msg_recv)
     });
-    let builder = get_builder();
-    let http_handler = HttpHandler::new(builder, msg_send.clone());
+    let api = WebDriverHttpApi::new();
+    let http_handler = HttpHandler::new(api, msg_send.clone());
     server.listen(http_handler).unwrap();
 }