diff --git a/Cargo.lock b/Cargo.lock index c6d78d700..2b3d9ccb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -361,8 +361,9 @@ dependencies = [ "jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 5.1.0 (git+https://github.com/ethcore/jsonrpc-http-server.git)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-status 0.3.7 (git+https://github.com/ethcore/parity-status.git)", - "parity-wallet 0.2.0 (git+https://github.com/ethcore/parity-wallet.git)", + "parity-idmanager 0.1.3 (git+https://github.com/ethcore/parity-idmanager-rs.git)", + "parity-status 0.4.1 (git+https://github.com/ethcore/parity-status.git)", + "parity-wallet 0.3.0 (git+https://github.com/ethcore/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", "url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -833,18 +834,26 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-idmanager" +version = "0.1.3" +source = "git+https://github.com/ethcore/parity-idmanager-rs.git#efb69592b87854f41d8882de75982c8f1e748666" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", +] + [[package]] name = "parity-status" -version = "0.3.7" -source = "git+https://github.com/ethcore/parity-status.git#b0ae32a7fe2f843e4e22dc38903fd2c3e7fb0763" +version = "0.4.1" +source = "git+https://github.com/ethcore/parity-status.git#f121ebd1f49986545d9fc262ba210cdf07039e6d" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", ] [[package]] name = "parity-wallet" -version = "0.2.0" -source = "git+https://github.com/ethcore/parity-wallet.git#18a602fd25f3e9bcdbc5528bf61ba627665d962c" +version = "0.3.0" +source = "git+https://github.com/ethcore/parity-wallet.git#664fd2b85dd94ca184868bd3965e14a4ba68c03f" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", ] diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 51f54f02d..093136ea4 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,8 +17,9 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git" } # List of apps -parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.3.7" } -parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.2.0", optional = true } +parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.4.1" } +parity-idmanager = { git = "https://github.com/ethcore/parity-idmanager-rs.git", version = "0.1.3" } +parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.3.0", optional = true } clippy = { version = "0.0.64", optional = true} [features] diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs index c07e9919c..1c9b7e5a8 100644 --- a/webapp/src/apps.rs +++ b/webapp/src/apps.rs @@ -14,19 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use endpoint::Endpoints; +use endpoint::{Endpoints, Endpoint}; use page::PageEndpoint; use proxypac::ProxyPac; use parity_webapp::WebApp; extern crate parity_status; +extern crate parity_idmanager; #[cfg(feature = "parity-wallet")] extern crate parity_wallet; +pub const DAPPS_DOMAIN : &'static str = ".parity"; +pub const RPC_PATH : &'static str = "rpc"; +pub const API_PATH : &'static str = "api"; +pub const UTILS_PATH : &'static str = "parity-utils"; + pub fn main_page() -> &'static str { "/status/" } +pub fn utils() -> Box { + Box::new(PageEndpoint::with_prefix(parity_idmanager::App::default(), UTILS_PATH.to_owned())) +} + pub fn all_endpoints() -> Endpoints { let mut pages = Endpoints::new(); pages.insert("proxy".to_owned(), ProxyPac::boxed()); diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 2c74dbdc3..819e9d362 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -61,6 +61,7 @@ mod proxypac; use std::sync::{Arc, Mutex}; use std::net::SocketAddr; +use std::collections::HashMap; use jsonrpc_core::{IoHandler, IoDelegate}; use router::auth::{Authorization, NoAuth, HttpBasicAuth}; @@ -106,17 +107,21 @@ pub struct Server { impl Server { fn start_http(addr: &SocketAddr, authorization: A, handler: Arc) -> Result { let panic_handler = Arc::new(Mutex::new(None)); - let endpoints = Arc::new(apps::all_endpoints()); let authorization = Arc::new(authorization); - let rpc_endpoint = Arc::new(rpc::rpc(handler, panic_handler.clone())); - let api = Arc::new(api::RestApi::new(endpoints.clone())); + let endpoints = Arc::new(apps::all_endpoints()); + let special = Arc::new({ + let mut special = HashMap::new(); + special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, panic_handler.clone())); + special.insert(router::SpecialEndpoint::Api, api::RestApi::new(endpoints.clone())); + special.insert(router::SpecialEndpoint::Utils, apps::utils()); + special + }); try!(hyper::Server::http(addr)) .handle(move |_| router::Router::new( apps::main_page(), endpoints.clone(), - rpc_endpoint.clone(), - api.clone(), + special.clone(), authorization.clone(), )) .map(|l| Server { diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs index abcd1930b..1d987c393 100644 --- a/webapp/src/page/mod.rs +++ b/webapp/src/page/mod.rs @@ -26,13 +26,23 @@ use endpoint::{Endpoint, EndpointPath}; use parity_webapp::WebApp; pub struct PageEndpoint { + /// Content of the files pub app: Arc, + /// Prefix to strip from the path (when `None` deducted from `app_id`) + pub prefix: Option, } impl PageEndpoint { pub fn new(app: T) -> Self { PageEndpoint { - app: Arc::new(app) + app: Arc::new(app), + prefix: None, + } + } + pub fn with_prefix(app: T, prefix: String) -> Self { + PageEndpoint { + app: Arc::new(app), + prefix: Some(prefix), } } } @@ -41,6 +51,7 @@ impl Endpoint for PageEndpoint { fn to_handler(&self, path: EndpointPath) -> Box> { Box::new(PageHandler { app: self.app.clone(), + prefix: self.prefix.clone(), path: path, file: None, write_pos: 0, @@ -50,6 +61,7 @@ impl Endpoint for PageEndpoint { struct PageHandler { app: Arc, + prefix: Option, path: EndpointPath, file: Option, write_pos: usize, @@ -57,7 +69,8 @@ struct PageHandler { impl PageHandler { fn extract_path(&self, path: &str) -> String { - let prefix = "/".to_owned() + &self.path.app_id; + let app_id = &self.path.app_id; + let prefix = "/".to_owned() + self.prefix.as_ref().unwrap_or(app_id); let prefix_with_slash = prefix.clone() + "/"; // Index file support diff --git a/webapp/src/proxypac.rs b/webapp/src/proxypac.rs index da2cab916..9d91d58f0 100644 --- a/webapp/src/proxypac.rs +++ b/webapp/src/proxypac.rs @@ -17,7 +17,7 @@ //! Serving ProxyPac file use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath}; -use DAPPS_DOMAIN; +use apps::DAPPS_DOMAIN; pub struct ProxyPac; diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 11205068a..e9d255f95 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -23,28 +23,31 @@ pub mod auth; use DAPPS_DOMAIN; use std::sync::Arc; +use std::collections::HashMap; use url::Host; use hyper; use hyper::{server, uri, header}; use hyper::{Next, Encoder, Decoder}; use hyper::net::HttpStream; +use apps; use endpoint::{Endpoint, Endpoints, EndpointPath}; use self::url::Url; use self::auth::{Authorization, Authorized}; use self::redirect::Redirection; -#[derive(Debug, PartialEq)] -enum SpecialEndpoint { +/// Special endpoints are accessible on every domain (every dapp) +#[derive(Debug, PartialEq, Hash, Eq)] +pub enum SpecialEndpoint { Rpc, Api, - None + Utils, + None, } pub struct Router { main_page: &'static str, endpoints: Arc, - rpc: Arc>, - api: Arc>, + special: Arc>>, authorization: Arc, handler: Box>, } @@ -63,13 +66,9 @@ impl server::Handler for Router { let endpoint = extract_endpoint(&url); match endpoint { - // First check RPC requests - (ref path, SpecialEndpoint::Rpc) if *req.method() != hyper::method::Method::Get => { - self.rpc.to_handler(path.clone().unwrap_or_default()) - }, - // Check API requests - (ref path, SpecialEndpoint::Api) => { - self.api.to_handler(path.clone().unwrap_or_default()) + // First check special endpoints + (ref path, ref endpoint) if self.special.contains_key(endpoint) => { + self.special.get(endpoint).unwrap().to_handler(path.clone().unwrap_or_default()) }, // Then delegate to dapp (Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => { @@ -81,7 +80,7 @@ impl server::Handler for Router { }, // RPC by default _ => { - self.rpc.to_handler(EndpointPath::default()) + self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()) } } } @@ -111,16 +110,14 @@ impl Router { pub fn new( main_page: &'static str, endpoints: Arc, - rpc: Arc>, - api: Arc>, + special: Arc>>, authorization: Arc) -> Self { - let handler = rpc.to_handler(EndpointPath::default()); + let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()); Router { main_page: main_page, endpoints: endpoints, - rpc: rpc, - api: api, + special: special, authorization: authorization, handler: handler, } @@ -158,9 +155,11 @@ fn extract_endpoint(url: &Option) -> (Option, SpecialEndpoint if url.path.len() <= 1 { return SpecialEndpoint::None; } + match url.path[0].as_ref() { - "rpc" => SpecialEndpoint::Rpc, - "api" => SpecialEndpoint::Api, + apps::RPC_PATH => SpecialEndpoint::Rpc, + apps::API_PATH => SpecialEndpoint::Api, + apps::UTILS_PATH => SpecialEndpoint::Utils, _ => SpecialEndpoint::None, } } @@ -215,6 +214,15 @@ fn should_extract_endpoint() { }), SpecialEndpoint::Rpc) ); + assert_eq!( + extract_endpoint(&Url::parse("http://my.status.dapp/parity-utils/inject.js").ok()), + (Some(EndpointPath { + app_id: "my.status".to_owned(), + host: "my.status.dapp".to_owned(), + port: 80, + }), SpecialEndpoint::Utils) + ); + // By Subdomain assert_eq!( extract_endpoint(&Url::parse("http://my.status.dapp/test.html").ok()), @@ -237,7 +245,7 @@ fn should_extract_endpoint() { // API by subdomain assert_eq!( - extract_endpoint(&Url::parse("http://my.status.dapp/rpc/").ok()), + extract_endpoint(&Url::parse("http://my.status.dapp/api/").ok()), (Some(EndpointPath { app_id: "my.status".to_owned(), host: "my.status.dapp".to_owned(),