Supporting topbar injection

This commit is contained in:
Tomasz Drwięga 2016-05-13 18:40:20 +02:00
parent 0a85df10e8
commit 72b1b41748
7 changed files with 85 additions and 42 deletions

21
Cargo.lock generated
View File

@ -358,8 +358,9 @@ dependencies = [
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "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)", "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)", "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-idmanager 0.1.1 (git+https://github.com/ethcore/parity-idmanager-rs.git)",
"parity-wallet 0.2.0 (git+https://github.com/ethcore/parity-wallet.git)", "parity-status 0.4.0 (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)", "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)", "url 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -820,18 +821,26 @@ name = "odds"
version = "0.2.12" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "parity-idmanager"
version = "0.1.1"
source = "git+https://github.com/ethcore/parity-idmanager-rs.git#5adf8da35e3d3605a6109c53715b867071a0cf57"
dependencies = [
"parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)",
]
[[package]] [[package]]
name = "parity-status" name = "parity-status"
version = "0.3.7" version = "0.4.0"
source = "git+https://github.com/ethcore/parity-status.git#b0ae32a7fe2f843e4e22dc38903fd2c3e7fb0763" source = "git+https://github.com/ethcore/parity-status.git#d104bcdbcc84aa8b51e6c194924893e83690b5ce"
dependencies = [ dependencies = [
"parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)",
] ]
[[package]] [[package]]
name = "parity-wallet" name = "parity-wallet"
version = "0.2.0" version = "0.3.0"
source = "git+https://github.com/ethcore/parity-wallet.git#18a602fd25f3e9bcdbc5528bf61ba627665d962c" source = "git+https://github.com/ethcore/parity-wallet.git#664fd2b85dd94ca184868bd3965e14a4ba68c03f"
dependencies = [ dependencies = [
"parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)", "parity-webapp 0.1.0 (git+https://github.com/ethcore/parity-webapp.git)",
] ]

View File

@ -17,8 +17,9 @@ ethcore-rpc = { path = "../rpc" }
ethcore-util = { path = "../util" } ethcore-util = { path = "../util" }
parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git" } parity-webapp = { git = "https://github.com/ethcore/parity-webapp.git" }
# List of apps # List of apps
parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.3.7" } parity-status = { git = "https://github.com/ethcore/parity-status.git", version = "0.4.0" }
parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.2.0", optional = true } parity-idmanager = { git = "https://github.com/ethcore/parity-idmanager-rs.git", version = "0.1.1" }
parity-wallet = { git = "https://github.com/ethcore/parity-wallet.git", version = "0.3.0", optional = true }
clippy = { version = "0.0.64", optional = true} clippy = { version = "0.0.64", optional = true}
[features] [features]

View File

@ -14,19 +14,29 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use endpoint::Endpoints; use endpoint::{Endpoints, Endpoint};
use page::PageEndpoint; use page::PageEndpoint;
use proxypac::ProxyPac; use proxypac::ProxyPac;
use parity_webapp::WebApp; use parity_webapp::WebApp;
extern crate parity_status; extern crate parity_status;
extern crate parity_idmanager;
#[cfg(feature = "parity-wallet")] #[cfg(feature = "parity-wallet")]
extern crate parity_wallet; extern crate parity_wallet;
pub const DAPPS_DOMAIN : &'static str = ".dapp";
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 { pub fn main_page() -> &'static str {
"/status/" "/status/"
} }
pub fn utils() -> Box<Endpoint> {
Box::new(PageEndpoint::with_prefix(parity_idmanager::App::default(), UTILS_PATH.to_owned()))
}
pub fn all_endpoints() -> Endpoints { pub fn all_endpoints() -> Endpoints {
let mut pages = Endpoints::new(); let mut pages = Endpoints::new();
pages.insert("proxy".to_owned(), ProxyPac::boxed()); pages.insert("proxy".to_owned(), ProxyPac::boxed());

View File

@ -61,11 +61,10 @@ mod proxypac;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use std::net::SocketAddr; use std::net::SocketAddr;
use std::collections::HashMap;
use jsonrpc_core::{IoHandler, IoDelegate}; use jsonrpc_core::{IoHandler, IoDelegate};
use router::auth::{Authorization, NoAuth, HttpBasicAuth}; use router::auth::{Authorization, NoAuth, HttpBasicAuth};
static DAPPS_DOMAIN : &'static str = ".dapp";
/// Webapps HTTP+RPC server build. /// Webapps HTTP+RPC server build.
pub struct ServerBuilder { pub struct ServerBuilder {
handler: Arc<IoHandler>, handler: Arc<IoHandler>,
@ -106,17 +105,21 @@ pub struct Server {
impl Server { impl Server {
fn start_http<A: Authorization + 'static>(addr: &SocketAddr, authorization: A, handler: Arc<IoHandler>) -> Result<Server, ServerError> { fn start_http<A: Authorization + 'static>(addr: &SocketAddr, authorization: A, handler: Arc<IoHandler>) -> Result<Server, ServerError> {
let panic_handler = Arc::new(Mutex::new(None)); let panic_handler = Arc::new(Mutex::new(None));
let endpoints = Arc::new(apps::all_endpoints());
let authorization = Arc::new(authorization); let authorization = Arc::new(authorization);
let rpc_endpoint = Arc::new(rpc::rpc(handler, panic_handler.clone())); let endpoints = Arc::new(apps::all_endpoints());
let api = Arc::new(api::RestApi::new(endpoints.clone())); 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)) try!(hyper::Server::http(addr))
.handle(move |_| router::Router::new( .handle(move |_| router::Router::new(
apps::main_page(), apps::main_page(),
endpoints.clone(), endpoints.clone(),
rpc_endpoint.clone(), special.clone(),
api.clone(),
authorization.clone(), authorization.clone(),
)) ))
.map(|l| Server { .map(|l| Server {

View File

@ -26,13 +26,23 @@ use endpoint::{Endpoint, EndpointPath};
use parity_webapp::WebApp; use parity_webapp::WebApp;
pub struct PageEndpoint<T : WebApp + 'static> { pub struct PageEndpoint<T : WebApp + 'static> {
/// Content of the files
pub app: Arc<T>, pub app: Arc<T>,
/// Prefix to strip from the path (when `None` deducted from `app_id`)
pub prefix: Option<String>,
} }
impl<T: WebApp + 'static> PageEndpoint<T> { impl<T: WebApp + 'static> PageEndpoint<T> {
pub fn new(app: T) -> Self { pub fn new(app: T) -> Self {
PageEndpoint { 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<T: WebApp> Endpoint for PageEndpoint<T> {
fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>> { fn to_handler(&self, path: EndpointPath) -> Box<server::Handler<HttpStream>> {
Box::new(PageHandler { Box::new(PageHandler {
app: self.app.clone(), app: self.app.clone(),
prefix: self.prefix.clone(),
path: path, path: path,
file: None, file: None,
write_pos: 0, write_pos: 0,
@ -50,6 +61,7 @@ impl<T: WebApp> Endpoint for PageEndpoint<T> {
struct PageHandler<T: WebApp + 'static> { struct PageHandler<T: WebApp + 'static> {
app: Arc<T>, app: Arc<T>,
prefix: Option<String>,
path: EndpointPath, path: EndpointPath,
file: Option<String>, file: Option<String>,
write_pos: usize, write_pos: usize,
@ -57,7 +69,8 @@ struct PageHandler<T: WebApp + 'static> {
impl<T: WebApp + 'static> PageHandler<T> { impl<T: WebApp + 'static> PageHandler<T> {
fn extract_path(&self, path: &str) -> String { 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() + "/"; let prefix_with_slash = prefix.clone() + "/";
// Index file support // Index file support

View File

@ -17,7 +17,7 @@
//! Serving ProxyPac file //! Serving ProxyPac file
use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath}; use endpoint::{Endpoint, Handler, ContentHandler, EndpointPath};
use DAPPS_DOMAIN; use apps::DAPPS_DOMAIN;
pub struct ProxyPac; pub struct ProxyPac;

View File

@ -21,30 +21,32 @@ mod url;
mod redirect; mod redirect;
pub mod auth; pub mod auth;
use DAPPS_DOMAIN;
use std::sync::Arc; use std::sync::Arc;
use std::collections::HashMap;
use url::Host; use url::Host;
use hyper; use hyper;
use hyper::{server, uri, header}; use hyper::{server, uri, header};
use hyper::{Next, Encoder, Decoder}; use hyper::{Next, Encoder, Decoder};
use hyper::net::HttpStream; use hyper::net::HttpStream;
use apps;
use endpoint::{Endpoint, Endpoints, EndpointPath}; use endpoint::{Endpoint, Endpoints, EndpointPath};
use self::url::Url; use self::url::Url;
use self::auth::{Authorization, Authorized}; use self::auth::{Authorization, Authorized};
use self::redirect::Redirection; use self::redirect::Redirection;
#[derive(Debug, PartialEq)] /// Special endpoints are accessible on every domain (every dapp)
enum SpecialEndpoint { #[derive(Debug, PartialEq, Hash, Eq)]
pub enum SpecialEndpoint {
Rpc, Rpc,
Api, Api,
Utils,
None None
} }
pub struct Router<A: Authorization + 'static> { pub struct Router<A: Authorization + 'static> {
main_page: &'static str, main_page: &'static str,
endpoints: Arc<Endpoints>, endpoints: Arc<Endpoints>,
rpc: Arc<Box<Endpoint>>, special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
api: Arc<Box<Endpoint>>,
authorization: Arc<A>, authorization: Arc<A>,
handler: Box<server::Handler<HttpStream>>, handler: Box<server::Handler<HttpStream>>,
} }
@ -63,13 +65,9 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
let endpoint = extract_endpoint(&url); let endpoint = extract_endpoint(&url);
match endpoint { match endpoint {
// First check RPC requests // First check special endpoints
(ref path, SpecialEndpoint::Rpc) if *req.method() != hyper::method::Method::Get => { (ref path, ref endpoint) if self.special.contains_key(endpoint) => {
self.rpc.to_handler(path.clone().unwrap_or_default()) self.special.get(endpoint).unwrap().to_handler(path.clone().unwrap_or_default())
},
// Check API requests
(ref path, SpecialEndpoint::Api) => {
self.api.to_handler(path.clone().unwrap_or_default())
}, },
// Then delegate to dapp // Then delegate to dapp
(Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => { (Some(ref path), _) if self.endpoints.contains_key(&path.app_id) => {
@ -81,7 +79,7 @@ impl<A: Authorization + 'static> server::Handler<HttpStream> for Router<A> {
}, },
// RPC by default // RPC by default
_ => { _ => {
self.rpc.to_handler(EndpointPath::default()) self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default())
} }
} }
} }
@ -111,16 +109,14 @@ impl<A: Authorization> Router<A> {
pub fn new( pub fn new(
main_page: &'static str, main_page: &'static str,
endpoints: Arc<Endpoints>, endpoints: Arc<Endpoints>,
rpc: Arc<Box<Endpoint>>, special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
api: Arc<Box<Endpoint>>,
authorization: Arc<A>) -> Self { authorization: Arc<A>) -> Self {
let handler = rpc.to_handler(EndpointPath::default()); let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default());
Router { Router {
main_page: main_page, main_page: main_page,
endpoints: endpoints, endpoints: endpoints,
rpc: rpc, special: special,
api: api,
authorization: authorization, authorization: authorization,
handler: handler, handler: handler,
} }
@ -158,17 +154,19 @@ fn extract_endpoint(url: &Option<Url>) -> (Option<EndpointPath>, SpecialEndpoint
if url.path.len() <= 1 { if url.path.len() <= 1 {
return SpecialEndpoint::None; return SpecialEndpoint::None;
} }
match url.path[0].as_ref() { match url.path[0].as_ref() {
"rpc" => SpecialEndpoint::Rpc, apps::RPC_PATH => SpecialEndpoint::Rpc,
"api" => SpecialEndpoint::Api, apps::API_PATH => SpecialEndpoint::Api,
apps::UTILS_PATH => SpecialEndpoint::Utils,
_ => SpecialEndpoint::None, _ => SpecialEndpoint::None,
} }
} }
match *url { match *url {
Some(ref url) => match url.host { Some(ref url) => match url.host {
Host::Domain(ref domain) if domain.ends_with(DAPPS_DOMAIN) => { Host::Domain(ref domain) if domain.ends_with(apps::DAPPS_DOMAIN) => {
let len = domain.len() - DAPPS_DOMAIN.len(); let len = domain.len() - apps::DAPPS_DOMAIN.len();
let id = domain[0..len].to_owned(); let id = domain[0..len].to_owned();
(Some(EndpointPath { (Some(EndpointPath {
@ -215,6 +213,15 @@ fn should_extract_endpoint() {
}), SpecialEndpoint::Rpc) }), 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 // By Subdomain
assert_eq!( assert_eq!(
extract_endpoint(&Url::parse("http://my.status.dapp/test.html").ok()), extract_endpoint(&Url::parse("http://my.status.dapp/test.html").ok()),
@ -237,7 +244,7 @@ fn should_extract_endpoint() {
// API by subdomain // API by subdomain
assert_eq!( assert_eq!(
extract_endpoint(&Url::parse("http://my.status.dapp/rpc/").ok()), extract_endpoint(&Url::parse("http://my.status.dapp/api/").ok()),
(Some(EndpointPath { (Some(EndpointPath {
app_id: "my.status".to_owned(), app_id: "my.status".to_owned(),
host: "my.status.dapp".to_owned(), host: "my.status.dapp".to_owned(),