diff --git a/Cargo.lock b/Cargo.lock index 9b793c219..c9b869226 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,7 +276,7 @@ dependencies = [ "ethcore-util 1.3.0", "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 6.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)", "mime_guess 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-dapps 0.6.0 (git+https://github.com/ethcore/parity-ui.git)", @@ -357,7 +357,7 @@ dependencies = [ "ethsync 1.3.0", "json-ipc-server 0.2.4 (git+https://github.com/ethcore/json-ipc-server.git)", "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 6.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)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -629,8 +629,8 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "6.1.0" -source = "git+https://github.com/ethcore/jsonrpc-http-server.git#517a0d7b8c7fd099995ce4cc93f52789e83f2cdc" +version = "5.1.0" +source = "git+https://github.com/ethcore/jsonrpc-http-server.git#f16b956c61e60b3a530ad4bac82112a8974cf505" dependencies = [ "hyper 0.9.4 (git+https://github.com/ethcore/hyper)", "jsonrpc-core 2.0.7 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/dapps/src/handlers/content.rs b/dapps/src/handlers/content.rs index b9d8d55d6..a589e5492 100644 --- a/dapps/src/handlers/content.rs +++ b/dapps/src/handlers/content.rs @@ -38,15 +38,6 @@ impl ContentHandler { } } - pub fn forbidden(content: String, mimetype: String) -> Self { - ContentHandler { - code: StatusCode::Forbidden, - content: content, - mimetype: mimetype, - write_pos: 0 - } - } - pub fn not_found(content: String, mimetype: String) -> Self { ContentHandler { code: StatusCode::NotFound, diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index d9fa06591..133b4ebaa 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -129,7 +129,6 @@ impl Server { special.insert(router::SpecialEndpoint::Utils, apps::utils()); special }); - let bind_address = format!("{}", addr); try!(hyper::Server::http(addr)) .handle(move |_| router::Router::new( @@ -137,7 +136,6 @@ impl Server { endpoints.clone(), special.clone(), authorization.clone(), - bind_address.clone(), )) .map(|(l, srv)| { diff --git a/dapps/src/router/host_validation.rs b/dapps/src/router/host_validation.rs deleted file mode 100644 index 4f04d28ac..000000000 --- a/dapps/src/router/host_validation.rs +++ /dev/null @@ -1,42 +0,0 @@ -// 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 . - - -use DAPPS_DOMAIN; -use hyper::server; -use hyper::net::HttpStream; - -use jsonrpc_http_server::{is_host_header_valid}; -use handlers::ContentHandler; - - -pub fn is_valid(request: &server::Request, bind_address: &str, endpoints: Vec) -> bool { - let mut endpoints = endpoints.into_iter() - .map(|endpoint| format!("{}{}", endpoint, DAPPS_DOMAIN)) - .collect::>(); - endpoints.push(bind_address.into()); - is_host_header_valid(request, &endpoints) -} - -pub fn host_invalid_response() -> Box + Send> { - Box::new(ContentHandler::forbidden( - r#" -

Request with disallowed Host header has been blocked.

-

Check the URL in your browser address bar.

- "#.into(), - "text/html".into() - )) -} diff --git a/dapps/src/router/mod.rs b/dapps/src/router/mod.rs index bdd5fd291..8fbb37cf3 100644 --- a/dapps/src/router/mod.rs +++ b/dapps/src/router/mod.rs @@ -18,7 +18,6 @@ //! Processes request handling authorization and dispatching it to proper application. pub mod auth; -mod host_validation; use DAPPS_DOMAIN; use std::sync::Arc; @@ -45,46 +44,40 @@ pub struct Router { endpoints: Arc, special: Arc>>, authorization: Arc, - bind_address: String, handler: Box + Send>, } impl server::Handler for Router { fn on_request(&mut self, req: server::Request) -> Next { - // Validate Host header - if !host_validation::is_valid(&req, &self.bind_address, self.endpoints.keys().cloned().collect()) { - self.handler = host_validation::host_invalid_response(); - return self.handler.on_request(req); - } - // Check authorization let auth = self.authorization.is_authorized(&req); - if let Authorized::No(handler) = auth { - self.handler = handler; - return self.handler.on_request(req); - } // Choose proper handler depending on path / domain - let url = extract_url(&req); - let endpoint = extract_endpoint(&url); + self.handler = match auth { + Authorized::No(handler) => handler, + Authorized::Yes => { + let url = extract_url(&req); + let endpoint = extract_endpoint(&url); - self.handler = match endpoint { - // 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) => { - self.endpoints.get(&path.app_id).unwrap().to_handler(path.clone()) - }, - // Redirection to main page - _ if *req.method() == hyper::method::Method::Get => { - Redirection::new(self.main_page) - }, - // RPC by default - _ => { - self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()) + match endpoint { + // 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) => { + self.endpoints.get(&path.app_id).unwrap().to_handler(path.clone()) + }, + // Redirection to main page + _ if *req.method() == hyper::method::Method::Get => { + Redirection::new(self.main_page) + }, + // RPC by default + _ => { + self.special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()) + } + } } }; @@ -113,9 +106,7 @@ impl Router { main_page: &'static str, endpoints: Arc, special: Arc>>, - authorization: Arc, - bind_address: String, - ) -> Self { + authorization: Arc) -> Self { let handler = special.get(&SpecialEndpoint::Rpc).unwrap().to_handler(EndpointPath::default()); Router { @@ -123,7 +114,6 @@ impl Router { endpoints: endpoints, special: special, authorization: authorization, - bind_address: bind_address, handler: handler, } } diff --git a/dapps/src/rpc.rs b/dapps/src/rpc.rs index 04470bcc1..e282c0440 100644 --- a/dapps/src/rpc.rs +++ b/dapps/src/rpc.rs @@ -23,22 +23,19 @@ pub fn rpc(handler: Arc, panic_handler: Arc Box::new(RpcEndpoint { handler: handler, panic_handler: panic_handler, - cors_domain: Some(vec![AccessControlAllowOrigin::Null]), - // NOTE [ToDr] We don't need to do any hosts validation here. It's already done in router. - allowed_hosts: None, + cors_domain: vec![AccessControlAllowOrigin::Null], }) } struct RpcEndpoint { handler: Arc, panic_handler: Arc () + Send>>>>, - cors_domain: Option>, - allowed_hosts: Option>, + cors_domain: Vec, } impl Endpoint for RpcEndpoint { fn to_handler(&self, _path: EndpointPath) -> Box { let panic_handler = PanicHandler { handler: self.panic_handler.clone() }; - Box::new(ServerHandler::new(self.handler.clone(), self.cors_domain.clone(), self.allowed_hosts.clone(), panic_handler)) + Box::new(ServerHandler::new(self.handler.clone(), self.cors_domain.clone(), panic_handler)) } } diff --git a/parity/cli.rs b/parity/cli.rs index 9c59c3c25..1c90afdf0 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -36,7 +36,7 @@ Operating Options: --mode MODE Set the operating mode. MODE can be one of: active - Parity continuously syncs the chain. passive - Parity syncs initially, then sleeps and - wakes regularly to resync. + wakes regularly to resync. dark - Parity syncs only when an external interface is active. [default: active]. --mode-timeout SECS Specify the number of seconds before inactivity @@ -107,11 +107,6 @@ API and Console Options: name. Possible name are web3, eth, net, personal, ethcore, ethcore_set, traces. [default: web3,eth,net,ethcore,personal,traces]. - --jsonrpc-hosts HOSTS List of allowed Host header values. This option will - validate the Host header sent by the browser, it - is additional security against some attack - vectors. Special options: "all", "none", - [default: none]. --no-ipc Disable JSON-RPC over IPC service. --ipc-path PATH Specify custom path for JSON-RPC over IPC service @@ -123,8 +118,8 @@ API and Console Options: --dapps-port PORT Specify the port portion of the Dapps server [default: 8080]. --dapps-interface IP Specify the hostname portion of the Dapps - server, IP should be an interface's hostname / IP - or local (localhost) [default: local]. + server, IP should be an interface's IP address, or + all (all interfaces) or local [default: local]. --dapps-user USERNAME Specify username for Dapps server. It will be used in HTTP Basic Authentication Scheme. If --dapps-pass is not specified you will be @@ -146,11 +141,11 @@ Sealing/Mining Options: own - reseal only on a new local transaction; ext - reseal only on a new external transaction; all - reseal on all new transactions [default: own]. - --reseal-min-period MS Specify the minimum time between reseals from + --reseal-min-period MS Specify the minimum time between reseals from incoming transactions. MS is time measured in milliseconds [default: 2000]. --work-queue-size ITEMS Specify the number of historical work packages - which are kept cached lest a solution is found for + which are kept cached lest a solution is found for them later. High values take more memory but result in fewer unusable solutions [default: 20]. --tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas @@ -316,7 +311,6 @@ pub struct Args { pub flag_jsonrpc_interface: String, pub flag_jsonrpc_port: u16, pub flag_jsonrpc_cors: Option, - pub flag_jsonrpc_hosts: String, pub flag_jsonrpc_apis: String, pub flag_no_ipc: bool, pub flag_ipc_path: String, diff --git a/parity/configuration.rs b/parity/configuration.rs index a9cc6f0e3..266f400a7 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -424,22 +424,9 @@ impl Configuration { self.args.flag_rpcapi.clone().unwrap_or(self.args.flag_jsonrpc_apis.clone()) } - pub fn rpc_cors(&self) -> Option> { + pub fn rpc_cors(&self) -> Vec { let cors = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone()); - cors.map(|c| c.split(',').map(|s| s.to_owned()).collect()) - } - - pub fn rpc_hosts(&self) -> Option> { - let hosts = self.args.flag_jsonrpc_hosts.split(',').collect::>(); - // look for special values - for h in &hosts { - match *h { - "none" => return Some(Vec::new()), - "all" => return None, - _ => {}, - } - } - Some(hosts.into_iter().map(|h| h.into()).collect()) + cors.map_or_else(Vec::new, |c| c.split(',').map(|s| s.to_owned()).collect()) } fn geth_ipc_path(&self) -> String { @@ -554,7 +541,8 @@ impl Configuration { pub fn dapps_interface(&self) -> String { match self.args.flag_dapps_interface.as_str() { - "local" => "localhost", + "all" => "0.0.0.0", + "local" => "127.0.0.1", x => x, }.into() } @@ -609,7 +597,7 @@ mod tests { assert_eq!(net.rpc_enabled, true); assert_eq!(net.rpc_interface, "all".to_owned()); assert_eq!(net.rpc_port, 8000); - assert_eq!(conf.rpc_cors(), Some(vec!["*".to_owned()])); + assert_eq!(conf.rpc_cors(), vec!["*".to_owned()]); assert_eq!(conf.rpc_apis(), "web3,eth".to_owned()); } @@ -631,22 +619,5 @@ mod tests { assert(conf1); assert(conf2); } - - #[test] - fn should_parse_rpc_hosts() { - // given - - // when - let conf0 = parse(&["parity"]); - let conf1 = parse(&["parity", "--jsonrpc-hosts", "none"]); - let conf2 = parse(&["parity", "--jsonrpc-hosts", "all"]); - let conf3 = parse(&["parity", "--jsonrpc-hosts", "ethcore.io,something.io"]); - - // then - assert_eq!(conf0.rpc_hosts(), Some(Vec::new())); - assert_eq!(conf1.rpc_hosts(), Some(Vec::new())); - assert_eq!(conf2.rpc_hosts(), None); - assert_eq!(conf3.rpc_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()])); - } } diff --git a/parity/main.rs b/parity/main.rs index fe5107d66..a8fd63d2a 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -280,7 +280,6 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig, port: network_settings.rpc_port, apis: conf.rpc_apis(), cors: conf.rpc_cors(), - hosts: conf.rpc_hosts(), }, &dependencies); // setup ipc rpc diff --git a/parity/rpc.rs b/parity/rpc.rs index 2b0599962..7317aa2e6 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -32,8 +32,7 @@ pub struct HttpConfiguration { pub interface: String, pub port: u16, pub apis: String, - pub cors: Option>, - pub hosts: Option>, + pub cors: Vec, } pub struct IpcConfiguration { @@ -67,7 +66,7 @@ pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Option, deps: &Dependencies) -> Server { @@ -79,17 +78,21 @@ fn setup_rpc_server(apis: Vec<&str>, deps: &Dependencies) -> Server { pub fn setup_http_rpc_server( dependencies: &Dependencies, url: &SocketAddr, - cors_domains: Option>, - allowed_hosts: Option>, + cors_domains: Vec, apis: Vec<&str>, ) -> RpcServer { let server = setup_rpc_server(apis, dependencies); + let start_result = server.start_http(url, cors_domains); let ph = dependencies.panic_handler.clone(); - let start_result = server.start_http(url, cors_domains, allowed_hosts, ph); match start_result { Err(RpcServerError::IoError(err)) => die_with_io_error("RPC", err), Err(e) => die!("RPC: {:?}", e), - Ok(server) => server, + Ok(server) => { + server.set_panic_handler(move || { + ph.notify_all("Panic in RPC thread.".to_owned()); + }); + server + }, } } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 5899d0027..73a769b13 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -41,10 +41,9 @@ extern crate ethcore_devtools as devtools; use std::sync::Arc; use std::net::SocketAddr; -use util::panics::PanicHandler; use self::jsonrpc_core::{IoHandler, IoDelegate}; -pub use jsonrpc_http_server::{ServerBuilder, Server, RpcServerError}; +pub use jsonrpc_http_server::{Server, RpcServerError}; pub mod v1; pub use v1::{SigningQueue, ConfirmationsQueue}; @@ -75,31 +74,15 @@ impl RpcServer { } /// Start http server asynchronously and returns result with `Server` handle on success or an error. - pub fn start_http( - &self, - addr: &SocketAddr, - cors_domains: Option>, - allowed_hosts: Option>, - panic_handler: Arc, - ) -> Result { - - let cors_domains = cors_domains.map(|domains| { - domains.into_iter() - .map(|v| match v.as_str() { - "*" => jsonrpc_http_server::AccessControlAllowOrigin::Any, - "null" => jsonrpc_http_server::AccessControlAllowOrigin::Null, - v => jsonrpc_http_server::AccessControlAllowOrigin::Value(v.into()), - }) - .collect() - }); - - ServerBuilder::new(self.handler.clone()) - .cors(cors_domains.into()) - .allowed_hosts(allowed_hosts.into()) - .panic_handler(move || { - panic_handler.notify_all("Panic in RPC thread.".to_owned()); + pub fn start_http(&self, addr: &SocketAddr, cors_domains: Vec) -> Result { + let cors_domains = cors_domains.into_iter() + .map(|v| match v.as_str() { + "*" => jsonrpc_http_server::AccessControlAllowOrigin::Any, + "null" => jsonrpc_http_server::AccessControlAllowOrigin::Null, + v => jsonrpc_http_server::AccessControlAllowOrigin::Value(v.into()), }) - .start_http(addr) + .collect(); + Server::start(addr, self.handler.clone(), cors_domains) } /// Start ipc server asynchronously and returns result with `Server` handle on success or an error.