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/>.
2016-07-25 16:09:47 +02:00
use std ::fmt ;
2016-04-21 13:12:43 +02:00
use std ::sync ::Arc ;
use std ::net ::SocketAddr ;
2016-10-25 15:55:53 +02:00
use std ::io ;
2017-01-11 20:02:27 +01:00
use dir ::default_data_path ;
2017-03-16 12:48:51 +01:00
use ethcore_rpc ::{ self as rpc , HttpServerError , Metadata , Origin , AccessControlAllowOrigin , Host } ;
2017-02-04 22:18:19 +01:00
use ethcore_rpc ::informant ::{ RpcStats , Middleware } ;
2017-01-11 20:02:27 +01:00
use helpers ::parity_ipc_path ;
2017-02-14 22:45:43 +01:00
use hyper ;
2017-01-11 20:02:27 +01:00
use jsonrpc_core ::MetaIoHandler ;
2016-06-01 19:37:34 +02:00
use rpc_apis ;
2016-07-25 16:09:47 +02:00
use rpc_apis ::ApiSet ;
2017-03-13 15:49:52 +01:00
use parity_reactor ::TokioRemote ;
2016-04-21 13:12:43 +02:00
2017-03-13 15:49:52 +01:00
pub use ethcore_rpc ::{ IpcServer , HttpServer } ;
2016-04-21 13:12:43 +02:00
2016-07-25 16:09:47 +02:00
#[ derive(Debug, 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 > > ,
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 ( ) ) ,
}
}
}
#[ 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 ;
impl rpc ::HttpMetaExtractor < Metadata > for RpcExtractor {
fn read_metadata ( & self , req : & hyper ::server ::Request < hyper ::net ::HttpStream > ) -> Metadata {
let origin = req . headers ( ) . get ::< hyper ::header ::Origin > ( )
. map ( | origin | format! ( " {} :// {} " , origin . scheme , origin . host ) )
. unwrap_or_else ( | | " unknown " . into ( ) ) ;
let mut metadata = Metadata ::default ( ) ;
metadata . origin = Origin ::Rpc ( origin ) ;
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-03-22 20:14:40 +01:00
pub fn new_http < D > ( conf : HttpConfiguration , deps : & Dependencies < D > ) -> Result < Option < HttpServer > , String >
where D : rpc_apis ::Dependencies
{
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 ) ) ? ;
Ok ( Some ( setup_http_rpc_server ( deps , & addr , conf . cors , conf . hosts , conf . apis ) ? ) )
2016-04-21 13:57:27 +02:00
}
2017-03-22 20:14:40 +01:00
fn setup_apis < D > ( apis : ApiSet , deps : & Dependencies < D > ) -> MetaIoHandler < Metadata , Middleware < D ::Notifier > >
where D : rpc_apis ::Dependencies
{
rpc_apis ::setup_rpc ( deps . stats . clone ( ) , & * deps . apis , apis )
2016-05-04 15:37:09 +02:00
}
2017-03-22 20:14:40 +01:00
pub fn setup_http_rpc_server < D : rpc_apis ::Dependencies > (
dependencies : & Dependencies < D > ,
2016-05-04 15:37:09 +02:00
url : & SocketAddr ,
2016-07-20 12:34:17 +02:00
cors_domains : Option < Vec < String > > ,
allowed_hosts : Option < Vec < String > > ,
2016-07-25 16:09:47 +02:00
apis : ApiSet
) -> Result < HttpServer , String > {
2017-03-13 15:49:52 +01:00
let handler = setup_apis ( apis , dependencies ) ;
let remote = dependencies . remote . clone ( ) ;
let cors_domains : Option < Vec < _ > > = cors_domains . map ( | domains | domains . into_iter ( ) . map ( AccessControlAllowOrigin ::from ) . collect ( ) ) ;
let allowed_hosts : Option < Vec < _ > > = allowed_hosts . map ( | hosts | hosts . into_iter ( ) . map ( Host ::from ) . collect ( ) ) ;
let start_result = rpc ::start_http ( url , cors_domains . into ( ) , allowed_hosts . into ( ) , handler , remote , RpcExtractor ) ;
2016-04-21 13:12:43 +02:00
match start_result {
2017-03-13 15:49:52 +01:00
Err ( HttpServerError ::IoError ( err ) ) = > match err . kind ( ) {
2016-10-25 15:55:53 +02:00
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 ) ) ,
_ = > Err ( format! ( " RPC io error: {} " , err ) ) ,
} ,
2016-07-25 16:09:47 +02:00
Err ( e ) = > Err ( format! ( " RPC error: {:?} " , e ) ) ,
Ok ( server ) = > Ok ( server ) ,
2016-04-21 13:12:43 +02:00
}
}
2016-06-13 18:55:24 +02:00
2017-03-22 20:14:40 +01:00
pub fn new_ipc < D : rpc_apis ::Dependencies > ( conf : IpcConfiguration , deps : & Dependencies < D > ) -> Result < Option < IpcServer > , String > {
2016-07-25 16:09:47 +02:00
if ! conf . enabled { return Ok ( None ) ; }
2016-12-27 12:53:56 +01:00
Ok ( Some ( setup_ipc_rpc_server ( deps , & conf . socket_addr , conf . apis ) ? ) )
2016-06-13 18:55:24 +02:00
}
2017-03-22 20:14:40 +01:00
pub fn setup_ipc_rpc_server < D : rpc_apis ::Dependencies > ( dependencies : & Dependencies < D > , addr : & str , apis : ApiSet ) -> Result < IpcServer , String > {
2017-03-13 15:49:52 +01:00
let handler = setup_apis ( apis , dependencies ) ;
let remote = dependencies . remote . clone ( ) ;
2017-03-16 12:48:51 +01:00
match rpc ::start_ipc ( addr , handler , remote , RpcExtractor ) {
Err ( io_error ) = > Err ( format! ( " RPC io error: {} " , io_error ) ) ,
2016-07-25 16:09:47 +02:00
Ok ( server ) = > Ok ( server )
2016-05-04 15:37:09 +02:00
}
}