2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-04-21 13:12:43 +02:00
// 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://www.gnu.org/licenses/>.
2017-04-03 10:27:37 +02:00
use std ::{ io , fmt } ;
2016-04-21 13:12:43 +02:00
use std ::sync ::Arc ;
2017-01-11 20:02:27 +01:00
2017-04-03 10:27:37 +02:00
use dapps ;
2017-01-11 20:02:27 +01:00
use dir ::default_data_path ;
2017-02-04 22:18:19 +01:00
use ethcore_rpc ::informant ::{ RpcStats , Middleware } ;
2017-04-03 10:27:37 +02:00
use ethcore_rpc ::{ self as rpc , HttpServerError , Metadata , Origin , AccessControlAllowOrigin , Host } ;
2017-01-11 20:02:27 +01:00
use helpers ::parity_ipc_path ;
use jsonrpc_core ::MetaIoHandler ;
2017-03-13 15:49:52 +01:00
use parity_reactor ::TokioRemote ;
2017-04-03 10:27:37 +02:00
use rpc_apis ::{ self , ApiSet } ;
2016-04-21 13:12:43 +02:00
2017-04-03 10:27:37 +02:00
pub use ethcore_rpc ::{ IpcServer , HttpServer , RequestMiddleware } ;
2016-04-21 13:12:43 +02:00
2017-04-03 10:27:37 +02:00
#[ derive(Debug, Clone, PartialEq) ]
2016-05-04 15:37:09 +02:00
pub struct HttpConfiguration {
2016-04-21 13:57:27 +02:00
pub enabled : bool ,
pub interface : String ,
pub port : u16 ,
2016-07-25 16:09:47 +02:00
pub apis : ApiSet ,
2016-07-20 12:34:17 +02:00
pub cors : Option < Vec < String > > ,
pub hosts : Option < Vec < String > > ,
2017-04-03 10:27:37 +02:00
pub threads : Option < usize > ,
2016-04-21 13:57:27 +02:00
}
2016-07-25 16:09:47 +02:00
impl Default for HttpConfiguration {
fn default ( ) -> Self {
HttpConfiguration {
enabled : true ,
interface : " 127.0.0.1 " . into ( ) ,
port : 8545 ,
apis : ApiSet ::UnsafeContext ,
cors : None ,
hosts : Some ( Vec ::new ( ) ) ,
2017-04-03 10:27:37 +02:00
threads : None ,
2016-07-25 16:09:47 +02:00
}
}
}
#[ derive(Debug, PartialEq) ]
2016-05-04 15:37:09 +02:00
pub struct IpcConfiguration {
pub enabled : bool ,
pub socket_addr : String ,
2016-07-25 16:09:47 +02:00
pub apis : ApiSet ,
}
impl Default for IpcConfiguration {
fn default ( ) -> Self {
2016-12-13 23:38:29 +01:00
let data_dir = default_data_path ( ) ;
2016-07-25 16:09:47 +02:00
IpcConfiguration {
enabled : true ,
2016-12-15 21:56:45 +01:00
socket_addr : parity_ipc_path ( & data_dir , " $BASE/jsonrpc.ipc " ) ,
2016-11-04 09:58:39 +01:00
apis : ApiSet ::IpcContext ,
2016-07-25 16:09:47 +02:00
}
}
2016-05-04 15:37:09 +02:00
}
2016-06-13 18:55:24 +02:00
impl fmt ::Display for IpcConfiguration {
fn fmt ( & self , f : & mut fmt ::Formatter ) -> fmt ::Result {
if self . enabled {
2016-07-25 16:09:47 +02:00
write! ( f , " endpoint address [{}], api list [{:?}] " , self . socket_addr , self . apis )
} else {
2016-06-13 18:55:24 +02:00
write! ( f , " disabled " )
}
}
}
2017-03-22 20:14:40 +01:00
pub struct Dependencies < D : rpc_apis ::Dependencies > {
pub apis : Arc < D > ,
2017-03-13 15:49:52 +01:00
pub remote : TokioRemote ,
2017-02-04 22:18:19 +01:00
pub stats : Arc < RpcStats > ,
2016-04-21 13:57:27 +02:00
}
2017-02-14 22:45:43 +01:00
pub struct RpcExtractor ;
2017-04-03 10:27:37 +02:00
impl rpc ::HttpMetaExtractor for RpcExtractor {
type Metadata = Metadata ;
fn read_metadata ( & self , origin : String , dapps_origin : Option < String > ) -> Metadata {
2017-02-14 22:45:43 +01:00
let mut metadata = Metadata ::default ( ) ;
2017-04-03 10:27:37 +02:00
metadata . origin = match ( origin . as_str ( ) , dapps_origin ) {
( " null " , Some ( dapp ) ) = > Origin ::Dapps ( dapp . into ( ) ) ,
_ = > Origin ::Rpc ( origin ) ,
} ;
2017-02-14 22:45:43 +01:00
metadata
}
}
2017-03-16 12:48:51 +01:00
impl rpc ::IpcMetaExtractor < Metadata > for RpcExtractor {
fn extract ( & self , _req : & rpc ::IpcRequestContext ) -> Metadata {
let mut metadata = Metadata ::default ( ) ;
// TODO [ToDr] Extract proper session id when it's available in context.
metadata . origin = Origin ::Ipc ( 1. into ( ) ) ;
metadata
}
}
2017-04-03 12:44:52 +02:00
fn setup_apis < D > ( apis : ApiSet , deps : & Dependencies < D > ) -> MetaIoHandler < Metadata , Middleware < D ::Notifier > >
2017-03-22 20:14:40 +01:00
where D : rpc_apis ::Dependencies
{
2017-04-03 12:44:52 +02:00
rpc_apis ::setup_rpc ( deps . stats . clone ( ) , & * deps . apis , apis )
2017-04-03 10:27:37 +02:00
}
2017-04-03 12:44:52 +02:00
pub fn new_http < D : rpc_apis ::Dependencies > (
conf : HttpConfiguration ,
deps : & Dependencies < D > ,
middleware : Option < dapps ::Middleware >
) -> Result < Option < HttpServer > , String > {
2016-04-21 13:57:27 +02:00
if ! conf . enabled {
2016-07-25 16:09:47 +02:00
return Ok ( None ) ;
2016-04-21 13:57:27 +02:00
}
2016-06-24 12:10:36 +02:00
let url = format! ( " {} : {} " , conf . interface , conf . port ) ;
2016-12-27 12:53:56 +01:00
let addr = url . parse ( ) . map_err ( | _ | format! ( " Invalid JSONRPC listen host/port given: {} " , url ) ) ? ;
2017-04-03 10:27:37 +02:00
let handler = setup_apis ( conf . apis , deps ) ;
let remote = deps . remote . clone ( ) ;
let cors_domains : Option < Vec < _ > > = conf . cors . map ( | domains | domains . into_iter ( ) . map ( AccessControlAllowOrigin ::from ) . collect ( ) ) ;
let allowed_hosts : Option < Vec < _ > > = conf . hosts . map ( | hosts | hosts . into_iter ( ) . map ( Host ::from ) . collect ( ) ) ;
let start_result = rpc ::start_http (
& addr ,
cors_domains . into ( ) ,
allowed_hosts . into ( ) ,
handler ,
remote ,
RpcExtractor ,
match ( conf . threads , middleware ) {
( Some ( threads ) , None ) = > rpc ::HttpSettings ::Threads ( threads ) ,
( None , middleware ) = > rpc ::HttpSettings ::Dapps ( middleware ) ,
( Some ( _ ) , Some ( _ ) ) = > {
return Err ( " Dapps and fast multi-threaded RPC server cannot be enabled at the same time. " . into ( ) )
} ,
}
) ;
2016-05-04 15:37:09 +02:00
2016-04-21 13:12:43 +02:00
match start_result {
2017-04-03 10:27:37 +02:00
Ok ( server ) = > Ok ( Some ( server ) ) ,
Err ( HttpServerError ::Io ( err ) ) = > match err . kind ( ) {
io ::ErrorKind ::AddrInUse = > Err (
format! ( " RPC address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options. " , url )
) ,
2016-10-25 15:55:53 +02:00
_ = > Err ( format! ( " RPC io error: {} " , err ) ) ,
} ,
2016-07-25 16:09:47 +02:00
Err ( e ) = > Err ( format! ( " RPC error: {:?} " , e ) ) ,
2016-04-21 13:12:43 +02:00
}
}
2016-06-13 18:55:24 +02:00
2017-04-03 12:44:52 +02:00
pub fn new_ipc < D : rpc_apis ::Dependencies > (
conf : IpcConfiguration ,
dependencies : & Dependencies < D >
) -> Result < Option < IpcServer > , String > {
2017-04-03 10:27:37 +02:00
if ! conf . enabled {
return Ok ( None ) ;
}
let handler = setup_apis ( conf . apis , dependencies ) ;
2017-03-13 15:49:52 +01:00
let remote = dependencies . remote . clone ( ) ;
2017-04-03 10:27:37 +02:00
match rpc ::start_ipc ( & conf . socket_addr , handler , remote , RpcExtractor ) {
Ok ( server ) = > Ok ( Some ( server ) ) ,
2017-03-16 12:48:51 +01:00
Err ( io_error ) = > Err ( format! ( " RPC io error: {} " , io_error ) ) ,
2017-04-03 10:27:37 +02:00
}
}
#[ cfg(test) ]
mod tests {
use super ::RpcExtractor ;
use ethcore_rpc ::{ HttpMetaExtractor , Origin } ;
#[ test ]
fn should_extract_rpc_origin ( ) {
// given
let extractor = RpcExtractor ;
// when
let meta = extractor . read_metadata ( " http://parity.io " . into ( ) , None ) ;
let meta1 = extractor . read_metadata ( " http://parity.io " . into ( ) , Some ( " ignored " . into ( ) ) ) ;
// then
assert_eq! ( meta . origin , Origin ::Rpc ( " http://parity.io " . into ( ) ) ) ;
assert_eq! ( meta1 . origin , Origin ::Rpc ( " http://parity.io " . into ( ) ) ) ;
}
#[ test ]
fn should_dapps_origin ( ) {
// given
let extractor = RpcExtractor ;
let dapp = " https://wallet.ethereum.org " . to_owned ( ) ;
// when
let meta = extractor . read_metadata ( " null " . into ( ) , Some ( dapp . clone ( ) ) ) ;
// then
assert_eq! ( meta . origin , Origin ::Dapps ( dapp . into ( ) ) ) ;
2016-05-04 15:37:09 +02:00
}
}