diff --git a/Cargo.lock b/Cargo.lock index 7c1bdbfaf..a1fd76643 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,14 +109,6 @@ dependencies = [ "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "conduit-mime-types" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cookie" version = "0.1.21" @@ -195,15 +187,6 @@ dependencies = [ "regex 0.1.65 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "error" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "eth-secp256k1" version = "0.5.4" @@ -318,13 +301,13 @@ dependencies = [ "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-status 0.1.6 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.1 (git+https://github.com/tomusdrw/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", + "url 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -484,23 +467,6 @@ dependencies = [ "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "iron" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itertools" version = "0.4.12" @@ -654,11 +620,6 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "modifier" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "net2" version = "0.2.23" @@ -744,14 +705,6 @@ name = "parity-webapp" version = "0.1.0" source = "git+https://github.com/tomusdrw/parity-webapp.git#a24297256bae0ae0712c6478cd1ad681828b3800" -[[package]] -name = "plugin" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "primal" version = "0.2.3" @@ -1057,11 +1010,6 @@ name = "traitobject" version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "traitobject" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "transient-hashmap" version = "0.1.0" @@ -1075,14 +1023,6 @@ name = "typeable" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "typemap" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicase" version = "1.4.0" @@ -1109,14 +1049,6 @@ name = "unicode-xid" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unsafe-any" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "traitobject 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "url" version = "0.2.38" diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index eb3e9c042..157d9e506 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -12,7 +12,7 @@ log = "0.3" jsonrpc-core = "2.0" jsonrpc-http-server = { git = "https://github.com/tomusdrw/jsonrpc-http-server.git", branch="old-hyper" } hyper = { version = "0.8", default-features = false } -iron = { version = "0.3" } +url = "0.5" ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index ed9a13967..8452f6453 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -20,8 +20,8 @@ #[macro_use] extern crate log; +extern crate url; extern crate hyper; -extern crate iron; extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_rpc as rpc; diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 070f94a34..f91e837a3 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -18,6 +18,7 @@ //! Processes request handling authorization and dispatching it to proper application. mod api; +mod url; pub mod auth; use std::sync::Arc; @@ -25,7 +26,7 @@ use hyper; use hyper::{server, uri, header}; use page::Page; use apps::Pages; -use iron::request::Url; +use self::url::Url; use jsonrpc_http_server::ServerHandler; use self::auth::{Authorization, Authorized}; diff --git a/webapp/src/router/url.rs b/webapp/src/router/url.rs new file mode 100644 index 000000000..108de740d --- /dev/null +++ b/webapp/src/router/url.rs @@ -0,0 +1,177 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! HTTP/HTTPS URL type. Based on URL type from Iron library. + +use url::Host; +use url::{whatwg_scheme_type_mapper}; +use url::{self, SchemeData, SchemeType}; + +/// HTTP/HTTPS URL type for Iron. +#[derive(PartialEq, Eq, Clone, Debug)] +pub struct Url { + /// The lower-cased scheme of the URL, typically "http" or "https". + pub scheme: String, + + /// The host field of the URL, probably a domain. + pub host: Host, + + /// The connection port. + pub port: u16, + + /// The URL path, the resource to be accessed. + /// + /// A *non-empty* vector encoding the parts of the URL path. + /// Empty entries of `""` correspond to trailing slashes. + pub path: Vec, + + /// The URL username field, from the userinfo section of the URL. + /// + /// `None` if the `@` character was not part of the input OR + /// if a blank username was provided. + /// Otherwise, a non-empty string. + pub username: Option, + + /// The URL password field, from the userinfo section of the URL. + /// + /// `None` if the `@` character was not part of the input OR + /// if a blank password was provided. + /// Otherwise, a non-empty string. + pub password: Option, + + /// The URL query string. + /// + /// `None` if the `?` character was not part of the input. + /// Otherwise, a possibly empty, percent encoded string. + pub query: Option, + + /// The URL fragment. + /// + /// `None` if the `#` character was not part of the input. + /// Otherwise, a possibly empty, percent encoded string. + pub fragment: Option +} + +impl Url { + /// Create a URL from a string. + /// + /// The input must be a valid URL with a special scheme for this to succeed. + /// + /// HTTP and HTTPS are special schemes. + /// + /// See: http://url.spec.whatwg.org/#special-scheme + pub fn parse(input: &str) -> Result { + // Parse the string using rust-url, then convert. + match url::Url::parse(input) { + Ok(raw_url) => Url::from_generic_url(raw_url), + Err(e) => Err(format!("{}", e)) + } + } + + /// Create a `Url` from a `rust-url` `Url`. + pub fn from_generic_url(raw_url: url::Url) -> Result { + // Create an Iron URL by extracting the special scheme data. + match raw_url.scheme_data { + SchemeData::Relative(data) => { + // Extract the port as a 16-bit unsigned integer. + let port: u16 = match data.port { + // If explicitly defined, unwrap it. + Some(port) => port, + + // Otherwise, use the scheme's default port. + None => { + match whatwg_scheme_type_mapper(&raw_url.scheme) { + SchemeType::Relative(port) => port, + _ => return Err(format!("Invalid special scheme: `{}`", + raw_url.scheme)) + } + } + }; + + // Map empty usernames to None. + let username = match &*data.username { + "" => None, + _ => Some(data.username) + }; + + // Map empty passwords to None. + let password = match data.password { + None => None, + Some(ref x) if x.is_empty() => None, + Some(password) => Some(password) + }; + + Ok(Url { + scheme: raw_url.scheme, + host: data.host, + port: port, + path: data.path, + username: username, + password: password, + query: raw_url.query, + fragment: raw_url.fragment + }) + }, + _ => Err(format!("Not a special scheme: `{}`", raw_url.scheme)) + } + } +} + +#[cfg(test)] +mod test { + use super::Url; + + #[test] + fn test_default_port() { + assert_eq!(Url::parse("http://example.com/wow").unwrap().port, 80u16); + assert_eq!(Url::parse("https://example.com/wow").unwrap().port, 443u16); + } + + #[test] + fn test_explicit_port() { + assert_eq!(Url::parse("http://localhost:3097").unwrap().port, 3097u16); + } + + #[test] + fn test_empty_username() { + assert!(Url::parse("http://@example.com").unwrap().username.is_none()); + assert!(Url::parse("http://:password@example.com").unwrap().username.is_none()); + } + + #[test] + fn test_not_empty_username() { + let user = Url::parse("http://john:pass@example.com").unwrap().username; + assert_eq!(user.unwrap(), "john"); + + let user = Url::parse("http://john:@example.com").unwrap().username; + assert_eq!(user.unwrap(), "john"); + } + + #[test] + fn test_empty_password() { + assert!(Url::parse("http://michael@example.com").unwrap().password.is_none()); + assert!(Url::parse("http://:@example.com").unwrap().password.is_none()); + } + + #[test] + fn test_not_empty_password() { + let pass = Url::parse("http://michael:pass@example.com").unwrap().password; + assert_eq!(pass.unwrap(), "pass"); + + let pass = Url::parse("http://:pass@example.com").unwrap().password; + assert_eq!(pass.unwrap(), "pass"); + } +}