Dapps and RPC server merge (#5365)
* Dapps server as a middleware. * Dapps RPC - Work in Progress * Merging Dapps and RPC server. * Fast HTTP server configuration. * Bump jsonrpc * Fixing test target * Re-implementing commented-out tests.
This commit is contained in:
parent
6a05967bef
commit
2df4532d50
148
Cargo.lock
generated
148
Cargo.lock
generated
@ -10,7 +10,6 @@ dependencies = [
|
|||||||
"docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ethcore 1.7.0",
|
"ethcore 1.7.0",
|
||||||
"ethcore-dapps 1.7.0",
|
|
||||||
"ethcore-devtools 1.7.0",
|
"ethcore-devtools 1.7.0",
|
||||||
"ethcore-io 1.7.0",
|
"ethcore-io 1.7.0",
|
||||||
"ethcore-ipc 1.7.0",
|
"ethcore-ipc 1.7.0",
|
||||||
@ -27,12 +26,12 @@ dependencies = [
|
|||||||
"ethsync 1.7.0",
|
"ethsync 1.7.0",
|
||||||
"evmbin 0.1.0",
|
"evmbin 0.1.0",
|
||||||
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
|
|
||||||
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"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)",
|
||||||
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num_cpus 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"number_prefix 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parity-dapps 1.7.0",
|
||||||
"parity-hash-fetch 1.7.0",
|
"parity-hash-fetch 1.7.0",
|
||||||
"parity-ipfs-api 1.7.0",
|
"parity-ipfs-api 1.7.0",
|
||||||
"parity-local-store 0.1.0",
|
"parity-local-store 0.1.0",
|
||||||
@ -40,6 +39,7 @@ dependencies = [
|
|||||||
"parity-rpc-client 1.4.0",
|
"parity-rpc-client 1.4.0",
|
||||||
"parity-updater 1.7.0",
|
"parity-updater 1.7.0",
|
||||||
"path 0.1.0",
|
"path 0.1.0",
|
||||||
|
"pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rlp 0.1.0",
|
"rlp 0.1.0",
|
||||||
"rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rpassword 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@ -309,6 +309,11 @@ dependencies = [
|
|||||||
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "difference"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "docopt"
|
name = "docopt"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
@ -446,40 +451,6 @@ dependencies = [
|
|||||||
"siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"siphasher 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ethcore-dapps"
|
|
||||||
version = "1.7.0"
|
|
||||||
dependencies = [
|
|
||||||
"base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"ethcore-devtools 1.7.0",
|
|
||||||
"ethcore-rpc 1.7.0",
|
|
||||||
"ethcore-util 1.7.0",
|
|
||||||
"fetch 0.1.0",
|
|
||||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
|
||||||
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
|
||||||
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
|
||||||
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"mime 0.2.0 (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-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"parity-hash-fetch 1.7.0",
|
|
||||||
"parity-reactor 0.1.0",
|
|
||||||
"parity-ui 1.7.0",
|
|
||||||
"rand 0.3.14 (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.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ethcore-devtools"
|
name = "ethcore-devtools"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@ -642,6 +613,7 @@ dependencies = [
|
|||||||
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
|
"jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"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)",
|
||||||
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"parity-reactor 0.1.0",
|
"parity-reactor 0.1.0",
|
||||||
@ -1088,7 +1060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-core"
|
name = "jsonrpc-core"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"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)",
|
||||||
@ -1100,7 +1072,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-http-server"
|
name = "jsonrpc-http-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
|
"hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)",
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
@ -1113,7 +1085,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-ipc-server"
|
name = "jsonrpc-ipc-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
@ -1125,17 +1097,31 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-macros"
|
name = "jsonrpc-macros"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jsonrpc-minihttp-server"
|
||||||
|
version = "7.0.0"
|
||||||
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
|
dependencies = [
|
||||||
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
|
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)",
|
||||||
|
"tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)",
|
||||||
|
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-pubsub"
|
name = "jsonrpc-pubsub"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"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)",
|
||||||
@ -1145,7 +1131,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-server-utils"
|
name = "jsonrpc-server-utils"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"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)",
|
||||||
@ -1156,7 +1142,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "jsonrpc-tcp-server"
|
name = "jsonrpc-tcp-server"
|
||||||
version = "7.0.0"
|
version = "7.0.0"
|
||||||
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#f4521e8a543145bec7936de0f875d6550e92c7f7"
|
source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#32c1c083139db50db6a5d532ccfc2004236dbfc3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
"jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
@ -1604,6 +1590,38 @@ dependencies = [
|
|||||||
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parity-dapps"
|
||||||
|
version = "1.7.0"
|
||||||
|
dependencies = [
|
||||||
|
"base32 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"ethcore-devtools 1.7.0",
|
||||||
|
"ethcore-util 1.7.0",
|
||||||
|
"fetch 0.1.0",
|
||||||
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
|
"jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)",
|
||||||
|
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"mime 0.2.0 (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-glue 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"parity-hash-fetch 1.7.0",
|
||||||
|
"parity-reactor 0.1.0",
|
||||||
|
"parity-ui 1.7.0",
|
||||||
|
"rand 0.3.14 (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.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_derive 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 0.9.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"url 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"zip 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parity-dapps-glue"
|
name = "parity-dapps-glue"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
@ -1826,6 +1844,14 @@ name = "podio"
|
|||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "primal"
|
name = "primal"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
@ -2431,6 +2457,21 @@ dependencies = [
|
|||||||
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-minihttp"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/tomusdrw/tokio-minihttp#8acbafae3e77e7f7eb516b441ec84695580221dd"
|
||||||
|
dependencies = [
|
||||||
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)",
|
||||||
|
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-named-pipes"
|
name = "tokio-named-pipes"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2441,6 +2482,22 @@ dependencies = [
|
|||||||
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-proto"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "git+https://github.com/tomusdrw/tokio-proto#f6ee08cb594fa2fc1b4178eaaca0855d66e68fd3"
|
||||||
|
dependencies = [
|
||||||
|
"futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"net2 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-proto"
|
name = "tokio-proto"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -2706,6 +2763,7 @@ dependencies = [
|
|||||||
"checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "<none>"
|
"checksum ctrlc 1.1.1 (git+https://github.com/paritytech/rust-ctrlc.git)" = "<none>"
|
||||||
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
|
"checksum daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "271ec51b7e0bee92f0d04601422c73eb76ececf197026711c97ad25038a010cf"
|
||||||
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
"checksum deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1614659040e711785ed8ea24219140654da1729f3ec8a47a9719d041112fe7bf"
|
||||||
|
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
|
||||||
"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
|
"checksum docopt 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab32ea6e284d87987066f21a9e809a73c14720571ef34516f0890b3d355ccfd8"
|
||||||
"checksum dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f"
|
"checksum dtoa 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5edd69c67b2f8e0911629b7e6b8a34cb3956613cd7c6e6414966dee349c2db4f"
|
||||||
"checksum either 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2b503c86dad62aaf414ecf2b8c527439abedb3f8d812537f0b12bfd6f32a91"
|
"checksum either 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3d2b503c86dad62aaf414ecf2b8c527439abedb3f8d812537f0b12bfd6f32a91"
|
||||||
@ -2739,6 +2797,7 @@ dependencies = [
|
|||||||
"checksum jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
"checksum jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-ipc-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
"checksum jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
|
"checksum jsonrpc-minihttp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
"checksum jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
"checksum jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
"checksum jsonrpc-tcp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
"checksum jsonrpc-tcp-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)" = "<none>"
|
||||||
@ -2802,6 +2861,7 @@ dependencies = [
|
|||||||
"checksum phf_shared 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fee4d039930e4f45123c9b15976cf93a499847b6483dc09c42ea0ec4940f2aa6"
|
"checksum phf_shared 0.7.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fee4d039930e4f45123c9b15976cf93a499847b6483dc09c42ea0ec4940f2aa6"
|
||||||
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
|
"checksum pkg-config 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8cee804ecc7eaf201a4a207241472cc870e825206f6c031e3ee2a72fa425f2fa"
|
||||||
"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
|
"checksum podio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e5422a1ee1bc57cc47ae717b0137314258138f38fd5f3cea083f43a9725383a0"
|
||||||
|
"checksum pretty_assertions 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2412f3332a07c7a2a50168988dcc184f32180a9758ad470390e5f55e089f6b6e"
|
||||||
"checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4"
|
"checksum primal 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0e31b86efadeaeb1235452171a66689682783149a6249ff334a2c5d8218d00a4"
|
||||||
"checksum primal-bit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "464a91febc06166783d4f5ba3577b5ed8dda8e421012df80bfe48a971ed7be8f"
|
"checksum primal-bit 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "464a91febc06166783d4f5ba3577b5ed8dda8e421012df80bfe48a971ed7be8f"
|
||||||
"checksum primal-check 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "647c81b67bb9551a7b88d0bcd785ac35b7d0bf4b2f358683d7c2375d04daec51"
|
"checksum primal-check 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "647c81b67bb9551a7b88d0bcd785ac35b7d0bf4b2f358683d7c2375d04daec51"
|
||||||
@ -2871,7 +2931,9 @@ dependencies = [
|
|||||||
"checksum tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1be481b55126f02ef88ff86748086473cb537a949fc4a8f4be403a530ae54b"
|
"checksum tokio-core 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1be481b55126f02ef88ff86748086473cb537a949fc4a8f4be403a530ae54b"
|
||||||
"checksum tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a278fde45f1be68e44995227d426aaa4841e0980bb0a21b981092f28c3c8473"
|
"checksum tokio-io 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a278fde45f1be68e44995227d426aaa4841e0980bb0a21b981092f28c3c8473"
|
||||||
"checksum tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)" = "<none>"
|
"checksum tokio-line 0.1.0 (git+https://github.com/tokio-rs/tokio-line)" = "<none>"
|
||||||
|
"checksum tokio-minihttp 0.1.0 (git+https://github.com/tomusdrw/tokio-minihttp)" = "<none>"
|
||||||
"checksum tokio-named-pipes 0.1.0 (git+https://github.com/alexcrichton/tokio-named-pipes)" = "<none>"
|
"checksum tokio-named-pipes 0.1.0 (git+https://github.com/alexcrichton/tokio-named-pipes)" = "<none>"
|
||||||
|
"checksum tokio-proto 0.1.0 (git+https://github.com/tomusdrw/tokio-proto)" = "<none>"
|
||||||
"checksum tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c0d6031f94d78d7b4d509d4a7c5e1cdf524a17e7b08d1c188a83cf720e69808"
|
"checksum tokio-proto 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7c0d6031f94d78d7b4d509d4a7c5e1cdf524a17e7b08d1c188a83cf720e69808"
|
||||||
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
|
"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162"
|
||||||
"checksum tokio-uds 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc7b5fc8e19e220b29566d1750949224a518478eab9cebc8df60583242ca30a"
|
"checksum tokio-uds 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc7b5fc8e19e220b29566d1750949224a518478eab9cebc8df60583242ca30a"
|
||||||
|
13
Cargo.toml
13
Cargo.toml
@ -25,7 +25,6 @@ serde_json = "0.9"
|
|||||||
app_dirs = "1.1.1"
|
app_dirs = "1.1.1"
|
||||||
fdlimit = "0.1"
|
fdlimit = "0.1"
|
||||||
ws2_32-sys = "0.2"
|
ws2_32-sys = "0.2"
|
||||||
hyper = { default-features = false, git = "https://github.com/paritytech/hyper" }
|
|
||||||
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
ethsync = { path = "sync" }
|
ethsync = { path = "sync" }
|
||||||
@ -50,8 +49,9 @@ parity-ipfs-api = { path = "ipfs" }
|
|||||||
parity-updater = { path = "updater" }
|
parity-updater = { path = "updater" }
|
||||||
parity-reactor = { path = "util/reactor" }
|
parity-reactor = { path = "util/reactor" }
|
||||||
parity-local-store = { path = "local-store" }
|
parity-local-store = { path = "local-store" }
|
||||||
ethcore-dapps = { path = "dapps", optional = true }
|
|
||||||
path = { path = "util/path" }
|
path = { path = "util/path" }
|
||||||
|
|
||||||
|
parity-dapps = { path = "dapps", optional = true }
|
||||||
clippy = { version = "0.0.103", optional = true}
|
clippy = { version = "0.0.103", optional = true}
|
||||||
ethcore-secretstore = { path = "secret_store", optional = true }
|
ethcore-secretstore = { path = "secret_store", optional = true }
|
||||||
|
|
||||||
@ -60,6 +60,7 @@ rustc_version = "0.2"
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
ethcore-ipc-tests = { path = "ipc/tests" }
|
ethcore-ipc-tests = { path = "ipc/tests" }
|
||||||
|
pretty_assertions = "0.1"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = "0.2"
|
winapi = "0.2"
|
||||||
@ -71,18 +72,18 @@ daemonize = "0.2"
|
|||||||
default = ["ui-precompiled"]
|
default = ["ui-precompiled"]
|
||||||
ui = [
|
ui = [
|
||||||
"dapps",
|
"dapps",
|
||||||
"ethcore-dapps/ui",
|
"parity-dapps/ui",
|
||||||
"ethcore-signer/ui",
|
"ethcore-signer/ui",
|
||||||
]
|
]
|
||||||
ui-precompiled = [
|
ui-precompiled = [
|
||||||
"dapps",
|
"dapps",
|
||||||
"ethcore-signer/ui-precompiled",
|
"ethcore-signer/ui-precompiled",
|
||||||
"ethcore-dapps/ui-precompiled",
|
"parity-dapps/ui-precompiled",
|
||||||
]
|
]
|
||||||
dapps = ["ethcore-dapps"]
|
dapps = ["parity-dapps"]
|
||||||
ipc = ["ethcore/ipc", "ethsync/ipc"]
|
ipc = ["ethcore/ipc", "ethsync/ipc"]
|
||||||
jit = ["ethcore/jit"]
|
jit = ["ethcore/jit"]
|
||||||
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
|
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "parity-dapps/dev", "ethcore-signer/dev"]
|
||||||
json-tests = ["ethcore/json-tests"]
|
json-tests = ["ethcore/json-tests"]
|
||||||
test-heavy = ["ethcore/test-heavy"]
|
test-heavy = ["ethcore/test-heavy"]
|
||||||
ethkey-cli = ["ethcore/ethkey-cli"]
|
ethkey-cli = ["ethcore/ethkey-cli"]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
description = "Parity Dapps crate"
|
description = "Parity Dapps crate"
|
||||||
name = "ethcore-dapps"
|
name = "parity-dapps"
|
||||||
version = "1.7.0"
|
version = "1.7.0"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
authors = ["Parity Technologies <admin@parity.io>"]
|
authors = ["Parity Technologies <admin@parity.io>"]
|
||||||
@ -28,11 +28,8 @@ zip = { version = "0.1", default-features = false }
|
|||||||
|
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
# TODO [ToDr] Temporary solution, server should be merged with RPC.
|
|
||||||
jsonrpc-server-utils = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
|
||||||
|
|
||||||
ethcore-devtools = { path = "../devtools" }
|
ethcore-devtools = { path = "../devtools" }
|
||||||
ethcore-rpc = { path = "../rpc" }
|
|
||||||
ethcore-util = { path = "../util" }
|
ethcore-util = { path = "../util" }
|
||||||
fetch = { path = "../util/fetch" }
|
fetch = { path = "../util/fetch" }
|
||||||
parity-hash-fetch = { path = "../hash-fetch" }
|
parity-hash-fetch = { path = "../hash-fetch" }
|
||||||
@ -42,7 +39,7 @@ parity-ui = { path = "./ui" }
|
|||||||
clippy = { version = "0.0.103", optional = true}
|
clippy = { version = "0.0.103", optional = true}
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"]
|
dev = ["clippy", "ethcore-util/dev"]
|
||||||
|
|
||||||
ui = ["parity-ui/no-precompiled-js"]
|
ui = ["parity-ui/no-precompiled-js"]
|
||||||
ui-precompiled = ["parity-ui/use-precompiled-js"]
|
ui-precompiled = ["parity-ui/use-precompiled-js"]
|
||||||
|
@ -14,7 +14,6 @@
|
|||||||
// 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 std::sync::Arc;
|
|
||||||
use unicase::UniCase;
|
use unicase::UniCase;
|
||||||
use hyper::{server, net, Decoder, Encoder, Next, Control};
|
use hyper::{server, net, Decoder, Encoder, Next, Control};
|
||||||
use hyper::header;
|
use hyper::header;
|
||||||
@ -26,48 +25,49 @@ use apps::fetcher::Fetcher;
|
|||||||
|
|
||||||
use handlers::extract_url;
|
use handlers::extract_url;
|
||||||
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, Handler, EndpointPath};
|
||||||
use jsonrpc_http_server;
|
use jsonrpc_http_server::{self, AccessControlAllowOrigin};
|
||||||
use jsonrpc_server_utils::cors;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct RestApi {
|
pub struct RestApi<F> {
|
||||||
cors_domains: Option<Vec<cors::AccessControlAllowOrigin>>,
|
// TODO [ToDr] cors_domains should be handled by the server to avoid duplicated logic.
|
||||||
endpoints: Arc<Endpoints>,
|
// RequestMiddleware should be able to tell that cors headers should be included.
|
||||||
fetcher: Arc<Fetcher>,
|
cors_domains: Option<Vec<AccessControlAllowOrigin>>,
|
||||||
|
apps: Vec<App>,
|
||||||
|
fetcher: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestApi {
|
impl<F: Fetcher + Clone> RestApi<F> {
|
||||||
pub fn new(cors_domains: Vec<cors::AccessControlAllowOrigin>, endpoints: Arc<Endpoints>, fetcher: Arc<Fetcher>) -> Box<Endpoint> {
|
pub fn new(cors_domains: Vec<AccessControlAllowOrigin>, endpoints: &Endpoints, fetcher: F) -> Box<Endpoint> {
|
||||||
Box::new(RestApi {
|
Box::new(RestApi {
|
||||||
cors_domains: Some(cors_domains),
|
cors_domains: Some(cors_domains),
|
||||||
endpoints: endpoints,
|
apps: Self::list_apps(endpoints),
|
||||||
fetcher: fetcher,
|
fetcher: fetcher,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_apps(&self) -> Vec<App> {
|
fn list_apps(endpoints: &Endpoints) -> Vec<App> {
|
||||||
self.endpoints.iter().filter_map(|(ref k, ref e)| {
|
endpoints.iter().filter_map(|(ref k, ref e)| {
|
||||||
e.info().map(|ref info| App::from_info(k, info))
|
e.info().map(|ref info| App::from_info(k, info))
|
||||||
}).collect()
|
}).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Endpoint for RestApi {
|
impl<F: Fetcher + Clone> Endpoint for RestApi<F> {
|
||||||
fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<Handler> {
|
fn to_async_handler(&self, path: EndpointPath, control: Control) -> Box<Handler> {
|
||||||
Box::new(RestApiRouter::new(self.clone(), path, control))
|
Box::new(RestApiRouter::new((*self).clone(), path, control))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RestApiRouter {
|
struct RestApiRouter<F> {
|
||||||
api: RestApi,
|
api: RestApi<F>,
|
||||||
cors_header: Option<header::AccessControlAllowOrigin>,
|
cors_header: Option<header::AccessControlAllowOrigin>,
|
||||||
path: Option<EndpointPath>,
|
path: Option<EndpointPath>,
|
||||||
control: Option<Control>,
|
control: Option<Control>,
|
||||||
handler: Box<Handler>,
|
handler: Box<Handler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RestApiRouter {
|
impl<F: Fetcher> RestApiRouter<F> {
|
||||||
fn new(api: RestApi, path: EndpointPath, control: Control) -> Self {
|
fn new(api: RestApi<F>, path: EndpointPath, control: Control) -> Self {
|
||||||
RestApiRouter {
|
RestApiRouter {
|
||||||
path: Some(path),
|
path: Some(path),
|
||||||
cors_header: None,
|
cors_header: None,
|
||||||
@ -114,7 +114,7 @@ impl RestApiRouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl server::Handler<net::HttpStream> for RestApiRouter {
|
impl<F: Fetcher> server::Handler<net::HttpStream> for RestApiRouter<F> {
|
||||||
|
|
||||||
fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next {
|
fn on_request(&mut self, request: server::Request<net::HttpStream>) -> Next {
|
||||||
self.cors_header = jsonrpc_http_server::cors_header(&request, &self.api.cors_domains).into();
|
self.cors_header = jsonrpc_http_server::cors_header(&request, &self.api.cors_domains).into();
|
||||||
@ -142,7 +142,7 @@ impl server::Handler<net::HttpStream> for RestApiRouter {
|
|||||||
if let Some(ref hash) = hash { path.app_id = hash.clone().to_owned() }
|
if let Some(ref hash) = hash { path.app_id = hash.clone().to_owned() }
|
||||||
|
|
||||||
let handler = endpoint.and_then(|v| match v {
|
let handler = endpoint.and_then(|v| match v {
|
||||||
"apps" => Some(response::as_json(&self.api.list_apps())),
|
"apps" => Some(response::as_json(&self.api.apps)),
|
||||||
"ping" => Some(response::ping()),
|
"ping" => Some(response::ping()),
|
||||||
"content" => self.resolve_content(hash, path, control),
|
"content" => self.resolve_content(hash, path, control),
|
||||||
_ => None
|
_ => None
|
||||||
|
@ -47,7 +47,8 @@ pub trait Fetcher: Send + Sync + 'static {
|
|||||||
fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler>;
|
fn to_async_handler(&self, path: EndpointPath, control: hyper::Control) -> Box<Handler>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + Send + Sync + 'static = URLHintContract> {
|
#[derive(Clone)]
|
||||||
|
pub struct ContentFetcher<F: Fetch + Clone = FetchClient, R: URLHint + Clone + 'static = URLHintContract> {
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
resolver: R,
|
resolver: R,
|
||||||
cache: Arc<Mutex<ContentCache>>,
|
cache: Arc<Mutex<ContentCache>>,
|
||||||
@ -57,14 +58,14 @@ pub struct ContentFetcher<F: Fetch = FetchClient, R: URLHint + Send + Sync + 'st
|
|||||||
fetch: F,
|
fetch: F,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: URLHint + Send + Sync + 'static, F: Fetch> Drop for ContentFetcher<F, R> {
|
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> Drop for ContentFetcher<F, R> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
// Clear cache path
|
// Clear cache path
|
||||||
let _ = fs::remove_dir_all(&self.dapps_path);
|
let _ = fs::remove_dir_all(&self.dapps_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: URLHint + Send + Sync + 'static, F: Fetch> ContentFetcher<F, R> {
|
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> ContentFetcher<F, R> {
|
||||||
|
|
||||||
pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>, remote: Remote, fetch: F) -> Self {
|
pub fn new(resolver: R, sync_status: Arc<SyncStatus>, embeddable_on: Option<(String, u16)>, remote: Remote, fetch: F) -> Self {
|
||||||
let mut dapps_path = env::temp_dir();
|
let mut dapps_path = env::temp_dir();
|
||||||
@ -97,7 +98,7 @@ impl<R: URLHint + Send + Sync + 'static, F: Fetch> ContentFetcher<F, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: URLHint + Send + Sync + 'static, F: Fetch> Fetcher for ContentFetcher<F, R> {
|
impl<R: URLHint + Clone + 'static, F: Fetch + Clone> Fetcher for ContentFetcher<F, R> {
|
||||||
fn contains(&self, content_id: &str) -> bool {
|
fn contains(&self, content_id: &str) -> bool {
|
||||||
{
|
{
|
||||||
let mut cache = self.cache.lock();
|
let mut cache = self.cache.lock();
|
||||||
@ -233,6 +234,7 @@ mod tests {
|
|||||||
use page::LocalPageEndpoint;
|
use page::LocalPageEndpoint;
|
||||||
use super::{ContentFetcher, Fetcher};
|
use super::{ContentFetcher, Fetcher};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
struct FakeResolver;
|
struct FakeResolver;
|
||||||
impl URLHint for FakeResolver {
|
impl URLHint for FakeResolver {
|
||||||
fn resolve(&self, _id: Bytes) -> Option<URLHintResult> {
|
fn resolve(&self, _id: Bytes) -> Option<URLHintResult> {
|
||||||
|
@ -16,9 +16,10 @@
|
|||||||
|
|
||||||
//! URL Endpoint traits
|
//! URL Endpoint traits
|
||||||
|
|
||||||
use hyper::{self, server, net};
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
use hyper::{self, server, net};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Default, Clone)]
|
#[derive(Debug, PartialEq, Default, Clone)]
|
||||||
pub struct EndpointPath {
|
pub struct EndpointPath {
|
||||||
pub app_id: String,
|
pub app_id: String,
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! Authorization Handlers
|
|
||||||
|
|
||||||
use hyper::{server, Decoder, Encoder, Next};
|
|
||||||
use hyper::net::HttpStream;
|
|
||||||
use hyper::status::StatusCode;
|
|
||||||
|
|
||||||
pub struct AuthRequiredHandler;
|
|
||||||
|
|
||||||
impl server::Handler<HttpStream> for AuthRequiredHandler {
|
|
||||||
fn on_request(&mut self, _request: server::Request<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_request_readable(&mut self, _decoder: &mut Decoder<HttpStream>) -> Next {
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response(&mut self, res: &mut server::Response) -> Next {
|
|
||||||
res.set_status(StatusCode::Unauthorized);
|
|
||||||
res.headers_mut().set_raw("WWW-Authenticate", vec![b"Basic realm=\"Parity\"".to_vec()]);
|
|
||||||
Next::write()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn on_response_writable(&mut self, _encoder: &mut Encoder<HttpStream>) -> Next {
|
|
||||||
Next::end()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -16,14 +16,12 @@
|
|||||||
|
|
||||||
//! Hyper handlers implementations.
|
//! Hyper handlers implementations.
|
||||||
|
|
||||||
mod auth;
|
|
||||||
mod content;
|
mod content;
|
||||||
mod echo;
|
mod echo;
|
||||||
mod fetch;
|
mod fetch;
|
||||||
mod redirect;
|
mod redirect;
|
||||||
mod streaming;
|
mod streaming;
|
||||||
|
|
||||||
pub use self::auth::AuthRequiredHandler;
|
|
||||||
pub use self::content::ContentHandler;
|
pub use self::content::ContentHandler;
|
||||||
pub use self::echo::EchoHandler;
|
pub use self::echo::EchoHandler;
|
||||||
pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse};
|
pub use self::fetch::{ContentFetcherHandler, ContentValidator, FetchControl, ValidatorResponse};
|
||||||
|
358
dapps/src/lib.rs
358
dapps/src/lib.rs
@ -34,9 +34,7 @@ extern crate zip;
|
|||||||
|
|
||||||
extern crate jsonrpc_core;
|
extern crate jsonrpc_core;
|
||||||
extern crate jsonrpc_http_server;
|
extern crate jsonrpc_http_server;
|
||||||
extern crate jsonrpc_server_utils;
|
|
||||||
|
|
||||||
extern crate ethcore_rpc;
|
|
||||||
extern crate ethcore_util as util;
|
extern crate ethcore_util as util;
|
||||||
extern crate fetch;
|
extern crate fetch;
|
||||||
extern crate parity_dapps_glue as parity_dapps;
|
extern crate parity_dapps_glue as parity_dapps;
|
||||||
@ -61,7 +59,6 @@ mod apps;
|
|||||||
mod page;
|
mod page;
|
||||||
mod router;
|
mod router;
|
||||||
mod handlers;
|
mod handlers;
|
||||||
mod rpc;
|
|
||||||
mod api;
|
mod api;
|
||||||
mod proxypac;
|
mod proxypac;
|
||||||
mod url;
|
mod url;
|
||||||
@ -69,23 +66,16 @@ mod web;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use jsonrpc_core::{Middleware, MetaIoHandler};
|
use jsonrpc_http_server::{self as http, hyper, AccessControlAllowOrigin};
|
||||||
use jsonrpc_http_server::tokio_core::reactor::Remote as TokioRemote;
|
|
||||||
pub use jsonrpc_http_server::{DomainsValidation, Host, AccessControlAllowOrigin};
|
|
||||||
pub use jsonrpc_http_server::hyper;
|
|
||||||
|
|
||||||
use ethcore_rpc::Metadata;
|
use fetch::Fetch;
|
||||||
use fetch::{Fetch, Client as FetchClient};
|
|
||||||
use hash_fetch::urlhint::ContractClient;
|
|
||||||
use parity_reactor::Remote;
|
use parity_reactor::Remote;
|
||||||
use router::auth::{Authorization, NoAuth, HttpBasicAuth};
|
|
||||||
|
|
||||||
use self::apps::{HOME_PAGE, DAPPS_DOMAIN};
|
pub use hash_fetch::urlhint::ContractClient;
|
||||||
|
|
||||||
/// Indicates sync status
|
/// Indicates sync status
|
||||||
pub trait SyncStatus: Send + Sync {
|
pub trait SyncStatus: Send + Sync {
|
||||||
@ -107,296 +97,92 @@ impl<F> WebProxyTokens for F where F: Fn(String) -> bool + Send + Sync {
|
|||||||
fn is_web_proxy_token_valid(&self, token: &str) -> bool { self(token.to_owned()) }
|
fn is_web_proxy_token_valid(&self, token: &str) -> bool { self(token.to_owned()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Webapps HTTP+RPC server build.
|
/// Dapps server as `jsonrpc-http-server` request middleware.
|
||||||
pub struct ServerBuilder<T: Fetch = FetchClient> {
|
pub struct Middleware<F: Fetch + Clone> {
|
||||||
dapps_path: PathBuf,
|
router: router::Router<apps::fetcher::ContentFetcher<F>>,
|
||||||
extra_dapps: Vec<PathBuf>,
|
|
||||||
registrar: Arc<ContractClient>,
|
|
||||||
sync_status: Arc<SyncStatus>,
|
|
||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
|
||||||
signer_address: Option<(String, u16)>,
|
|
||||||
allowed_hosts: Option<Vec<Host>>,
|
|
||||||
extra_cors: Option<Vec<AccessControlAllowOrigin>>,
|
|
||||||
remote: Remote,
|
|
||||||
fetch: Option<T>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServerBuilder {
|
impl<F: Fetch + Clone> Middleware<F> {
|
||||||
/// Construct new dapps server
|
/// Creates new Dapps server middleware.
|
||||||
pub fn new<P: AsRef<Path>>(dapps_path: P, registrar: Arc<ContractClient>, remote: Remote) -> Self {
|
pub fn new(
|
||||||
ServerBuilder {
|
remote: Remote,
|
||||||
dapps_path: dapps_path.as_ref().to_owned(),
|
|
||||||
extra_dapps: vec![],
|
|
||||||
registrar: registrar,
|
|
||||||
sync_status: Arc::new(|| false),
|
|
||||||
web_proxy_tokens: Arc::new(|_| false),
|
|
||||||
signer_address: None,
|
|
||||||
allowed_hosts: Some(vec![]),
|
|
||||||
extra_cors: None,
|
|
||||||
remote: remote,
|
|
||||||
fetch: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Fetch> ServerBuilder<T> {
|
|
||||||
/// Set a fetch client to use.
|
|
||||||
pub fn fetch<X: Fetch>(self, fetch: X) -> ServerBuilder<X> {
|
|
||||||
ServerBuilder {
|
|
||||||
dapps_path: self.dapps_path,
|
|
||||||
extra_dapps: vec![],
|
|
||||||
registrar: self.registrar,
|
|
||||||
sync_status: self.sync_status,
|
|
||||||
web_proxy_tokens: self.web_proxy_tokens,
|
|
||||||
signer_address: self.signer_address,
|
|
||||||
allowed_hosts: self.allowed_hosts,
|
|
||||||
extra_cors: self.extra_cors,
|
|
||||||
remote: self.remote,
|
|
||||||
fetch: Some(fetch),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change default sync status.
|
|
||||||
pub fn sync_status(mut self, status: Arc<SyncStatus>) -> Self {
|
|
||||||
self.sync_status = status;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change default web proxy tokens validator.
|
|
||||||
pub fn web_proxy_tokens(mut self, tokens: Arc<WebProxyTokens>) -> Self {
|
|
||||||
self.web_proxy_tokens = tokens;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change default signer port.
|
|
||||||
pub fn signer_address(mut self, signer_address: Option<(String, u16)>) -> Self {
|
|
||||||
self.signer_address = signer_address;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change allowed hosts.
|
|
||||||
/// `None` - All hosts are allowed
|
|
||||||
/// `Some(whitelist)` - Allow only whitelisted hosts (+ listen address)
|
|
||||||
pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<Host>) -> Self {
|
|
||||||
self.allowed_hosts = allowed_hosts.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Extra cors headers.
|
|
||||||
/// `None` - no additional CORS URLs
|
|
||||||
pub fn extra_cors_headers(mut self, cors: DomainsValidation<AccessControlAllowOrigin>) -> Self {
|
|
||||||
self.extra_cors = cors.into();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Change extra dapps paths (apart from `dapps_path`)
|
|
||||||
pub fn extra_dapps<P: AsRef<Path>>(mut self, extra_dapps: &[P]) -> Self {
|
|
||||||
self.extra_dapps = extra_dapps.iter().map(|p| p.as_ref().to_owned()).collect();
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asynchronously start server with no authentication,
|
|
||||||
/// returns result with `Server` handle on success or an error.
|
|
||||||
pub fn start_unsecured_http<S: Middleware<Metadata>>(self, addr: &SocketAddr, handler: MetaIoHandler<Metadata, S>, tokio_remote: TokioRemote) -> Result<Server, ServerError> {
|
|
||||||
let fetch = self.fetch_client()?;
|
|
||||||
Server::start_http(
|
|
||||||
addr,
|
|
||||||
self.allowed_hosts,
|
|
||||||
self.extra_cors,
|
|
||||||
NoAuth,
|
|
||||||
handler,
|
|
||||||
self.dapps_path,
|
|
||||||
self.extra_dapps,
|
|
||||||
self.signer_address,
|
|
||||||
self.registrar,
|
|
||||||
self.sync_status,
|
|
||||||
self.web_proxy_tokens,
|
|
||||||
self.remote,
|
|
||||||
tokio_remote,
|
|
||||||
fetch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Asynchronously start server with `HTTP Basic Authentication`,
|
|
||||||
/// return result with `Server` handle on success or an error.
|
|
||||||
pub fn start_basic_auth_http<S: Middleware<Metadata>>(self, addr: &SocketAddr, username: &str, password: &str, handler: MetaIoHandler<Metadata, S>, tokio_remote: TokioRemote) -> Result<Server, ServerError> {
|
|
||||||
let fetch = self.fetch_client()?;
|
|
||||||
Server::start_http(
|
|
||||||
addr,
|
|
||||||
self.allowed_hosts,
|
|
||||||
self.extra_cors,
|
|
||||||
HttpBasicAuth::single_user(username, password),
|
|
||||||
handler,
|
|
||||||
self.dapps_path,
|
|
||||||
self.extra_dapps,
|
|
||||||
self.signer_address,
|
|
||||||
self.registrar,
|
|
||||||
self.sync_status,
|
|
||||||
self.web_proxy_tokens,
|
|
||||||
self.remote,
|
|
||||||
tokio_remote,
|
|
||||||
fetch,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch_client(&self) -> Result<T, ServerError> {
|
|
||||||
match self.fetch.clone() {
|
|
||||||
Some(fetch) => Ok(fetch),
|
|
||||||
None => T::new().map_err(|_| ServerError::FetchInitialization),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Webapps HTTP server.
|
|
||||||
pub struct Server {
|
|
||||||
server: Option<hyper::server::Listening>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Server {
|
|
||||||
/// Returns a list of allowed hosts or `None` if all hosts are allowed.
|
|
||||||
fn allowed_hosts(hosts: Option<Vec<Host>>, bind_address: String) -> Option<Vec<Host>> {
|
|
||||||
let mut allowed = Vec::new();
|
|
||||||
|
|
||||||
match hosts {
|
|
||||||
Some(hosts) => allowed.extend_from_slice(&hosts),
|
|
||||||
None => return None,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add localhost domain as valid too if listening on loopback interface.
|
|
||||||
allowed.push(bind_address.replace("127.0.0.1", "localhost").into());
|
|
||||||
allowed.push(bind_address.into());
|
|
||||||
Some(allowed)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a list of CORS domains for API endpoint.
|
|
||||||
fn cors_domains(
|
|
||||||
signer_address: Option<(String, u16)>,
|
signer_address: Option<(String, u16)>,
|
||||||
extra_cors: Option<Vec<AccessControlAllowOrigin>>,
|
|
||||||
) -> Vec<AccessControlAllowOrigin> {
|
|
||||||
let basic_cors = match signer_address {
|
|
||||||
Some(signer_address) => [
|
|
||||||
format!("http://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
|
||||||
format!("http://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
|
||||||
format!("http://{}", address(&signer_address)),
|
|
||||||
format!("https://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
|
||||||
format!("https://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
|
||||||
format!("https://{}", address(&signer_address)),
|
|
||||||
].into_iter().map(|val| AccessControlAllowOrigin::Value(val.into())).collect(),
|
|
||||||
None => vec![],
|
|
||||||
};
|
|
||||||
|
|
||||||
match extra_cors {
|
|
||||||
None => basic_cors,
|
|
||||||
Some(extra_cors) => basic_cors.into_iter().chain(extra_cors).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_http<A: Authorization + 'static, F: Fetch, T: Middleware<Metadata>>(
|
|
||||||
addr: &SocketAddr,
|
|
||||||
hosts: Option<Vec<Host>>,
|
|
||||||
extra_cors: Option<Vec<AccessControlAllowOrigin>>,
|
|
||||||
authorization: A,
|
|
||||||
handler: MetaIoHandler<Metadata, T>,
|
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
signer_address: Option<(String, u16)>,
|
|
||||||
registrar: Arc<ContractClient>,
|
registrar: Arc<ContractClient>,
|
||||||
sync_status: Arc<SyncStatus>,
|
sync_status: Arc<SyncStatus>,
|
||||||
web_proxy_tokens: Arc<WebProxyTokens>,
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
remote: Remote,
|
|
||||||
tokio_remote: TokioRemote,
|
|
||||||
fetch: F,
|
fetch: F,
|
||||||
) -> Result<Server, ServerError> {
|
) -> Self {
|
||||||
let authorization = Arc::new(authorization);
|
let content_fetcher = apps::fetcher::ContentFetcher::new(
|
||||||
let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new(
|
|
||||||
hash_fetch::urlhint::URLHintContract::new(registrar),
|
hash_fetch::urlhint::URLHintContract::new(registrar),
|
||||||
sync_status,
|
sync_status,
|
||||||
signer_address.clone(),
|
signer_address.clone(),
|
||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
));
|
);
|
||||||
let endpoints = Arc::new(apps::all_endpoints(
|
let endpoints = apps::all_endpoints(
|
||||||
dapps_path,
|
dapps_path,
|
||||||
extra_dapps,
|
extra_dapps,
|
||||||
signer_address.clone(),
|
signer_address.clone(),
|
||||||
web_proxy_tokens,
|
web_proxy_tokens,
|
||||||
remote.clone(),
|
remote.clone(),
|
||||||
fetch.clone(),
|
fetch.clone(),
|
||||||
));
|
);
|
||||||
let cors_domains = Self::cors_domains(signer_address.clone(), extra_cors);
|
|
||||||
|
|
||||||
let special = Arc::new({
|
let cors_domains = cors_domains(signer_address.clone());
|
||||||
|
|
||||||
|
let special = {
|
||||||
let mut special = HashMap::new();
|
let mut special = HashMap::new();
|
||||||
special.insert(router::SpecialEndpoint::Rpc, rpc::rpc(handler, tokio_remote, cors_domains.clone()));
|
special.insert(router::SpecialEndpoint::Rpc, None);
|
||||||
special.insert(router::SpecialEndpoint::Utils, apps::utils());
|
special.insert(router::SpecialEndpoint::Utils, Some(apps::utils()));
|
||||||
special.insert(
|
special.insert(
|
||||||
router::SpecialEndpoint::Api,
|
router::SpecialEndpoint::Api,
|
||||||
api::RestApi::new(cors_domains, endpoints.clone(), content_fetcher.clone())
|
Some(api::RestApi::new(cors_domains.clone(), &endpoints, content_fetcher.clone())),
|
||||||
);
|
);
|
||||||
special
|
special
|
||||||
});
|
};
|
||||||
let hosts = Self::allowed_hosts(hosts, format!("{}", addr));
|
|
||||||
|
|
||||||
hyper::Server::http(addr)?
|
let router = router::Router::new(
|
||||||
.handle(move |ctrl| router::Router::new(
|
signer_address,
|
||||||
ctrl,
|
content_fetcher,
|
||||||
signer_address.clone(),
|
endpoints,
|
||||||
content_fetcher.clone(),
|
special,
|
||||||
endpoints.clone(),
|
);
|
||||||
special.clone(),
|
|
||||||
authorization.clone(),
|
|
||||||
hosts.clone(),
|
|
||||||
))
|
|
||||||
.map(|(l, srv)| {
|
|
||||||
|
|
||||||
::std::thread::spawn(move || {
|
Middleware {
|
||||||
srv.run();
|
router: router,
|
||||||
});
|
|
||||||
|
|
||||||
Server {
|
|
||||||
server: Some(l),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map_err(ServerError::from)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
/// Returns address that this server is bound to.
|
|
||||||
pub fn addr(&self) -> &SocketAddr {
|
|
||||||
self.server.as_ref()
|
|
||||||
.expect("server is always Some at the start; it's consumed only when object is dropped; qed")
|
|
||||||
.addrs()
|
|
||||||
.first()
|
|
||||||
.expect("You cannot start the server without binding to at least one address; qed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for Server {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
self.server.take().unwrap().close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Webapp Server startup error
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ServerError {
|
|
||||||
/// Wrapped `std::io::Error`
|
|
||||||
IoError(std::io::Error),
|
|
||||||
/// Other `hyper` error
|
|
||||||
Other(hyper::error::Error),
|
|
||||||
/// Fetch service initialization error
|
|
||||||
FetchInitialization,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<hyper::error::Error> for ServerError {
|
|
||||||
fn from(err: hyper::error::Error) -> Self {
|
|
||||||
match err {
|
|
||||||
hyper::error::Error::Io(e) => ServerError::IoError(e),
|
|
||||||
e => ServerError::Other(e),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F: Fetch + Clone> http::RequestMiddleware for Middleware<F> {
|
||||||
|
fn on_request(&self, req: &hyper::server::Request<hyper::net::HttpStream>, control: &hyper::Control) -> http::RequestMiddlewareAction {
|
||||||
|
self.router.on_request(req, control)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a list of CORS domains for API endpoint.
|
||||||
|
fn cors_domains(signer_address: Option<(String, u16)>) -> Vec<AccessControlAllowOrigin> {
|
||||||
|
use self::apps::{HOME_PAGE, DAPPS_DOMAIN};
|
||||||
|
|
||||||
|
match signer_address {
|
||||||
|
Some(signer_address) => [
|
||||||
|
format!("http://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
||||||
|
format!("http://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
||||||
|
format!("http://{}", address(&signer_address)),
|
||||||
|
format!("https://{}{}", HOME_PAGE, DAPPS_DOMAIN),
|
||||||
|
format!("https://{}{}:{}", HOME_PAGE, DAPPS_DOMAIN, signer_address.1),
|
||||||
|
format!("https://{}", address(&signer_address)),
|
||||||
|
].into_iter().map(|val| AccessControlAllowOrigin::Value(val.into())).collect(),
|
||||||
|
None => vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn address(address: &(String, u16)) -> String {
|
||||||
|
format!("{}:{}", address.0, address.1)
|
||||||
|
}
|
||||||
|
|
||||||
/// Random filename
|
/// Random filename
|
||||||
fn random_filename() -> String {
|
fn random_filename() -> String {
|
||||||
use ::rand::Rng;
|
use ::rand::Rng;
|
||||||
@ -404,39 +190,18 @@ fn random_filename() -> String {
|
|||||||
rng.gen_ascii_chars().take(12).collect()
|
rng.gen_ascii_chars().take(12).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn address(address: &(String, u16)) -> String {
|
|
||||||
format!("{}:{}", address.0, address.1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod util_tests {
|
mod util_tests {
|
||||||
use super::Server;
|
use super::cors_domains;
|
||||||
use jsonrpc_http_server::AccessControlAllowOrigin;
|
use jsonrpc_http_server::AccessControlAllowOrigin;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_return_allowed_hosts() {
|
|
||||||
// given
|
|
||||||
let bind_address = "127.0.0.1".to_owned();
|
|
||||||
|
|
||||||
// when
|
|
||||||
let all = Server::allowed_hosts(None, bind_address.clone());
|
|
||||||
let address = Server::allowed_hosts(Some(Vec::new()), bind_address.clone());
|
|
||||||
let some = Server::allowed_hosts(Some(vec!["ethcore.io".into()]), bind_address.clone());
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(all, None);
|
|
||||||
assert_eq!(address, Some(vec!["localhost".into(), "127.0.0.1".into()]));
|
|
||||||
assert_eq!(some, Some(vec!["ethcore.io".into(), "localhost".into(), "127.0.0.1".into()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_cors_domains() {
|
fn should_return_cors_domains() {
|
||||||
// given
|
// given
|
||||||
|
|
||||||
// when
|
// when
|
||||||
let none = Server::cors_domains(None, None);
|
let none = cors_domains(None);
|
||||||
let some = Server::cors_domains(Some(("127.0.0.1".into(), 18180)), None);
|
let some = cors_domains(Some(("127.0.0.1".into(), 18180)));
|
||||||
let extra = Server::cors_domains(None, Some(vec!["all".into()]));
|
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(none, Vec::<AccessControlAllowOrigin>::new());
|
assert_eq!(none, Vec::<AccessControlAllowOrigin>::new());
|
||||||
@ -448,6 +213,5 @@ mod util_tests {
|
|||||||
"https://parity.web3.site:18180".into(),
|
"https://parity.web3.site:18180".into(),
|
||||||
"https://127.0.0.1:18180".into(),
|
"https://127.0.0.1:18180".into(),
|
||||||
]);
|
]);
|
||||||
assert_eq!(extra, vec![AccessControlAllowOrigin::Any]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,24 +15,20 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Router implementation
|
//! Router implementation
|
||||||
//! Processes request handling authorization and dispatching it to proper application.
|
//! Dispatch requests to proper application.
|
||||||
|
|
||||||
pub mod auth;
|
|
||||||
mod host_validation;
|
|
||||||
|
|
||||||
use address;
|
use address;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::sync::Arc;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use url::{Url, Host};
|
use url::{Url, Host};
|
||||||
use hyper::{self, server, header, Next, Encoder, Decoder, Control, StatusCode};
|
use hyper::{self, server, header, Control, StatusCode};
|
||||||
use hyper::net::HttpStream;
|
use hyper::net::HttpStream;
|
||||||
use jsonrpc_server_utils::hosts;
|
use jsonrpc_http_server as http;
|
||||||
|
|
||||||
use apps::{self, DAPPS_DOMAIN};
|
use apps::{self, DAPPS_DOMAIN};
|
||||||
use apps::fetcher::Fetcher;
|
use apps::fetcher::Fetcher;
|
||||||
use endpoint::{Endpoint, Endpoints, EndpointPath};
|
use endpoint::{Endpoint, Endpoints, EndpointPath, Handler};
|
||||||
use handlers::{self, Redirection, ContentHandler};
|
use handlers::{self, Redirection, ContentHandler};
|
||||||
|
|
||||||
/// Special endpoints are accessible on every domain (every dapp)
|
/// Special endpoints are accessible on every domain (every dapp)
|
||||||
@ -44,51 +40,29 @@ pub enum SpecialEndpoint {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Router<A: auth::Authorization + 'static> {
|
pub struct Router<F> {
|
||||||
control: Option<Control>,
|
|
||||||
signer_address: Option<(String, u16)>,
|
signer_address: Option<(String, u16)>,
|
||||||
endpoints: Arc<Endpoints>,
|
endpoints: Endpoints,
|
||||||
fetch: Arc<Fetcher>,
|
fetch: F,
|
||||||
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
|
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
|
||||||
authorization: Arc<A>,
|
|
||||||
allowed_hosts: Option<Vec<hosts::Host>>,
|
|
||||||
handler: Box<server::Handler<HttpStream> + Send>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: auth::Authorization + 'static> server::Handler<HttpStream> for Router<A> {
|
impl<F: Fetcher + 'static> http::RequestMiddleware for Router<F> {
|
||||||
|
fn on_request(&self, req: &server::Request<HttpStream>, control: &Control) -> http::RequestMiddlewareAction {
|
||||||
fn on_request(&mut self, req: server::Request<HttpStream>) -> Next {
|
|
||||||
// Choose proper handler depending on path / domain
|
// Choose proper handler depending on path / domain
|
||||||
let url = handlers::extract_url(&req);
|
let url = handlers::extract_url(req);
|
||||||
let endpoint = extract_endpoint(&url);
|
let endpoint = extract_endpoint(&url);
|
||||||
let referer = extract_referer_endpoint(&req);
|
let referer = extract_referer_endpoint(req);
|
||||||
let is_utils = endpoint.1 == SpecialEndpoint::Utils;
|
let is_utils = endpoint.1 == SpecialEndpoint::Utils;
|
||||||
|
let is_dapps_domain = endpoint.0.as_ref().map(|endpoint| endpoint.using_dapps_domains).unwrap_or(false);
|
||||||
|
let is_origin_set = req.headers().get::<http::hyper::header::Origin>().is_some();
|
||||||
let is_get_request = *req.method() == hyper::Method::Get;
|
let is_get_request = *req.method() == hyper::Method::Get;
|
||||||
|
|
||||||
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", url, req);
|
trace!(target: "dapps", "Routing request to {:?}. Details: {:?}", url, req);
|
||||||
|
|
||||||
// Validate Host header
|
let control = control.clone();
|
||||||
trace!(target: "dapps", "Validating host headers against: {:?}", self.allowed_hosts);
|
|
||||||
let is_valid = is_utils || host_validation::is_valid(&req, &self.allowed_hosts);
|
|
||||||
if !is_valid {
|
|
||||||
debug!(target: "dapps", "Rejecting invalid host header.");
|
|
||||||
self.handler = host_validation::host_invalid_response();
|
|
||||||
return self.handler.on_request(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
trace!(target: "dapps", "Checking authorization.");
|
|
||||||
// Check authorization
|
|
||||||
let auth = self.authorization.is_authorized(&req);
|
|
||||||
if let auth::Authorized::No(handler) = auth {
|
|
||||||
debug!(target: "dapps", "Authorization denied.");
|
|
||||||
self.handler = handler;
|
|
||||||
return self.handler.on_request(req);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
let control = self.control.take().expect("on_request is called only once; control is always defined at start; qed");
|
|
||||||
debug!(target: "dapps", "Handling endpoint request: {:?}", endpoint);
|
debug!(target: "dapps", "Handling endpoint request: {:?}", endpoint);
|
||||||
self.handler = match (endpoint.0, endpoint.1, referer) {
|
let handler: Option<Box<Handler>> = match (endpoint.0, endpoint.1, referer) {
|
||||||
// Handle invalid web requests that we can recover from
|
// Handle invalid web requests that we can recover from
|
||||||
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
(ref path, SpecialEndpoint::None, Some((ref referer, ref referer_url)))
|
||||||
if referer.app_id == apps::WEB_PATH
|
if referer.app_id == apps::WEB_PATH
|
||||||
@ -100,26 +74,27 @@ impl<A: auth::Authorization + 'static> server::Handler<HttpStream> for Router<A>
|
|||||||
let len = cmp::min(referer_url.path.len(), 2); // /web/<encoded>/
|
let len = cmp::min(referer_url.path.len(), 2); // /web/<encoded>/
|
||||||
let base = referer_url.path[..len].join("/");
|
let base = referer_url.path[..len].join("/");
|
||||||
let requested = url.map(|u| u.path.join("/")).unwrap_or_default();
|
let requested = url.map(|u| u.path.join("/")).unwrap_or_default();
|
||||||
Redirection::boxed(&format!("/{}/{}", base, requested))
|
Some(Redirection::boxed(&format!("/{}/{}", base, requested)))
|
||||||
},
|
},
|
||||||
// First check special endpoints
|
// First check special endpoints
|
||||||
(ref path, ref endpoint, _) if self.special.contains_key(endpoint) => {
|
(ref path, ref endpoint, _) if self.special.contains_key(endpoint) => {
|
||||||
trace!(target: "dapps", "Resolving to special endpoint.");
|
trace!(target: "dapps", "Resolving to special endpoint.");
|
||||||
self.special.get(endpoint)
|
self.special.get(endpoint)
|
||||||
.expect("special known to contain key; qed")
|
.expect("special known to contain key; qed")
|
||||||
.to_async_handler(path.clone().unwrap_or_default(), control)
|
.as_ref()
|
||||||
|
.map(|special| special.to_async_handler(path.clone().unwrap_or_default(), control))
|
||||||
},
|
},
|
||||||
// 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) => {
|
||||||
trace!(target: "dapps", "Resolving to local/builtin dapp.");
|
trace!(target: "dapps", "Resolving to local/builtin dapp.");
|
||||||
self.endpoints.get(&path.app_id)
|
Some(self.endpoints.get(&path.app_id)
|
||||||
.expect("endpoints known to contain key; qed")
|
.expect("endpoints known to contain key; qed")
|
||||||
.to_async_handler(path.clone(), control)
|
.to_async_handler(path.clone(), control))
|
||||||
},
|
},
|
||||||
// Try to resolve and fetch the dapp
|
// Try to resolve and fetch the dapp
|
||||||
(Some(ref path), _, _) if self.fetch.contains(&path.app_id) => {
|
(Some(ref path), _, _) if self.fetch.contains(&path.app_id) => {
|
||||||
trace!(target: "dapps", "Resolving to fetchable content.");
|
trace!(target: "dapps", "Resolving to fetchable content.");
|
||||||
self.fetch.to_async_handler(path.clone(), control)
|
Some(self.fetch.to_async_handler(path.clone(), control))
|
||||||
},
|
},
|
||||||
// NOTE [todr] /home is redirected to home page since some users may have the redirection cached
|
// NOTE [todr] /home is redirected to home page since some users may have the redirection cached
|
||||||
// (in the past we used 301 instead of 302)
|
// (in the past we used 301 instead of 302)
|
||||||
@ -128,82 +103,61 @@ impl<A: auth::Authorization + 'static> server::Handler<HttpStream> for Router<A>
|
|||||||
// 404 for non-existent content
|
// 404 for non-existent content
|
||||||
(Some(ref path), _, _) if is_get_request && path.app_id != "home" => {
|
(Some(ref path), _, _) if is_get_request && path.app_id != "home" => {
|
||||||
trace!(target: "dapps", "Resolving to 404.");
|
trace!(target: "dapps", "Resolving to 404.");
|
||||||
Box::new(ContentHandler::error(
|
Some(Box::new(ContentHandler::error(
|
||||||
StatusCode::NotFound,
|
StatusCode::NotFound,
|
||||||
"404 Not Found",
|
"404 Not Found",
|
||||||
"Requested content was not found.",
|
"Requested content was not found.",
|
||||||
None,
|
None,
|
||||||
self.signer_address.clone(),
|
self.signer_address.clone(),
|
||||||
))
|
)))
|
||||||
},
|
},
|
||||||
// Redirect any other GET request to signer.
|
// Redirect any other GET request to signer.
|
||||||
_ if is_get_request => {
|
_ if is_get_request => {
|
||||||
if let Some(ref signer_address) = self.signer_address {
|
if let Some(ref signer_address) = self.signer_address {
|
||||||
trace!(target: "dapps", "Redirecting to signer interface.");
|
trace!(target: "dapps", "Redirecting to signer interface.");
|
||||||
Redirection::boxed(&format!("http://{}", address(signer_address)))
|
Some(Redirection::boxed(&format!("http://{}", address(signer_address))))
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "dapps", "Signer disabled, returning 404.");
|
trace!(target: "dapps", "Signer disabled, returning 404.");
|
||||||
Box::new(ContentHandler::error(
|
Some(Box::new(ContentHandler::error(
|
||||||
StatusCode::NotFound,
|
StatusCode::NotFound,
|
||||||
"404 Not Found",
|
"404 Not Found",
|
||||||
"Your homepage is not available when Trusted Signer is disabled.",
|
"Your homepage is not available when Trusted Signer is disabled.",
|
||||||
Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."),
|
Some("You can still access dapps by writing a correct address, though. Re-enable Signer to get your homepage back."),
|
||||||
self.signer_address.clone(),
|
self.signer_address.clone(),
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// RPC by default
|
// RPC by default
|
||||||
_ => {
|
_ => {
|
||||||
trace!(target: "dapps", "Resolving to RPC call.");
|
trace!(target: "dapps", "Resolving to RPC call.");
|
||||||
self.special.get(&SpecialEndpoint::Rpc)
|
None
|
||||||
.expect("RPC endpoint always stored; qed")
|
|
||||||
.to_async_handler(EndpointPath::default(), control)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delegate on_request to proper handler
|
match handler {
|
||||||
self.handler.on_request(req)
|
Some(handler) => http::RequestMiddlewareAction::Respond {
|
||||||
}
|
should_validate_hosts: !(is_utils || is_dapps_domain),
|
||||||
|
handler: handler,
|
||||||
/// This event occurs each time the `Request` is ready to be read from.
|
},
|
||||||
fn on_request_readable(&mut self, decoder: &mut Decoder<HttpStream>) -> Next {
|
None => http::RequestMiddlewareAction::Proceed {
|
||||||
self.handler.on_request_readable(decoder)
|
should_continue_on_invalid_cors: !is_origin_set,
|
||||||
}
|
},
|
||||||
|
}
|
||||||
/// This event occurs after the first time this handled signals `Next::write()`.
|
|
||||||
fn on_response(&mut self, response: &mut server::Response) -> Next {
|
|
||||||
self.handler.on_response(response)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// This event occurs each time the `Response` is ready to be written to.
|
|
||||||
fn on_response_writable(&mut self, encoder: &mut Encoder<HttpStream>) -> Next {
|
|
||||||
self.handler.on_response_writable(encoder)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: auth::Authorization> Router<A> {
|
impl<F> Router<F> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
control: Control,
|
|
||||||
signer_address: Option<(String, u16)>,
|
signer_address: Option<(String, u16)>,
|
||||||
content_fetcher: Arc<Fetcher>,
|
content_fetcher: F,
|
||||||
endpoints: Arc<Endpoints>,
|
endpoints: Endpoints,
|
||||||
special: Arc<HashMap<SpecialEndpoint, Box<Endpoint>>>,
|
special: HashMap<SpecialEndpoint, Option<Box<Endpoint>>>,
|
||||||
authorization: Arc<A>,
|
) -> Self {
|
||||||
allowed_hosts: Option<Vec<hosts::Host>>,
|
|
||||||
) -> Self {
|
|
||||||
|
|
||||||
let handler = special.get(&SpecialEndpoint::Utils)
|
|
||||||
.expect("Utils endpoint always stored; qed")
|
|
||||||
.to_handler(EndpointPath::default());
|
|
||||||
Router {
|
Router {
|
||||||
control: Some(control),
|
|
||||||
signer_address: signer_address,
|
signer_address: signer_address,
|
||||||
endpoints: endpoints,
|
endpoints: endpoints,
|
||||||
fetch: content_fetcher,
|
fetch: content_fetcher,
|
||||||
special: special,
|
special: special,
|
||||||
authorization: authorization,
|
|
||||||
allowed_hosts: allowed_hosts,
|
|
||||||
handler: handler,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,106 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
//! HTTP Authorization implementations
|
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use hyper::{server, net, header, status};
|
|
||||||
use endpoint::Handler;
|
|
||||||
use handlers::{AuthRequiredHandler, ContentHandler};
|
|
||||||
|
|
||||||
/// Authorization result
|
|
||||||
pub enum Authorized {
|
|
||||||
/// Authorization was successful.
|
|
||||||
Yes,
|
|
||||||
/// Unsuccessful authorization. Handler for further work is returned.
|
|
||||||
No(Box<Handler>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Authorization interface
|
|
||||||
pub trait Authorization : Send + Sync {
|
|
||||||
/// Checks if authorization is valid.
|
|
||||||
fn is_authorized(&self, req: &server::Request<net::HttpStream>)-> Authorized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HTTP Basic Authorization handler
|
|
||||||
pub struct HttpBasicAuth {
|
|
||||||
users: HashMap<String, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// No-authorization implementation (authorization disabled)
|
|
||||||
pub struct NoAuth;
|
|
||||||
|
|
||||||
impl Authorization for NoAuth {
|
|
||||||
fn is_authorized(&self, _req: &server::Request<net::HttpStream>)-> Authorized {
|
|
||||||
Authorized::Yes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Authorization for HttpBasicAuth {
|
|
||||||
fn is_authorized(&self, req: &server::Request<net::HttpStream>) -> Authorized {
|
|
||||||
let auth = self.check_auth(&req);
|
|
||||||
|
|
||||||
match auth {
|
|
||||||
Access::Denied => {
|
|
||||||
Authorized::No(Box::new(ContentHandler::error(
|
|
||||||
status::StatusCode::Unauthorized,
|
|
||||||
"Unauthorized",
|
|
||||||
"You need to provide valid credentials to access this page.",
|
|
||||||
None,
|
|
||||||
None,
|
|
||||||
)))
|
|
||||||
},
|
|
||||||
Access::AuthRequired => {
|
|
||||||
Authorized::No(Box::new(AuthRequiredHandler))
|
|
||||||
},
|
|
||||||
Access::Granted => {
|
|
||||||
Authorized::Yes
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum Access {
|
|
||||||
Granted,
|
|
||||||
Denied,
|
|
||||||
AuthRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HttpBasicAuth {
|
|
||||||
/// Creates `HttpBasicAuth` instance with only one user.
|
|
||||||
pub fn single_user(username: &str, password: &str) -> Self {
|
|
||||||
let mut users = HashMap::new();
|
|
||||||
users.insert(username.to_owned(), password.to_owned());
|
|
||||||
HttpBasicAuth {
|
|
||||||
users: users
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_authorized(&self, username: &str, password: &str) -> bool {
|
|
||||||
self.users.get(&username.to_owned()).map_or(false, |pass| pass == password)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn check_auth(&self, req: &server::Request<net::HttpStream>) -> Access {
|
|
||||||
match req.headers().get::<header::Authorization<header::Basic>>() {
|
|
||||||
Some(&header::Authorization(
|
|
||||||
header::Basic { ref username, password: Some(ref password) }
|
|
||||||
)) if self.is_authorized(username, password) => Access::Granted,
|
|
||||||
Some(_) => Access::Denied,
|
|
||||||
None => Access::AuthRequired,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,42 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
|
|
||||||
use apps::DAPPS_DOMAIN;
|
|
||||||
use hyper::{server, header, StatusCode};
|
|
||||||
use hyper::net::HttpStream;
|
|
||||||
|
|
||||||
use handlers::ContentHandler;
|
|
||||||
use jsonrpc_http_server;
|
|
||||||
use jsonrpc_server_utils::hosts;
|
|
||||||
|
|
||||||
pub fn is_valid(req: &server::Request<HttpStream>, allowed_hosts: &Option<Vec<hosts::Host>>) -> bool {
|
|
||||||
let header_valid = jsonrpc_http_server::is_host_allowed(req, allowed_hosts);
|
|
||||||
match (header_valid, req.headers().get::<header::Host>()) {
|
|
||||||
(true, _) => true,
|
|
||||||
(_, Some(host)) => host.hostname.ends_with(DAPPS_DOMAIN),
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn host_invalid_response() -> Box<server::Handler<HttpStream> + Send> {
|
|
||||||
Box::new(ContentHandler::error(StatusCode::Forbidden,
|
|
||||||
"Current Host Is Disallowed",
|
|
||||||
"You are trying to access your node using incorrect address.",
|
|
||||||
Some("Use allowed URL or specify different <code>hosts</code> CLI options."),
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
}
|
|
@ -66,14 +66,14 @@ impl<T: Middleware<Metadata>> Endpoint for RpcEndpoint<T> {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct NoopMiddleware;
|
struct NoopMiddleware;
|
||||||
impl http::RequestMiddleware for NoopMiddleware {
|
impl http::RequestMiddleware for NoopMiddleware {
|
||||||
fn on_request(&self, request: &http::hyper::server::Request<http::hyper::net::HttpStream>) -> http::RequestMiddlewareAction {
|
fn on_request(&self, request: &http::hyper::server::Request<http::hyper::net::HttpStream>, _control: &http::hyper::Control) -> http::RequestMiddlewareAction {
|
||||||
http::RequestMiddlewareAction::Proceed {
|
http::RequestMiddlewareAction::Proceed {
|
||||||
should_continue_on_invalid_cors: request.headers().get::<http::hyper::header::Origin>().is_none(),
|
should_continue_on_invalid_cors: request.headers().get::<http::hyper::header::Origin>().is_none(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MetadataExtractor;
|
pub struct MetadataExtractor;
|
||||||
impl HttpMetaExtractor<Metadata> for MetadataExtractor {
|
impl HttpMetaExtractor<Metadata> for MetadataExtractor {
|
||||||
fn read_metadata(&self, request: &http::hyper::server::Request<http::hyper::net::HttpStream>) -> Metadata {
|
fn read_metadata(&self, request: &http::hyper::server::Request<http::hyper::net::HttpStream>) -> Metadata {
|
||||||
let dapp_id = request.headers().get::<http::hyper::header::Origin>()
|
let dapp_id = request.headers().get::<http::hyper::header::Origin>()
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
// 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 tests::helpers::{serve, serve_with_registrar, serve_extra_cors, request, assert_security_headers};
|
use tests::helpers::{serve, serve_with_registrar, request, assert_security_headers};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_return_error() {
|
fn should_return_error() {
|
||||||
@ -195,26 +195,3 @@ fn should_return_signer_port_cors_headers_for_home_parity_with_port() {
|
|||||||
response.assert_status("HTTP/1.1 200 OK");
|
response.assert_status("HTTP/1.1 200 OK");
|
||||||
response.assert_header("Access-Control-Allow-Origin", "http://parity.web3.site:18180");
|
response.assert_header("Access-Control-Allow-Origin", "http://parity.web3.site:18180");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_return_extra_cors_headers() {
|
|
||||||
// given
|
|
||||||
let server = serve_extra_cors(Some(vec!["all".to_owned()]));
|
|
||||||
|
|
||||||
// when
|
|
||||||
let response = request(server,
|
|
||||||
"\
|
|
||||||
POST /api/ping HTTP/1.1\r\n\
|
|
||||||
Host: localhost:8080\r\n\
|
|
||||||
Origin: http://somedomain.io\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
\r\n\
|
|
||||||
{}
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
// then
|
|
||||||
response.assert_status("HTTP/1.1 200 OK");
|
|
||||||
response.assert_header("Access-Control-Allow-Origin", "http://somedomain.io");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
use tests::helpers::{serve_with_auth, request, assert_security_headers_for_embed};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_require_authorization() {
|
|
||||||
// given
|
|
||||||
let server = serve_with_auth("test", "test");
|
|
||||||
|
|
||||||
// when
|
|
||||||
let response = request(server,
|
|
||||||
"\
|
|
||||||
GET / HTTP/1.1\r\n\
|
|
||||||
Host: 127.0.0.1:8080\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
\r\n\
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(response.status, "HTTP/1.1 401 Unauthorized".to_owned());
|
|
||||||
assert_eq!(response.headers.get(0).unwrap(), "WWW-Authenticate: Basic realm=\"Parity\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_reject_on_invalid_auth() {
|
|
||||||
// given
|
|
||||||
let server = serve_with_auth("test", "test");
|
|
||||||
|
|
||||||
// when
|
|
||||||
let response = request(server,
|
|
||||||
"\
|
|
||||||
GET / HTTP/1.1\r\n\
|
|
||||||
Host: 127.0.0.1:8080\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l\r\n
|
|
||||||
\r\n\
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(response.status, "HTTP/1.1 401 Unauthorized".to_owned());
|
|
||||||
assert!(response.body.contains("Unauthorized"), response.body);
|
|
||||||
assert_eq!(response.headers_raw.contains("WWW-Authenticate"), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_allow_on_valid_auth() {
|
|
||||||
// given
|
|
||||||
let server = serve_with_auth("Aladdin", "OpenSesame");
|
|
||||||
|
|
||||||
// when
|
|
||||||
let response = request(server,
|
|
||||||
"\
|
|
||||||
GET /ui/ HTTP/1.1\r\n\
|
|
||||||
Host: 127.0.0.1:8080\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l\r\n
|
|
||||||
\r\n\
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
|
|
||||||
assert_security_headers_for_embed(&response.headers);
|
|
||||||
}
|
|
@ -16,18 +16,20 @@
|
|||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::str;
|
use std::str;
|
||||||
use std::ops::Deref;
|
use std::net::SocketAddr;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use env_logger::LogBuilder;
|
use env_logger::LogBuilder;
|
||||||
use ethcore_rpc::Metadata;
|
use jsonrpc_core::IoHandler;
|
||||||
use jsonrpc_core::MetaIoHandler;
|
use jsonrpc_http_server::{self as http, Host, DomainsValidation};
|
||||||
|
|
||||||
use ServerBuilder;
|
|
||||||
use Server;
|
|
||||||
use fetch::Fetch;
|
|
||||||
use devtools::http_client;
|
use devtools::http_client;
|
||||||
|
use hash_fetch::urlhint::ContractClient;
|
||||||
|
use fetch::{Fetch, Client as FetchClient};
|
||||||
use parity_reactor::{EventLoop, Remote};
|
use parity_reactor::{EventLoop, Remote};
|
||||||
|
|
||||||
|
use {Middleware, SyncStatus, WebProxyTokens};
|
||||||
|
|
||||||
mod registrar;
|
mod registrar;
|
||||||
mod fetch;
|
mod fetch;
|
||||||
|
|
||||||
@ -50,7 +52,7 @@ pub struct ServerLoop {
|
|||||||
pub event_loop: EventLoop,
|
pub event_loop: EventLoop,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for ServerLoop {
|
impl ::std::ops::Deref for ServerLoop {
|
||||||
type Target = Server;
|
type Target = Server;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
@ -58,7 +60,7 @@ impl Deref for ServerLoop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init_server<F, B>(process: F, io: MetaIoHandler<Metadata>, remote: Remote) -> (ServerLoop, Arc<FakeRegistrar>) where
|
pub fn init_server<F, B>(process: F, io: IoHandler, remote: Remote) -> (ServerLoop, Arc<FakeRegistrar>) where
|
||||||
F: FnOnce(ServerBuilder) -> ServerBuilder<B>,
|
F: FnOnce(ServerBuilder) -> ServerBuilder<B>,
|
||||||
B: Fetch,
|
B: Fetch,
|
||||||
{
|
{
|
||||||
@ -74,33 +76,15 @@ pub fn init_server<F, B>(process: F, io: MetaIoHandler<Metadata>, remote: Remote
|
|||||||
&dapps_path, registrar.clone(), remote,
|
&dapps_path, registrar.clone(), remote,
|
||||||
))
|
))
|
||||||
.signer_address(Some(("127.0.0.1".into(), SIGNER_PORT)))
|
.signer_address(Some(("127.0.0.1".into(), SIGNER_PORT)))
|
||||||
.start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io, event_loop.raw_remote()).unwrap();
|
.start_unsecured_http(&"127.0.0.1:0".parse().unwrap(), io).unwrap();
|
||||||
(
|
(
|
||||||
ServerLoop { server: server, event_loop: event_loop },
|
ServerLoop { server: server, event_loop: event_loop },
|
||||||
registrar,
|
registrar,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_with_auth(user: &str, pass: &str) -> ServerLoop {
|
pub fn serve_with_rpc(io: IoHandler) -> ServerLoop {
|
||||||
init_logger();
|
init_server(|builder| builder, io, Remote::new_sync()).0
|
||||||
let registrar = Arc::new(FakeRegistrar::new());
|
|
||||||
let mut dapps_path = env::temp_dir();
|
|
||||||
dapps_path.push("non-existent-dir-to-prevent-fs-files-from-loading");
|
|
||||||
|
|
||||||
let event_loop = EventLoop::spawn();
|
|
||||||
let io = MetaIoHandler::default();
|
|
||||||
let server = ServerBuilder::new(&dapps_path, registrar, event_loop.remote())
|
|
||||||
.signer_address(Some(("127.0.0.1".into(), SIGNER_PORT)))
|
|
||||||
.allowed_hosts(None.into())
|
|
||||||
.start_basic_auth_http(&"127.0.0.1:0".parse().unwrap(), user, pass, io, event_loop.raw_remote()).unwrap();
|
|
||||||
ServerLoop {
|
|
||||||
server: server,
|
|
||||||
event_loop: event_loop,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serve_with_rpc(io: MetaIoHandler<Metadata>) -> ServerLoop {
|
|
||||||
init_server(|builder| builder.allowed_hosts(None.into()), io, Remote::new_sync()).0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_hosts(hosts: Option<Vec<String>>) -> ServerLoop {
|
pub fn serve_hosts(hosts: Option<Vec<String>>) -> ServerLoop {
|
||||||
@ -108,20 +92,13 @@ pub fn serve_hosts(hosts: Option<Vec<String>>) -> ServerLoop {
|
|||||||
init_server(|builder| builder.allowed_hosts(hosts.into()), Default::default(), Remote::new_sync()).0
|
init_server(|builder| builder.allowed_hosts(hosts.into()), Default::default(), Remote::new_sync()).0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_extra_cors(extra_cors: Option<Vec<String>>) -> ServerLoop {
|
|
||||||
let extra_cors = extra_cors.map(|cors| cors.into_iter().map(Into::into).collect());
|
|
||||||
init_server(|builder| builder.allowed_hosts(None.into()).extra_cors_headers(extra_cors.into()), Default::default(), Remote::new_sync()).0
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn serve_with_registrar() -> (ServerLoop, Arc<FakeRegistrar>) {
|
pub fn serve_with_registrar() -> (ServerLoop, Arc<FakeRegistrar>) {
|
||||||
init_server(|builder| builder.allowed_hosts(None.into()), Default::default(), Remote::new_sync())
|
init_server(|builder| builder, Default::default(), Remote::new_sync())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve_with_registrar_and_sync() -> (ServerLoop, Arc<FakeRegistrar>) {
|
pub fn serve_with_registrar_and_sync() -> (ServerLoop, Arc<FakeRegistrar>) {
|
||||||
init_server(|builder| {
|
init_server(|builder| {
|
||||||
builder
|
builder.sync_status(Arc::new(|| true))
|
||||||
.sync_status(Arc::new(|| true))
|
|
||||||
.allowed_hosts(None.into())
|
|
||||||
}, Default::default(), Remote::new_sync())
|
}, Default::default(), Remote::new_sync())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +110,7 @@ pub fn serve_with_registrar_and_fetch_and_threads(multi_threaded: bool) -> (Serv
|
|||||||
let fetch = FakeFetch::default();
|
let fetch = FakeFetch::default();
|
||||||
let f = fetch.clone();
|
let f = fetch.clone();
|
||||||
let (server, reg) = init_server(move |builder| {
|
let (server, reg) = init_server(move |builder| {
|
||||||
builder.allowed_hosts(None.into()).fetch(f.clone())
|
builder.fetch(f.clone())
|
||||||
}, Default::default(), if multi_threaded { Remote::new_thread_per_future() } else { Remote::new_sync() });
|
}, Default::default(), if multi_threaded { Remote::new_thread_per_future() } else { Remote::new_sync() });
|
||||||
|
|
||||||
(server, fetch, reg)
|
(server, fetch, reg)
|
||||||
@ -144,7 +121,6 @@ pub fn serve_with_fetch(web_token: &'static str) -> (ServerLoop, FakeFetch) {
|
|||||||
let f = fetch.clone();
|
let f = fetch.clone();
|
||||||
let (server, _) = init_server(move |builder| {
|
let (server, _) = init_server(move |builder| {
|
||||||
builder
|
builder
|
||||||
.allowed_hosts(None.into())
|
|
||||||
.fetch(f.clone())
|
.fetch(f.clone())
|
||||||
.web_proxy_tokens(Arc::new(move |token| &token == web_token))
|
.web_proxy_tokens(Arc::new(move |token| &token == web_token))
|
||||||
}, Default::default(), Remote::new_sync());
|
}, Default::default(), Remote::new_sync());
|
||||||
@ -153,7 +129,7 @@ pub fn serve_with_fetch(web_token: &'static str) -> (ServerLoop, FakeFetch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn serve() -> ServerLoop {
|
pub fn serve() -> ServerLoop {
|
||||||
init_server(|builder| builder.allowed_hosts(None.into()), Default::default(), Remote::new_sync()).0
|
init_server(|builder| builder, Default::default(), Remote::new_sync()).0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(server: ServerLoop, request: &str) -> http_client::Response {
|
pub fn request(server: ServerLoop, request: &str) -> http_client::Response {
|
||||||
@ -166,3 +142,157 @@ pub fn assert_security_headers(headers: &[String]) {
|
|||||||
pub fn assert_security_headers_for_embed(headers: &[String]) {
|
pub fn assert_security_headers_for_embed(headers: &[String]) {
|
||||||
http_client::assert_security_headers_present(headers, Some(SIGNER_PORT))
|
http_client::assert_security_headers_present(headers, Some(SIGNER_PORT))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Webapps HTTP+RPC server build.
|
||||||
|
pub struct ServerBuilder<T: Fetch = FetchClient> {
|
||||||
|
dapps_path: PathBuf,
|
||||||
|
registrar: Arc<ContractClient>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
|
signer_address: Option<(String, u16)>,
|
||||||
|
allowed_hosts: DomainsValidation<Host>,
|
||||||
|
remote: Remote,
|
||||||
|
fetch: Option<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ServerBuilder {
|
||||||
|
/// Construct new dapps server
|
||||||
|
pub fn new<P: AsRef<Path>>(dapps_path: P, registrar: Arc<ContractClient>, remote: Remote) -> Self {
|
||||||
|
ServerBuilder {
|
||||||
|
dapps_path: dapps_path.as_ref().to_owned(),
|
||||||
|
registrar: registrar,
|
||||||
|
sync_status: Arc::new(|| false),
|
||||||
|
web_proxy_tokens: Arc::new(|_| false),
|
||||||
|
signer_address: None,
|
||||||
|
allowed_hosts: DomainsValidation::Disabled,
|
||||||
|
remote: remote,
|
||||||
|
fetch: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Fetch> ServerBuilder<T> {
|
||||||
|
/// Set a fetch client to use.
|
||||||
|
pub fn fetch<X: Fetch>(self, fetch: X) -> ServerBuilder<X> {
|
||||||
|
ServerBuilder {
|
||||||
|
dapps_path: self.dapps_path,
|
||||||
|
registrar: self.registrar,
|
||||||
|
sync_status: self.sync_status,
|
||||||
|
web_proxy_tokens: self.web_proxy_tokens,
|
||||||
|
signer_address: self.signer_address,
|
||||||
|
allowed_hosts: self.allowed_hosts,
|
||||||
|
remote: self.remote,
|
||||||
|
fetch: Some(fetch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change default sync status.
|
||||||
|
pub fn sync_status(mut self, status: Arc<SyncStatus>) -> Self {
|
||||||
|
self.sync_status = status;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change default web proxy tokens validator.
|
||||||
|
pub fn web_proxy_tokens(mut self, tokens: Arc<WebProxyTokens>) -> Self {
|
||||||
|
self.web_proxy_tokens = tokens;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change default signer port.
|
||||||
|
pub fn signer_address(mut self, signer_address: Option<(String, u16)>) -> Self {
|
||||||
|
self.signer_address = signer_address;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change allowed hosts.
|
||||||
|
/// `None` - All hosts are allowed
|
||||||
|
/// `Some(whitelist)` - Allow only whitelisted hosts (+ listen address)
|
||||||
|
pub fn allowed_hosts(mut self, allowed_hosts: DomainsValidation<Host>) -> Self {
|
||||||
|
self.allowed_hosts = allowed_hosts;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Asynchronously start server with no authentication,
|
||||||
|
/// returns result with `Server` handle on success or an error.
|
||||||
|
pub fn start_unsecured_http(self, addr: &SocketAddr, io: IoHandler) -> Result<Server, http::Error> {
|
||||||
|
let fetch = self.fetch_client();
|
||||||
|
Server::start_http(
|
||||||
|
addr,
|
||||||
|
io,
|
||||||
|
self.allowed_hosts,
|
||||||
|
self.signer_address,
|
||||||
|
self.dapps_path,
|
||||||
|
vec![],
|
||||||
|
self.registrar,
|
||||||
|
self.sync_status,
|
||||||
|
self.web_proxy_tokens,
|
||||||
|
self.remote,
|
||||||
|
fetch,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch_client(&self) -> T {
|
||||||
|
match self.fetch.clone() {
|
||||||
|
Some(fetch) => fetch,
|
||||||
|
None => T::new().unwrap(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Webapps HTTP server.
|
||||||
|
pub struct Server {
|
||||||
|
server: Option<http::Server>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Server {
|
||||||
|
fn start_http<F: Fetch>(
|
||||||
|
addr: &SocketAddr,
|
||||||
|
io: IoHandler,
|
||||||
|
allowed_hosts: DomainsValidation<Host>,
|
||||||
|
signer_address: Option<(String, u16)>,
|
||||||
|
dapps_path: PathBuf,
|
||||||
|
extra_dapps: Vec<PathBuf>,
|
||||||
|
registrar: Arc<ContractClient>,
|
||||||
|
sync_status: Arc<SyncStatus>,
|
||||||
|
web_proxy_tokens: Arc<WebProxyTokens>,
|
||||||
|
remote: Remote,
|
||||||
|
fetch: F,
|
||||||
|
) -> Result<Server, http::Error> {
|
||||||
|
let middleware = Middleware::new(
|
||||||
|
remote,
|
||||||
|
signer_address,
|
||||||
|
dapps_path,
|
||||||
|
extra_dapps,
|
||||||
|
registrar,
|
||||||
|
sync_status,
|
||||||
|
web_proxy_tokens,
|
||||||
|
fetch,
|
||||||
|
);
|
||||||
|
http::ServerBuilder::new(io)
|
||||||
|
.request_middleware(middleware)
|
||||||
|
.allowed_hosts(allowed_hosts)
|
||||||
|
.cors(http::DomainsValidation::Disabled)
|
||||||
|
.start_http(addr)
|
||||||
|
.map(|server| Server {
|
||||||
|
server: Some(server),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns address that this server is bound to.
|
||||||
|
pub fn addr(&self) -> &SocketAddr {
|
||||||
|
self.server.as_ref()
|
||||||
|
.expect("server is always Some at the start; it's consumed only when object is dropped; qed")
|
||||||
|
.addrs()
|
||||||
|
.first()
|
||||||
|
.expect("You cannot start the server without binding to at least one address; qed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Server {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.server.take().unwrap().close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
mod helpers;
|
mod helpers;
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod authorization;
|
|
||||||
mod fetch;
|
mod fetch;
|
||||||
mod redirection;
|
mod redirection;
|
||||||
mod rpc;
|
mod rpc;
|
||||||
|
@ -14,16 +14,14 @@
|
|||||||
// 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 futures::{future, Future};
|
use jsonrpc_core::{IoHandler, Value};
|
||||||
use ethcore_rpc::{Metadata, Origin};
|
|
||||||
use jsonrpc_core::{MetaIoHandler, Value};
|
|
||||||
|
|
||||||
use tests::helpers::{serve_with_rpc, request};
|
use tests::helpers::{serve_with_rpc, request};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_serve_rpc() {
|
fn should_serve_rpc() {
|
||||||
// given
|
// given
|
||||||
let mut io = MetaIoHandler::default();
|
let mut io = IoHandler::default();
|
||||||
io.add_method("rpc_test", |_| {
|
io.add_method("rpc_test", |_| {
|
||||||
Ok(Value::String("Hello World!".into()))
|
Ok(Value::String("Hello World!".into()))
|
||||||
});
|
});
|
||||||
@ -49,70 +47,3 @@ fn should_serve_rpc() {
|
|||||||
response.assert_status("HTTP/1.1 200 OK");
|
response.assert_status("HTTP/1.1 200 OK");
|
||||||
assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned());
|
assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_extract_metadata() {
|
|
||||||
// given
|
|
||||||
let mut io = MetaIoHandler::default();
|
|
||||||
io.add_method_with_meta("rpc_test", |_params, meta: Metadata| {
|
|
||||||
assert_eq!(meta.origin, Origin::Dapps("".into()));
|
|
||||||
assert_eq!(meta.dapp_id(), "".into());
|
|
||||||
future::ok(Value::String("Hello World!".into())).boxed()
|
|
||||||
});
|
|
||||||
let server = serve_with_rpc(io);
|
|
||||||
|
|
||||||
// when
|
|
||||||
let req = r#"{"jsonrpc":"2.0","id":1,"method":"rpc_test","params":[]}"#;
|
|
||||||
let response = request(server, &format!(
|
|
||||||
"\
|
|
||||||
POST /rpc/ HTTP/1.1\r\n\
|
|
||||||
Host: 127.0.0.1:8080\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
X-Parity-Origin: https://this.should.be.ignored\r\n\
|
|
||||||
Content-Type: application/json\r\n\
|
|
||||||
Content-Length: {}\r\n\
|
|
||||||
\r\n\
|
|
||||||
{}\r\n\
|
|
||||||
",
|
|
||||||
req.as_bytes().len(),
|
|
||||||
req,
|
|
||||||
));
|
|
||||||
|
|
||||||
// then
|
|
||||||
response.assert_status("HTTP/1.1 200 OK");
|
|
||||||
assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_extract_metadata_from_custom_header() {
|
|
||||||
// given
|
|
||||||
let mut io = MetaIoHandler::default();
|
|
||||||
io.add_method_with_meta("rpc_test", |_params, meta: Metadata| {
|
|
||||||
assert_eq!(meta.origin, Origin::Dapps("https://parity.io/".into()));
|
|
||||||
assert_eq!(meta.dapp_id(), "https://parity.io/".into());
|
|
||||||
future::ok(Value::String("Hello World!".into())).boxed()
|
|
||||||
});
|
|
||||||
let server = serve_with_rpc(io);
|
|
||||||
|
|
||||||
// when
|
|
||||||
let req = r#"{"jsonrpc":"2.0","id":1,"method":"rpc_test","params":[]}"#;
|
|
||||||
let response = request(server, &format!(
|
|
||||||
"\
|
|
||||||
POST /rpc/ HTTP/1.1\r\n\
|
|
||||||
Host: 127.0.0.1:8080\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
Origin: null\r\n\
|
|
||||||
X-Parity-Origin: https://parity.io/\r\n\
|
|
||||||
Content-Type: application/json\r\n\
|
|
||||||
Content-Length: {}\r\n\
|
|
||||||
\r\n\
|
|
||||||
{}\r\n\
|
|
||||||
",
|
|
||||||
req.as_bytes().len(),
|
|
||||||
req,
|
|
||||||
));
|
|
||||||
|
|
||||||
// then
|
|
||||||
response.assert_status("HTTP/1.1 200 OK");
|
|
||||||
assert_eq!(response.body, "31\n{\"jsonrpc\":\"2.0\",\"result\":\"Hello World!\",\"id\":1}\n\n0\n\n".to_owned());
|
|
||||||
}
|
|
||||||
|
@ -34,7 +34,7 @@ fn should_reject_invalid_host() {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assert_eq!(response.status, "HTTP/1.1 403 Forbidden".to_owned());
|
assert_eq!(response.status, "HTTP/1.1 403 Forbidden".to_owned());
|
||||||
assert!(response.body.contains("Current Host Is Disallowed"), response.body);
|
assert!(response.body.contains("Provided Host header is not whitelisted."), response.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -97,31 +97,3 @@ fn should_allow_parity_utils_even_on_invalid_domain() {
|
|||||||
// then
|
// then
|
||||||
assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
|
assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_not_return_cors_headers_for_rpc() {
|
|
||||||
// given
|
|
||||||
let server = serve_hosts(Some(vec!["localhost:8080".into()]));
|
|
||||||
|
|
||||||
// when
|
|
||||||
let response = request(server,
|
|
||||||
"\
|
|
||||||
POST /rpc HTTP/1.1\r\n\
|
|
||||||
Host: localhost:8080\r\n\
|
|
||||||
Origin: null\r\n\
|
|
||||||
Content-Type: application/json\r\n\
|
|
||||||
Connection: close\r\n\
|
|
||||||
\r\n\
|
|
||||||
{}
|
|
||||||
"
|
|
||||||
);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(response.status, "HTTP/1.1 200 OK".to_owned());
|
|
||||||
assert!(
|
|
||||||
!response.headers_raw.contains("Access-Control-Allow-Origin"),
|
|
||||||
"CORS headers were not expected: {:?}",
|
|
||||||
response.headers
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -92,12 +92,13 @@ pub enum URLHintResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// URLHint Contract interface
|
/// URLHint Contract interface
|
||||||
pub trait URLHint {
|
pub trait URLHint: Send + Sync {
|
||||||
/// Resolves given id to registrar entry.
|
/// Resolves given id to registrar entry.
|
||||||
fn resolve(&self, id: Bytes) -> Option<URLHintResult>;
|
fn resolve(&self, id: Bytes) -> Option<URLHintResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `URLHintContract` API
|
/// `URLHintContract` API
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct URLHintContract {
|
pub struct URLHintContract {
|
||||||
urlhint: Contract,
|
urlhint: Contract,
|
||||||
registrar: Contract,
|
registrar: Contract,
|
||||||
|
@ -32,12 +32,13 @@ use std::sync::Arc;
|
|||||||
use std::net::{SocketAddr, IpAddr};
|
use std::net::{SocketAddr, IpAddr};
|
||||||
use error::ServerError;
|
use error::ServerError;
|
||||||
use route::Out;
|
use route::Out;
|
||||||
use http::hyper::server::{Listening, Handler, Request, Response};
|
use http::hyper::server::{Handler, Request, Response};
|
||||||
use http::hyper::net::HttpStream;
|
use http::hyper::net::HttpStream;
|
||||||
use http::hyper::header::{self, Vary, ContentLength, ContentType};
|
use http::hyper::header::{self, Vary, ContentLength, ContentType};
|
||||||
use http::hyper::{Next, Encoder, Decoder, Method, RequestUri, StatusCode};
|
use http::hyper::{Next, Encoder, Decoder, Method, RequestUri, StatusCode};
|
||||||
use ethcore::client::BlockChainClient;
|
use ethcore::client::BlockChainClient;
|
||||||
|
|
||||||
|
pub use http::hyper::server::Listening;
|
||||||
pub use http::{AccessControlAllowOrigin, Host, DomainsValidation};
|
pub use http::{AccessControlAllowOrigin, Host, DomainsValidation};
|
||||||
|
|
||||||
/// Request/response handler
|
/// Request/response handler
|
||||||
|
@ -164,6 +164,8 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
||||||
flag_jsonrpc_hosts: String = "none",
|
flag_jsonrpc_hosts: String = "none",
|
||||||
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
||||||
|
flag_jsonrpc_threads: Option<usize> = None,
|
||||||
|
or |c: &Config| otry!(c.rpc).threads.map(Some),
|
||||||
|
|
||||||
// IPC
|
// IPC
|
||||||
flag_no_ipc: bool = false,
|
flag_no_ipc: bool = false,
|
||||||
@ -176,21 +178,8 @@ usage! {
|
|||||||
// DAPPS
|
// DAPPS
|
||||||
flag_no_dapps: bool = false,
|
flag_no_dapps: bool = false,
|
||||||
or |c: &Config| otry!(c.dapps).disable.clone(),
|
or |c: &Config| otry!(c.dapps).disable.clone(),
|
||||||
flag_dapps_port: u16 = 8080u16,
|
|
||||||
or |c: &Config| otry!(c.dapps).port.clone(),
|
|
||||||
flag_dapps_interface: String = "local",
|
|
||||||
or |c: &Config| otry!(c.dapps).interface.clone(),
|
|
||||||
flag_dapps_hosts: String = "none",
|
|
||||||
or |c: &Config| otry!(c.dapps).hosts.as_ref().map(|vec| vec.join(",")),
|
|
||||||
flag_dapps_cors: Option<String> = None,
|
|
||||||
or |c: &Config| otry!(c.dapps).cors.clone().map(Some),
|
|
||||||
flag_dapps_path: String = "$BASE/dapps",
|
flag_dapps_path: String = "$BASE/dapps",
|
||||||
or |c: &Config| otry!(c.dapps).path.clone(),
|
or |c: &Config| otry!(c.dapps).path.clone(),
|
||||||
flag_dapps_user: Option<String> = None,
|
|
||||||
or |c: &Config| otry!(c.dapps).user.clone().map(Some),
|
|
||||||
flag_dapps_pass: Option<String> = None,
|
|
||||||
or |c: &Config| otry!(c.dapps).pass.clone().map(Some),
|
|
||||||
flag_dapps_apis_all: bool = false, or |_| None,
|
|
||||||
|
|
||||||
// Secret Store
|
// Secret Store
|
||||||
flag_no_secretstore: bool = false,
|
flag_no_secretstore: bool = false,
|
||||||
@ -330,6 +319,22 @@ usage! {
|
|||||||
or |c: &Config| otry!(c.misc).log_file.clone().map(Some),
|
or |c: &Config| otry!(c.misc).log_file.clone().map(Some),
|
||||||
flag_no_color: bool = false,
|
flag_no_color: bool = false,
|
||||||
or |c: &Config| otry!(c.misc).color.map(|c| !c).clone(),
|
or |c: &Config| otry!(c.misc).color.map(|c| !c).clone(),
|
||||||
|
|
||||||
|
|
||||||
|
// -- Legacy Options supported in configs
|
||||||
|
flag_dapps_port: Option<u16> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).port.clone().map(Some),
|
||||||
|
flag_dapps_interface: Option<String> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).interface.clone().map(Some),
|
||||||
|
flag_dapps_hosts: Option<String> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).hosts.as_ref().map(|vec| Some(vec.join(","))),
|
||||||
|
flag_dapps_cors: Option<String> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).cors.clone().map(Some),
|
||||||
|
flag_dapps_user: Option<String> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).user.clone().map(Some),
|
||||||
|
flag_dapps_pass: Option<String> = None,
|
||||||
|
or |c: &Config| otry!(c.dapps).pass.clone().map(Some),
|
||||||
|
flag_dapps_apis_all: Option<bool> = None, or |_| None,
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Values with optional default value.
|
// Values with optional default value.
|
||||||
@ -419,6 +424,7 @@ struct Rpc {
|
|||||||
cors: Option<String>,
|
cors: Option<String>,
|
||||||
apis: Option<Vec<String>>,
|
apis: Option<Vec<String>>,
|
||||||
hosts: Option<Vec<String>>,
|
hosts: Option<Vec<String>>,
|
||||||
|
threads: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Debug, PartialEq, RustcDecodable)]
|
#[derive(Default, Debug, PartialEq, RustcDecodable)]
|
||||||
@ -672,6 +678,7 @@ mod tests {
|
|||||||
flag_jsonrpc_cors: Some("null".into()),
|
flag_jsonrpc_cors: Some("null".into()),
|
||||||
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc".into(),
|
flag_jsonrpc_apis: "web3,eth,net,parity,traces,rpc".into(),
|
||||||
flag_jsonrpc_hosts: "none".into(),
|
flag_jsonrpc_hosts: "none".into(),
|
||||||
|
flag_jsonrpc_threads: None,
|
||||||
|
|
||||||
// IPC
|
// IPC
|
||||||
flag_no_ipc: false,
|
flag_no_ipc: false,
|
||||||
@ -679,15 +686,8 @@ mod tests {
|
|||||||
flag_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc".into(),
|
flag_ipc_apis: "web3,eth,net,parity,parity_accounts,personal,traces,rpc".into(),
|
||||||
|
|
||||||
// DAPPS
|
// DAPPS
|
||||||
flag_no_dapps: false,
|
|
||||||
flag_dapps_port: 8080u16,
|
|
||||||
flag_dapps_interface: "local".into(),
|
|
||||||
flag_dapps_hosts: "none".into(),
|
|
||||||
flag_dapps_cors: None,
|
|
||||||
flag_dapps_path: "$HOME/.parity/dapps".into(),
|
flag_dapps_path: "$HOME/.parity/dapps".into(),
|
||||||
flag_dapps_user: Some("test_user".into()),
|
flag_no_dapps: false,
|
||||||
flag_dapps_pass: Some("test_pass".into()),
|
|
||||||
flag_dapps_apis_all: false,
|
|
||||||
|
|
||||||
flag_no_secretstore: false,
|
flag_no_secretstore: false,
|
||||||
flag_secretstore_port: 8082u16,
|
flag_secretstore_port: 8082u16,
|
||||||
@ -792,6 +792,14 @@ mod tests {
|
|||||||
flag_extradata: None,
|
flag_extradata: None,
|
||||||
flag_cache: None,
|
flag_cache: None,
|
||||||
flag_warp: Some(true),
|
flag_warp: Some(true),
|
||||||
|
// Legacy-Dapps
|
||||||
|
flag_dapps_port: Some(8080),
|
||||||
|
flag_dapps_interface: Some("local".into()),
|
||||||
|
flag_dapps_hosts: Some("none".into()),
|
||||||
|
flag_dapps_cors: None,
|
||||||
|
flag_dapps_user: Some("test_user".into()),
|
||||||
|
flag_dapps_pass: Some("test_pass".into()),
|
||||||
|
flag_dapps_apis_all: None,
|
||||||
|
|
||||||
// -- Miscellaneous Options
|
// -- Miscellaneous Options
|
||||||
flag_version: false,
|
flag_version: false,
|
||||||
@ -873,6 +881,7 @@ mod tests {
|
|||||||
cors: None,
|
cors: None,
|
||||||
apis: None,
|
apis: None,
|
||||||
hosts: None,
|
hosts: None,
|
||||||
|
threads: None,
|
||||||
}),
|
}),
|
||||||
ipc: Some(Ipc {
|
ipc: Some(Ipc {
|
||||||
disable: None,
|
disable: None,
|
||||||
|
@ -149,6 +149,8 @@ API and Console Options:
|
|||||||
is additional security against some attack
|
is additional security against some attack
|
||||||
vectors. Special options: "all", "none",
|
vectors. Special options: "all", "none",
|
||||||
(default: {flag_jsonrpc_hosts}).
|
(default: {flag_jsonrpc_hosts}).
|
||||||
|
--jsonrpc-threads THREADS Enables experimental faster implementation of JSON-RPC server.
|
||||||
|
Requires Dapps server to be disabled using --no-dapps. (default: {flag_jsonrpc_threads:?})
|
||||||
|
|
||||||
--no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc})
|
--no-ipc Disable JSON-RPC over IPC service. (default: {flag_no_ipc})
|
||||||
--ipc-path PATH Specify custom path for JSON-RPC over IPC service
|
--ipc-path PATH Specify custom path for JSON-RPC over IPC service
|
||||||
@ -157,29 +159,8 @@ API and Console Options:
|
|||||||
IPC (default: {flag_ipc_apis}).
|
IPC (default: {flag_ipc_apis}).
|
||||||
|
|
||||||
--no-dapps Disable the Dapps server (e.g. status page). (default: {flag_no_dapps})
|
--no-dapps Disable the Dapps server (e.g. status page). (default: {flag_no_dapps})
|
||||||
--dapps-port PORT Specify the port portion of the Dapps server
|
|
||||||
(default: {flag_dapps_port}).
|
|
||||||
--dapps-interface IP Specify the hostname portion of the Dapps
|
|
||||||
server, IP should be an interface's IP address,
|
|
||||||
or local (default: {flag_dapps_interface}).
|
|
||||||
--dapps-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: {flag_dapps_hosts}).
|
|
||||||
--dapps-cors URL Specify CORS headers for Dapps server APIs.
|
|
||||||
(default: {flag_dapps_cors:?})
|
|
||||||
--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
|
|
||||||
asked for password on startup. (default: {flag_dapps_user:?})
|
|
||||||
--dapps-pass PASSWORD Specify password for Dapps server. Use only in
|
|
||||||
conjunction with --dapps-user. (default: {flag_dapps_pass:?})
|
|
||||||
--dapps-path PATH Specify directory where dapps should be installed.
|
--dapps-path PATH Specify directory where dapps should be installed.
|
||||||
(default: {flag_dapps_path})
|
(default: {flag_dapps_path})
|
||||||
--dapps-apis-all Expose all possible RPC APIs on Dapps port.
|
|
||||||
WARNING: INSECURE. Used only for development.
|
|
||||||
(default: {flag_dapps_apis_all})
|
|
||||||
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
|
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
|
||||||
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
|
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
|
||||||
(default: {flag_ipfs_api_port})
|
(default: {flag_ipfs_api_port})
|
||||||
@ -392,6 +373,13 @@ Legacy Options:
|
|||||||
--jsonrpc-off Equivalent to --no-jsonrpc.
|
--jsonrpc-off Equivalent to --no-jsonrpc.
|
||||||
-w --webapp Does nothing; dapps server is on by default now.
|
-w --webapp Does nothing; dapps server is on by default now.
|
||||||
--dapps-off Equivalent to --no-dapps.
|
--dapps-off Equivalent to --no-dapps.
|
||||||
|
--dapps-user USERNAME Dapps server authentication has been removed. (default: {flag_dapps_user:?})
|
||||||
|
--dapps-pass PASSWORD Dapps server authentication has been removed. (default: {flag_dapps_pass:?})
|
||||||
|
--dapps-apis-all Dapps server is merged with RPC server. Use --jsonrpc-apis. (default: {flag_dapps_apis_all:?})
|
||||||
|
--dapps-cors URL Dapps server is merged with RPC server. Use --jsonrpc-cors. (default: {flag_dapps_cors:?})
|
||||||
|
--dapps-hosts HOSTS Dapps server is merged with RPC server. Use --jsonrpc-hosts. (default: {flag_dapps_hosts:?})
|
||||||
|
--dapps-interface IP Dapps server is merged with RPC server. Use --jsonrpc-interface. (default: {flag_dapps_interface:?})
|
||||||
|
--dapps-port PORT Dapps server is merged with RPC server. Use --jsonrpc-port. (default: {flag_dapps_port:?})
|
||||||
--rpc Does nothing; JSON-RPC is on by default now.
|
--rpc Does nothing; JSON-RPC is on by default now.
|
||||||
--warp Does nothing; Warp sync is on by default. (default: {flag_warp})
|
--warp Does nothing; Warp sync is on by default. (default: {flag_warp})
|
||||||
--rpcaddr IP Equivalent to --jsonrpc-interface IP.
|
--rpcaddr IP Equivalent to --jsonrpc-interface IP.
|
||||||
|
@ -132,12 +132,17 @@ impl Configuration {
|
|||||||
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
|
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
|
||||||
let geth_compatibility = self.args.flag_geth;
|
let geth_compatibility = self.args.flag_geth;
|
||||||
let ui_address = self.ui_port().map(|port| (self.ui_interface(), port));
|
let ui_address = self.ui_port().map(|port| (self.ui_interface(), port));
|
||||||
let dapps_conf = self.dapps_config();
|
let mut dapps_conf = self.dapps_config();
|
||||||
let ipfs_conf = self.ipfs_config();
|
let ipfs_conf = self.ipfs_config();
|
||||||
let signer_conf = self.signer_config();
|
let signer_conf = self.signer_config();
|
||||||
let secretstore_conf = self.secretstore_config();
|
let secretstore_conf = self.secretstore_config();
|
||||||
let format = self.format()?;
|
let format = self.format()?;
|
||||||
|
|
||||||
|
if self.args.flag_jsonrpc_threads.is_some() && dapps_conf.enabled {
|
||||||
|
dapps_conf.enabled = false;
|
||||||
|
writeln!(&mut stderr(), "Warning: Disabling Dapps server because fast RPC server was enabled.").expect("Error writing to stderr.")
|
||||||
|
}
|
||||||
|
|
||||||
let cmd = if self.args.flag_version {
|
let cmd = if self.args.flag_version {
|
||||||
Cmd::Version
|
Cmd::Version
|
||||||
} else if self.args.cmd_signer {
|
} else if self.args.cmd_signer {
|
||||||
@ -554,19 +559,12 @@ impl Configuration {
|
|||||||
fn dapps_config(&self) -> DappsConfiguration {
|
fn dapps_config(&self) -> DappsConfiguration {
|
||||||
DappsConfiguration {
|
DappsConfiguration {
|
||||||
enabled: self.dapps_enabled(),
|
enabled: self.dapps_enabled(),
|
||||||
interface: self.dapps_interface(),
|
|
||||||
port: self.args.flag_dapps_port,
|
|
||||||
hosts: self.dapps_hosts(),
|
|
||||||
cors: self.dapps_cors(),
|
|
||||||
user: self.args.flag_dapps_user.clone(),
|
|
||||||
pass: self.args.flag_dapps_pass.clone(),
|
|
||||||
dapps_path: PathBuf::from(self.directories().dapps),
|
dapps_path: PathBuf::from(self.directories().dapps),
|
||||||
extra_dapps: if self.args.cmd_dapp {
|
extra_dapps: if self.args.cmd_dapp {
|
||||||
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
|
self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect()
|
||||||
} else {
|
} else {
|
||||||
vec![]
|
vec![]
|
||||||
},
|
},
|
||||||
all_apis: self.args.flag_dapps_apis_all,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -746,14 +744,10 @@ impl Configuration {
|
|||||||
Self::cors(self.args.flag_ipfs_api_cors.as_ref())
|
Self::cors(self.args.flag_ipfs_api_cors.as_ref())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dapps_cors(&self) -> Option<Vec<String>> {
|
|
||||||
Self::cors(self.args.flag_dapps_cors.as_ref())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn hosts(hosts: &str) -> Option<Vec<String>> {
|
fn hosts(hosts: &str) -> Option<Vec<String>> {
|
||||||
match hosts {
|
match hosts {
|
||||||
"none" => return Some(Vec::new()),
|
"none" => return Some(Vec::new()),
|
||||||
"all" => return None,
|
"*" | "all" | "any" => return None,
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
let hosts = hosts.split(',').map(Into::into).collect();
|
let hosts = hosts.split(',').map(Into::into).collect();
|
||||||
@ -764,10 +758,6 @@ impl Configuration {
|
|||||||
Self::hosts(&self.args.flag_jsonrpc_hosts)
|
Self::hosts(&self.args.flag_jsonrpc_hosts)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dapps_hosts(&self) -> Option<Vec<String>> {
|
|
||||||
Self::hosts(&self.args.flag_dapps_hosts)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipfs_hosts(&self) -> Option<Vec<String>> {
|
fn ipfs_hosts(&self) -> Option<Vec<String>> {
|
||||||
Self::hosts(&self.args.flag_ipfs_api_hosts)
|
Self::hosts(&self.args.flag_ipfs_api_hosts)
|
||||||
}
|
}
|
||||||
@ -793,12 +783,17 @@ impl Configuration {
|
|||||||
|
|
||||||
fn http_config(&self) -> Result<HttpConfiguration, String> {
|
fn http_config(&self) -> Result<HttpConfiguration, String> {
|
||||||
let conf = HttpConfiguration {
|
let conf = HttpConfiguration {
|
||||||
enabled: !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc,
|
enabled: self.rpc_enabled(),
|
||||||
interface: self.rpc_interface(),
|
interface: self.rpc_interface(),
|
||||||
port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
||||||
apis: self.rpc_apis().parse()?,
|
apis: self.rpc_apis().parse()?,
|
||||||
hosts: self.rpc_hosts(),
|
hosts: self.rpc_hosts(),
|
||||||
cors: self.rpc_cors(),
|
cors: self.rpc_cors(),
|
||||||
|
threads: match self.args.flag_jsonrpc_threads {
|
||||||
|
Some(threads) if threads > 0 => Some(threads),
|
||||||
|
None => None,
|
||||||
|
_ => return Err("--jsonrpc-threads number needs to be positive.".into()),
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(conf)
|
Ok(conf)
|
||||||
@ -809,7 +804,7 @@ impl Configuration {
|
|||||||
name: self.args.flag_identity.clone(),
|
name: self.args.flag_identity.clone(),
|
||||||
chain: self.chain(),
|
chain: self.chain(),
|
||||||
network_port: self.args.flag_port,
|
network_port: self.args.flag_port,
|
||||||
rpc_enabled: !self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc,
|
rpc_enabled: self.rpc_enabled(),
|
||||||
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
|
rpc_interface: self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone()),
|
||||||
rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
rpc_port: self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port),
|
||||||
}
|
}
|
||||||
@ -916,13 +911,6 @@ impl Configuration {
|
|||||||
Self::interface(&self.network_settings().rpc_interface)
|
Self::interface(&self.network_settings().rpc_interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dapps_interface(&self) -> String {
|
|
||||||
match self.args.flag_dapps_interface.as_str() {
|
|
||||||
"local" => "127.0.0.1",
|
|
||||||
x => x,
|
|
||||||
}.into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipfs_interface(&self) -> String {
|
fn ipfs_interface(&self) -> String {
|
||||||
Self::interface(&self.args.flag_ipfs_api_interface)
|
Self::interface(&self.args.flag_ipfs_api_interface)
|
||||||
}
|
}
|
||||||
@ -938,8 +926,12 @@ impl Configuration {
|
|||||||
Self::interface(&self.args.flag_stratum_interface)
|
Self::interface(&self.args.flag_stratum_interface)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rpc_enabled(&self) -> bool {
|
||||||
|
!self.args.flag_jsonrpc_off && !self.args.flag_no_jsonrpc
|
||||||
|
}
|
||||||
|
|
||||||
fn dapps_enabled(&self) -> bool {
|
fn dapps_enabled(&self) -> bool {
|
||||||
!self.args.flag_dapps_off && !self.args.flag_no_dapps && cfg!(feature = "dapps")
|
!self.args.flag_dapps_off && !self.args.flag_no_dapps && self.rpc_enabled() && cfg!(feature = "dapps")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn secretstore_enabled(&self) -> bool {
|
fn secretstore_enabled(&self) -> bool {
|
||||||
@ -1317,23 +1309,6 @@ mod tests {
|
|||||||
assert_eq!(conf3.rpc_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
|
assert_eq!(conf3.rpc_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_parse_dapps_hosts() {
|
|
||||||
// given
|
|
||||||
|
|
||||||
// when
|
|
||||||
let conf0 = parse(&["parity"]);
|
|
||||||
let conf1 = parse(&["parity", "--dapps-hosts", "none"]);
|
|
||||||
let conf2 = parse(&["parity", "--dapps-hosts", "all"]);
|
|
||||||
let conf3 = parse(&["parity", "--dapps-hosts", "ethcore.io,something.io"]);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assert_eq!(conf0.dapps_hosts(), Some(Vec::new()));
|
|
||||||
assert_eq!(conf1.dapps_hosts(), Some(Vec::new()));
|
|
||||||
assert_eq!(conf2.dapps_hosts(), None);
|
|
||||||
assert_eq!(conf3.dapps_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_ipfs_hosts() {
|
fn should_parse_ipfs_hosts() {
|
||||||
// given
|
// given
|
||||||
|
149
parity/dapps.rs
149
parity/dapps.rs
@ -19,25 +19,17 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use dir::default_data_path;
|
use dir::default_data_path;
|
||||||
use ethcore::client::Client;
|
use ethcore::client::Client;
|
||||||
use ethcore_rpc::informant::RpcStats;
|
|
||||||
use ethsync::SyncProvider;
|
use ethsync::SyncProvider;
|
||||||
use hash_fetch::fetch::Client as FetchClient;
|
use hash_fetch::fetch::Client as FetchClient;
|
||||||
use helpers::replace_home;
|
use helpers::replace_home;
|
||||||
use rpc_apis::{self, SignerService};
|
use rpc_apis::SignerService;
|
||||||
use parity_reactor;
|
use parity_reactor;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub interface: String,
|
|
||||||
pub port: u16,
|
|
||||||
pub hosts: Option<Vec<String>>,
|
|
||||||
pub cors: Option<Vec<String>>,
|
|
||||||
pub user: Option<String>,
|
|
||||||
pub pass: Option<String>,
|
|
||||||
pub dapps_path: PathBuf,
|
pub dapps_path: PathBuf,
|
||||||
pub extra_dapps: Vec<PathBuf>,
|
pub extra_dapps: Vec<PathBuf>,
|
||||||
pub all_apis: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Configuration {
|
impl Default for Configuration {
|
||||||
@ -45,80 +37,56 @@ impl Default for Configuration {
|
|||||||
let data_dir = default_data_path();
|
let data_dir = default_data_path();
|
||||||
Configuration {
|
Configuration {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
interface: "127.0.0.1".into(),
|
|
||||||
port: 8080,
|
|
||||||
hosts: Some(Vec::new()),
|
|
||||||
cors: None,
|
|
||||||
user: None,
|
|
||||||
pass: None,
|
|
||||||
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
dapps_path: replace_home(&data_dir, "$BASE/dapps").into(),
|
||||||
extra_dapps: vec![],
|
extra_dapps: vec![],
|
||||||
all_apis: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Dependencies {
|
pub struct Dependencies {
|
||||||
pub apis: Arc<rpc_apis::Dependencies>,
|
|
||||||
pub client: Arc<Client>,
|
pub client: Arc<Client>,
|
||||||
pub sync: Arc<SyncProvider>,
|
pub sync: Arc<SyncProvider>,
|
||||||
pub remote: parity_reactor::TokioRemote,
|
pub remote: parity_reactor::TokioRemote,
|
||||||
pub fetch: FetchClient,
|
pub fetch: FetchClient,
|
||||||
pub signer: Arc<SignerService>,
|
pub signer: Arc<SignerService>,
|
||||||
pub stats: Arc<RpcStats>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<WebappServer>, String> {
|
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Middleware>, String> {
|
||||||
if !configuration.enabled {
|
if !configuration.enabled {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = format!("{}:{}", configuration.interface, configuration.port);
|
dapps_middleware(
|
||||||
let addr = url.parse().map_err(|_| format!("Invalid Webapps listen host/port given: {}", url))?;
|
|
||||||
|
|
||||||
let auth = configuration.user.as_ref().map(|username| {
|
|
||||||
let password = configuration.pass.as_ref().map_or_else(|| {
|
|
||||||
use rpassword::read_password;
|
|
||||||
println!("Type password for WebApps server (user: {}): ", username);
|
|
||||||
let pass = read_password().unwrap();
|
|
||||||
println!("OK, got it. Starting server...");
|
|
||||||
pass
|
|
||||||
}, |pass| pass.to_owned());
|
|
||||||
(username.to_owned(), password)
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(Some(setup_dapps_server(
|
|
||||||
deps,
|
deps,
|
||||||
configuration.dapps_path,
|
configuration.dapps_path,
|
||||||
configuration.extra_dapps,
|
configuration.extra_dapps,
|
||||||
&addr,
|
).map(Some)
|
||||||
configuration.hosts,
|
|
||||||
configuration.cors,
|
|
||||||
auth,
|
|
||||||
configuration.all_apis,
|
|
||||||
)?))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use self::server::WebappServer;
|
pub use self::server::Middleware;
|
||||||
pub use self::server::setup_dapps_server;
|
pub use self::server::dapps_middleware;
|
||||||
|
|
||||||
#[cfg(not(feature = "dapps"))]
|
#[cfg(not(feature = "dapps"))]
|
||||||
mod server {
|
mod server {
|
||||||
use super::Dependencies;
|
use super::Dependencies;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use ethcore_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction};
|
||||||
|
|
||||||
pub struct WebappServer;
|
pub struct Middleware;
|
||||||
pub fn setup_dapps_server(
|
|
||||||
|
impl RequestMiddleware for Middleware {
|
||||||
|
fn on_request(
|
||||||
|
&self, req: &hyper::server::Request<hyper::net::HttpStream>, control: &hyper::Control
|
||||||
|
) -> RequestMiddlewareAction {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dapps_middleware(
|
||||||
_deps: Dependencies,
|
_deps: Dependencies,
|
||||||
_dapps_path: PathBuf,
|
_dapps_path: PathBuf,
|
||||||
_extra_dapps: Vec<PathBuf>,
|
_extra_dapps: Vec<PathBuf>,
|
||||||
_url: &SocketAddr,
|
) -> Result<Middleware, String> {
|
||||||
_allowed_hosts: Option<Vec<String>>,
|
|
||||||
_cors: Option<Vec<String>>,
|
|
||||||
_auth: Option<(String, String)>,
|
|
||||||
_all_apis: bool,
|
|
||||||
) -> Result<WebappServer, String> {
|
|
||||||
Err("Your Parity version has been compiled without WebApps support.".into())
|
Err("Your Parity version has been compiled without WebApps support.".into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -128,78 +96,41 @@ mod server {
|
|||||||
use super::Dependencies;
|
use super::Dependencies;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::io;
|
|
||||||
use util::{Bytes, Address, U256};
|
use util::{Bytes, Address, U256};
|
||||||
|
|
||||||
use ansi_term::Colour;
|
|
||||||
use ethcore::transaction::{Transaction, Action};
|
use ethcore::transaction::{Transaction, Action};
|
||||||
use ethcore::client::{Client, BlockChainClient, BlockId};
|
use ethcore::client::{Client, BlockChainClient, BlockId};
|
||||||
use ethcore_dapps::{AccessControlAllowOrigin, Host};
|
|
||||||
use ethcore_rpc::is_major_importing;
|
use ethcore_rpc::is_major_importing;
|
||||||
|
use hash_fetch::fetch::Client as FetchClient;
|
||||||
use hash_fetch::urlhint::ContractClient;
|
use hash_fetch::urlhint::ContractClient;
|
||||||
|
use parity_dapps;
|
||||||
use parity_reactor;
|
use parity_reactor;
|
||||||
use rpc_apis;
|
|
||||||
|
|
||||||
pub use ethcore_dapps::Server as WebappServer;
|
pub type Middleware = parity_dapps::Middleware<FetchClient>;
|
||||||
|
|
||||||
pub fn setup_dapps_server(
|
pub fn dapps_middleware(
|
||||||
deps: Dependencies,
|
deps: Dependencies,
|
||||||
dapps_path: PathBuf,
|
dapps_path: PathBuf,
|
||||||
extra_dapps: Vec<PathBuf>,
|
extra_dapps: Vec<PathBuf>,
|
||||||
url: &SocketAddr,
|
) -> Result<Middleware, String> {
|
||||||
allowed_hosts: Option<Vec<String>>,
|
let sync = deps.sync;
|
||||||
cors: Option<Vec<String>>,
|
|
||||||
auth: Option<(String, String)>,
|
|
||||||
all_apis: bool,
|
|
||||||
) -> Result<WebappServer, String> {
|
|
||||||
use ethcore_dapps as dapps;
|
|
||||||
|
|
||||||
let server = dapps::ServerBuilder::new(
|
|
||||||
&dapps_path,
|
|
||||||
Arc::new(Registrar { client: deps.client.clone() }),
|
|
||||||
parity_reactor::Remote::new(deps.remote.clone()),
|
|
||||||
);
|
|
||||||
let allowed_hosts: Option<Vec<_>> = allowed_hosts.map(|hosts| hosts.into_iter().map(Host::from).collect());
|
|
||||||
let cors: Option<Vec<_>> = cors.map(|cors| cors.into_iter().map(AccessControlAllowOrigin::from).collect());
|
|
||||||
|
|
||||||
let sync = deps.sync.clone();
|
|
||||||
let client = deps.client.clone();
|
|
||||||
let signer = deps.signer.clone();
|
let signer = deps.signer.clone();
|
||||||
let server = server
|
let client = deps.client;
|
||||||
.fetch(deps.fetch.clone())
|
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
|
||||||
.sync_status(Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())))
|
let registrar = Arc::new(Registrar { client: client.clone() });
|
||||||
.web_proxy_tokens(Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token)))
|
let sync_status = Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info()));
|
||||||
.extra_dapps(&extra_dapps)
|
let web_proxy_tokens = Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token));
|
||||||
.signer_address(deps.signer.address())
|
|
||||||
.allowed_hosts(allowed_hosts.into())
|
|
||||||
.extra_cors_headers(cors.into());
|
|
||||||
|
|
||||||
let api_set = if all_apis {
|
Ok(parity_dapps::Middleware::new(
|
||||||
warn!("{}", Colour::Red.bold().paint("*** INSECURE *** Running Dapps with all APIs exposed."));
|
parity_remote,
|
||||||
info!("If you do not intend this, exit now.");
|
deps.signer.address(),
|
||||||
rpc_apis::ApiSet::SafeContext
|
dapps_path,
|
||||||
} else {
|
extra_dapps,
|
||||||
rpc_apis::ApiSet::UnsafeContext
|
registrar,
|
||||||
};
|
sync_status,
|
||||||
let apis = rpc_apis::setup_rpc(deps.stats, deps.apis.clone(), api_set);
|
web_proxy_tokens,
|
||||||
let start_result = match auth {
|
deps.fetch.clone(),
|
||||||
None => {
|
))
|
||||||
server.start_unsecured_http(url, apis, deps.remote)
|
|
||||||
},
|
|
||||||
Some((username, password)) => {
|
|
||||||
server.start_basic_auth_http(url, &username, &password, apis, deps.remote)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
match start_result {
|
|
||||||
Err(dapps::ServerError::IoError(err)) => match err.kind() {
|
|
||||||
io::ErrorKind::AddrInUse => Err(format!("WebApps address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --dapps-port and --dapps-interface options.", url)),
|
|
||||||
_ => Err(format!("WebApps io error: {}", err)),
|
|
||||||
},
|
|
||||||
Err(e) => Err(format!("WebApps error: {:?}", e)),
|
|
||||||
Ok(server) => Ok(server),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Registrar {
|
struct Registrar {
|
||||||
|
@ -21,94 +21,89 @@ use cli::Args;
|
|||||||
pub enum Deprecated {
|
pub enum Deprecated {
|
||||||
DoesNothing(&'static str),
|
DoesNothing(&'static str),
|
||||||
Replaced(&'static str, &'static str),
|
Replaced(&'static str, &'static str),
|
||||||
|
Removed(&'static str),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Deprecated {
|
impl fmt::Display for Deprecated {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
match *self {
|
match *self {
|
||||||
Deprecated::DoesNothing(s) => write!(f, "Option '{}' does nothing. It's on by default", s),
|
Deprecated::DoesNothing(s) => write!(f, "Option '{}' does nothing. It's on by default.", s),
|
||||||
Deprecated::Replaced(old, new) => write!(f, "Option '{}' is deprecated. Please use '{}' instead", old, new),
|
Deprecated::Replaced(old, new) => write!(f, "Option '{}' is deprecated. Please use '{}' instead.", old, new),
|
||||||
|
Deprecated::Removed(s) => write!(f, "Option '{}' has been removed and is no longer supported.", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Deprecated {
|
|
||||||
fn jsonrpc() -> Self {
|
|
||||||
Deprecated::DoesNothing("--jsonrpc")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rpc() -> Self {
|
|
||||||
Deprecated::DoesNothing("--rpc")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn jsonrpc_off() -> Self {
|
|
||||||
Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn webapp() -> Self {
|
|
||||||
Deprecated::DoesNothing("--webapp")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dapps_off() -> Self {
|
|
||||||
Deprecated::Replaced("--dapps-off", "--no-dapps")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipcdisable() -> Self {
|
|
||||||
Deprecated::Replaced("--ipcdisable", "--no-ipc")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ipc_off() -> Self {
|
|
||||||
Deprecated::Replaced("--ipc-off", "--no-ipc")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn etherbase() -> Self {
|
|
||||||
Deprecated::Replaced("--etherbase", "--author")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn extradata() -> Self {
|
|
||||||
Deprecated::Replaced("--extradata", "--extra-data")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
|
pub fn find_deprecated(args: &Args) -> Vec<Deprecated> {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|
||||||
if args.flag_jsonrpc {
|
if args.flag_jsonrpc {
|
||||||
result.push(Deprecated::jsonrpc());
|
result.push(Deprecated::DoesNothing("--jsonrpc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_rpc {
|
if args.flag_rpc {
|
||||||
result.push(Deprecated::rpc());
|
result.push(Deprecated::DoesNothing("--rpc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_jsonrpc_off {
|
if args.flag_jsonrpc_off {
|
||||||
result.push(Deprecated::jsonrpc_off());
|
result.push(Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_webapp {
|
if args.flag_webapp {
|
||||||
result.push(Deprecated::webapp())
|
result.push(Deprecated::DoesNothing("--webapp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_dapps_off {
|
if args.flag_dapps_off {
|
||||||
result.push(Deprecated::dapps_off());
|
result.push(Deprecated::Replaced("--dapps-off", "--no-dapps"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_ipcdisable {
|
if args.flag_ipcdisable {
|
||||||
result.push(Deprecated::ipcdisable());
|
result.push(Deprecated::Replaced("--ipcdisable", "--no-ipc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_ipc_off {
|
if args.flag_ipc_off {
|
||||||
result.push(Deprecated::ipc_off());
|
result.push(Deprecated::Replaced("--ipc-off", "--no-ipc"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_etherbase.is_some() {
|
if args.flag_etherbase.is_some() {
|
||||||
result.push(Deprecated::etherbase());
|
result.push(Deprecated::Replaced("--etherbase", "--author"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.flag_extradata.is_some() {
|
if args.flag_extradata.is_some() {
|
||||||
result.push(Deprecated::extradata());
|
result.push(Deprecated::Replaced("--extradata", "--extra-data"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Removed in 1.7
|
||||||
|
if args.flag_dapps_port.is_some() {
|
||||||
|
result.push(Deprecated::Replaced("--dapps-port", "--jsonrpc-port"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_interface.is_some() {
|
||||||
|
result.push(Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_hosts.is_some() {
|
||||||
|
result.push(Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_cors.is_some() {
|
||||||
|
result.push(Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_user.is_some() {
|
||||||
|
result.push(Deprecated::Removed("--dapps-user"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_pass.is_some() {
|
||||||
|
result.push(Deprecated::Removed("--dapps-pass"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.flag_dapps_apis_all.is_some() {
|
||||||
|
result.push(Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Removed in 1.8
|
||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,17 +126,31 @@ mod tests {
|
|||||||
args.flag_ipc_off = true;
|
args.flag_ipc_off = true;
|
||||||
args.flag_etherbase = Some(Default::default());
|
args.flag_etherbase = Some(Default::default());
|
||||||
args.flag_extradata = Some(Default::default());
|
args.flag_extradata = Some(Default::default());
|
||||||
|
args.flag_dapps_port = Some(Default::default());
|
||||||
|
args.flag_dapps_interface = Some(Default::default());
|
||||||
|
args.flag_dapps_hosts = Some(Default::default());
|
||||||
|
args.flag_dapps_cors = Some(Default::default());
|
||||||
|
args.flag_dapps_user = Some(Default::default());
|
||||||
|
args.flag_dapps_pass = Some(Default::default());
|
||||||
|
args.flag_dapps_apis_all = Some(Default::default());
|
||||||
args
|
args
|
||||||
}), vec![
|
}), vec![
|
||||||
Deprecated::jsonrpc(),
|
Deprecated::DoesNothing("--jsonrpc"),
|
||||||
Deprecated::rpc(),
|
Deprecated::DoesNothing("--rpc"),
|
||||||
Deprecated::jsonrpc_off(),
|
Deprecated::Replaced("--jsonrpc-off", "--no-jsonrpc"),
|
||||||
Deprecated::webapp(),
|
Deprecated::DoesNothing("--webapp"),
|
||||||
Deprecated::dapps_off(),
|
Deprecated::Replaced("--dapps-off", "--no-dapps"),
|
||||||
Deprecated::ipcdisable(),
|
Deprecated::Replaced("--ipcdisable", "--no-ipc"),
|
||||||
Deprecated::ipc_off(),
|
Deprecated::Replaced("--ipc-off", "--no-ipc"),
|
||||||
Deprecated::etherbase(),
|
Deprecated::Replaced("--etherbase", "--author"),
|
||||||
Deprecated::extradata(),
|
Deprecated::Replaced("--extradata", "--extra-data"),
|
||||||
|
Deprecated::Replaced("--dapps-port", "--jsonrpc-port"),
|
||||||
|
Deprecated::Replaced("--dapps-interface", "--jsonrpc-interface"),
|
||||||
|
Deprecated::Replaced("--dapps-hosts", "--jsonrpc-hosts"),
|
||||||
|
Deprecated::Replaced("--dapps-cors", "--jsonrpc-cors"),
|
||||||
|
Deprecated::Removed("--dapps-user"),
|
||||||
|
Deprecated::Removed("--dapps-pass"),
|
||||||
|
Deprecated::Replaced("--dapps-apis-all", "--jsonrpc-apis"),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,10 +15,9 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use parity_ipfs_api::{self, AccessControlAllowOrigin, Host};
|
use parity_ipfs_api::{self, AccessControlAllowOrigin, Host, Listening};
|
||||||
use parity_ipfs_api::error::ServerError;
|
use parity_ipfs_api::error::ServerError;
|
||||||
use ethcore::client::BlockChainClient;
|
use ethcore::client::BlockChainClient;
|
||||||
use hyper::server::Listening;
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub struct Configuration {
|
pub struct Configuration {
|
||||||
|
@ -28,7 +28,6 @@ extern crate ctrlc;
|
|||||||
extern crate docopt;
|
extern crate docopt;
|
||||||
extern crate env_logger;
|
extern crate env_logger;
|
||||||
extern crate fdlimit;
|
extern crate fdlimit;
|
||||||
extern crate hyper;
|
|
||||||
extern crate isatty;
|
extern crate isatty;
|
||||||
extern crate jsonrpc_core;
|
extern crate jsonrpc_core;
|
||||||
extern crate num_cpus;
|
extern crate num_cpus;
|
||||||
@ -73,7 +72,11 @@ extern crate ethcore_stratum;
|
|||||||
extern crate ethcore_secretstore;
|
extern crate ethcore_secretstore;
|
||||||
|
|
||||||
#[cfg(feature = "dapps")]
|
#[cfg(feature = "dapps")]
|
||||||
extern crate ethcore_dapps;
|
extern crate parity_dapps;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[macro_use]
|
||||||
|
extern crate pretty_assertions;
|
||||||
|
|
||||||
#[cfg(windows)] extern crate ws2_32;
|
#[cfg(windows)] extern crate ws2_32;
|
||||||
#[cfg(windows)] extern crate winapi;
|
#[cfg(windows)] extern crate winapi;
|
||||||
|
133
parity/rpc.rs
133
parity/rpc.rs
@ -14,24 +14,21 @@
|
|||||||
// 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 std::fmt;
|
use std::{io, fmt};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::net::SocketAddr;
|
|
||||||
use std::io;
|
|
||||||
|
|
||||||
|
use dapps;
|
||||||
use dir::default_data_path;
|
use dir::default_data_path;
|
||||||
use ethcore_rpc::{self as rpc, HttpServerError, Metadata, Origin, AccessControlAllowOrigin, Host};
|
|
||||||
use ethcore_rpc::informant::{RpcStats, Middleware};
|
use ethcore_rpc::informant::{RpcStats, Middleware};
|
||||||
|
use ethcore_rpc::{self as rpc, HttpServerError, Metadata, Origin, AccessControlAllowOrigin, Host};
|
||||||
use helpers::parity_ipc_path;
|
use helpers::parity_ipc_path;
|
||||||
use hyper;
|
|
||||||
use jsonrpc_core::MetaIoHandler;
|
use jsonrpc_core::MetaIoHandler;
|
||||||
use rpc_apis;
|
|
||||||
use rpc_apis::ApiSet;
|
|
||||||
use parity_reactor::TokioRemote;
|
use parity_reactor::TokioRemote;
|
||||||
|
use rpc_apis::{self, ApiSet};
|
||||||
|
|
||||||
pub use ethcore_rpc::{IpcServer, HttpServer};
|
pub use ethcore_rpc::{IpcServer, HttpServer, RequestMiddleware};
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct HttpConfiguration {
|
pub struct HttpConfiguration {
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
pub interface: String,
|
pub interface: String,
|
||||||
@ -39,6 +36,7 @@ pub struct HttpConfiguration {
|
|||||||
pub apis: ApiSet,
|
pub apis: ApiSet,
|
||||||
pub cors: Option<Vec<String>>,
|
pub cors: Option<Vec<String>>,
|
||||||
pub hosts: Option<Vec<String>>,
|
pub hosts: Option<Vec<String>>,
|
||||||
|
pub threads: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for HttpConfiguration {
|
impl Default for HttpConfiguration {
|
||||||
@ -50,6 +48,7 @@ impl Default for HttpConfiguration {
|
|||||||
apis: ApiSet::UnsafeContext,
|
apis: ApiSet::UnsafeContext,
|
||||||
cors: None,
|
cors: None,
|
||||||
hosts: Some(Vec::new()),
|
hosts: Some(Vec::new()),
|
||||||
|
threads: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,13 +88,17 @@ pub struct Dependencies {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct RpcExtractor;
|
pub struct RpcExtractor;
|
||||||
impl rpc::HttpMetaExtractor<Metadata> for RpcExtractor {
|
impl rpc::HttpMetaExtractor for RpcExtractor {
|
||||||
fn read_metadata(&self, req: &hyper::server::Request<hyper::net::HttpStream>) -> Metadata {
|
type Metadata = Metadata;
|
||||||
let origin = req.headers().get::<hyper::header::Origin>()
|
|
||||||
.map(|origin| format!("{}://{}", origin.scheme, origin.host))
|
fn read_metadata(&self, origin: String, dapps_origin: Option<String>) -> Metadata {
|
||||||
.unwrap_or_else(|| "unknown".into());
|
|
||||||
let mut metadata = Metadata::default();
|
let mut metadata = Metadata::default();
|
||||||
metadata.origin = Origin::Rpc(origin);
|
|
||||||
|
metadata.origin = match (origin.as_str(), dapps_origin) {
|
||||||
|
("null", Some(dapp)) => Origin::Dapps(dapp.into()),
|
||||||
|
_ => Origin::Rpc(origin),
|
||||||
|
};
|
||||||
|
|
||||||
metadata
|
metadata
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,52 +112,92 @@ impl rpc::IpcMetaExtractor<Metadata> for RpcExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Result<Option<HttpServer>, String> {
|
fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler<Metadata, Middleware> {
|
||||||
|
rpc_apis::setup_rpc(deps.stats.clone(), deps.apis.clone(), apis)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_http(conf: HttpConfiguration, deps: &Dependencies, middleware: Option<dapps::Middleware>) -> Result<Option<HttpServer>, String> {
|
||||||
if !conf.enabled {
|
if !conf.enabled {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = format!("{}:{}", conf.interface, conf.port);
|
let url = format!("{}:{}", conf.interface, conf.port);
|
||||||
let addr = url.parse().map_err(|_| format!("Invalid JSONRPC listen host/port given: {}", url))?;
|
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)?))
|
let handler = setup_apis(conf.apis, deps);
|
||||||
}
|
let remote = deps.remote.clone();
|
||||||
|
|
||||||
fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler<Metadata, Middleware> {
|
let cors_domains: Option<Vec<_>> = conf.cors.map(|domains| domains.into_iter().map(AccessControlAllowOrigin::from).collect());
|
||||||
rpc_apis::setup_rpc(deps.stats.clone(), deps.apis.clone(), apis)
|
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())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
pub fn setup_http_rpc_server(
|
|
||||||
dependencies: &Dependencies,
|
|
||||||
url: &SocketAddr,
|
|
||||||
cors_domains: Option<Vec<String>>,
|
|
||||||
allowed_hosts: Option<Vec<String>>,
|
|
||||||
apis: ApiSet
|
|
||||||
) -> Result<HttpServer, String> {
|
|
||||||
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);
|
|
||||||
match start_result {
|
match start_result {
|
||||||
Err(HttpServerError::IoError(err)) => match err.kind() {
|
Ok(server) => Ok(Some(server)),
|
||||||
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(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)
|
||||||
|
),
|
||||||
_ => Err(format!("RPC io error: {}", err)),
|
_ => Err(format!("RPC io error: {}", err)),
|
||||||
},
|
},
|
||||||
Err(e) => Err(format!("RPC error: {:?}", e)),
|
Err(e) => Err(format!("RPC error: {:?}", e)),
|
||||||
Ok(server) => Ok(server),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Result<Option<IpcServer>, String> {
|
pub fn new_ipc(conf: IpcConfiguration, dependencies: &Dependencies) -> Result<Option<IpcServer>, String> {
|
||||||
if !conf.enabled { return Ok(None); }
|
if !conf.enabled {
|
||||||
Ok(Some(setup_ipc_rpc_server(deps, &conf.socket_addr, conf.apis)?))
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
let handler = setup_apis(conf.apis, dependencies);
|
||||||
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: ApiSet) -> Result<IpcServer, String> {
|
|
||||||
let handler = setup_apis(apis, dependencies);
|
|
||||||
let remote = dependencies.remote.clone();
|
let remote = dependencies.remote.clone();
|
||||||
match rpc::start_ipc(addr, handler, remote, RpcExtractor) {
|
match rpc::start_ipc(&conf.socket_addr, handler, remote, RpcExtractor) {
|
||||||
|
Ok(server) => Ok(Some(server)),
|
||||||
Err(io_error) => Err(format!("RPC io error: {}", io_error)),
|
Err(io_error) => Err(format!("RPC io error: {}", io_error)),
|
||||||
Ok(server) => Ok(server)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,7 +81,7 @@ impl FromStr for Api {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ApiSet {
|
pub enum ApiSet {
|
||||||
SafeContext,
|
SafeContext,
|
||||||
UnsafeContext,
|
UnsafeContext,
|
||||||
|
@ -36,7 +36,6 @@ use updater::{UpdatePolicy, Updater};
|
|||||||
use parity_reactor::EventLoop;
|
use parity_reactor::EventLoop;
|
||||||
use hash_fetch::fetch::{Fetch, Client as FetchClient};
|
use hash_fetch::fetch::{Fetch, Client as FetchClient};
|
||||||
|
|
||||||
use rpc::{HttpConfiguration, IpcConfiguration};
|
|
||||||
use params::{
|
use params::{
|
||||||
SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch,
|
SpecType, Pruning, AccountsConfig, GasPricerConfig, MinerExtras, Switch,
|
||||||
tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool
|
tracing_switch_to_bool, fatdb_switch_to_bool, mode_switch_to_bool
|
||||||
@ -76,8 +75,8 @@ pub struct RunCmd {
|
|||||||
pub daemon: Option<String>,
|
pub daemon: Option<String>,
|
||||||
pub logger_config: LogConfig,
|
pub logger_config: LogConfig,
|
||||||
pub miner_options: MinerOptions,
|
pub miner_options: MinerOptions,
|
||||||
pub http_conf: HttpConfiguration,
|
pub http_conf: rpc::HttpConfiguration,
|
||||||
pub ipc_conf: IpcConfiguration,
|
pub ipc_conf: rpc::IpcConfiguration,
|
||||||
pub net_conf: NetworkConfiguration,
|
pub net_conf: NetworkConfiguration,
|
||||||
pub network_id: Option<u64>,
|
pub network_id: Option<u64>,
|
||||||
pub warp_sync: bool,
|
pub warp_sync: bool,
|
||||||
@ -110,11 +109,7 @@ pub struct RunCmd {
|
|||||||
pub verifier_settings: VerifierSettings,
|
pub verifier_settings: VerifierSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_ui(dapps_conf: &dapps::Configuration, signer_conf: &signer::Configuration) -> Result<(), String> {
|
pub fn open_ui(signer_conf: &signer::Configuration) -> Result<(), String> {
|
||||||
if !dapps_conf.enabled {
|
|
||||||
return Err("Cannot use UI command with Dapps turned off.".into())
|
|
||||||
}
|
|
||||||
|
|
||||||
if !signer_conf.enabled {
|
if !signer_conf.enabled {
|
||||||
return Err("Cannot use UI command with UI turned off.".into())
|
return Err("Cannot use UI command with UI turned off.".into())
|
||||||
}
|
}
|
||||||
@ -127,12 +122,12 @@ pub fn open_ui(dapps_conf: &dapps::Configuration, signer_conf: &signer::Configur
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_dapp(dapps_conf: &dapps::Configuration, dapp: &str) -> Result<(), String> {
|
pub fn open_dapp(dapps_conf: &dapps::Configuration, rpc_conf: &rpc::HttpConfiguration, dapp: &str) -> Result<(), String> {
|
||||||
if !dapps_conf.enabled {
|
if !dapps_conf.enabled {
|
||||||
return Err("Cannot use DAPP command with Dapps turned off.".into())
|
return Err("Cannot use DAPP command with Dapps turned off.".into())
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = format!("http://{}:{}/{}/", dapps_conf.interface, dapps_conf.port, dapp);
|
let url = format!("http://{}:{}/{}/", rpc_conf.interface, rpc_conf.port, dapp);
|
||||||
url::open(&url);
|
url::open(&url);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -156,9 +151,9 @@ impl ::local_store::NodeInfo for FullNodeInfo {
|
|||||||
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
|
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
|
||||||
if cmd.ui && cmd.dapps_conf.enabled {
|
if cmd.ui && cmd.dapps_conf.enabled {
|
||||||
// Check if Parity is already running
|
// Check if Parity is already running
|
||||||
let addr = format!("{}:{}", cmd.dapps_conf.interface, cmd.dapps_conf.port);
|
let addr = format!("{}:{}", cmd.signer_conf.interface, cmd.signer_conf.port);
|
||||||
if !TcpListener::bind(&addr as &str).is_ok() {
|
if !TcpListener::bind(&addr as &str).is_ok() {
|
||||||
return open_ui(&cmd.dapps_conf, &cmd.signer_conf).map(|_| (false, None));
|
return open_ui(&cmd.signer_conf).map(|_| (false, None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -429,11 +424,11 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
updater: updater.clone(),
|
updater: updater.clone(),
|
||||||
geth_compatibility: cmd.geth_compatibility,
|
geth_compatibility: cmd.geth_compatibility,
|
||||||
dapps_interface: match cmd.dapps_conf.enabled {
|
dapps_interface: match cmd.dapps_conf.enabled {
|
||||||
true => Some(cmd.dapps_conf.interface.clone()),
|
true => Some(cmd.http_conf.interface.clone()),
|
||||||
false => None,
|
false => None,
|
||||||
},
|
},
|
||||||
dapps_port: match cmd.dapps_conf.enabled {
|
dapps_port: match cmd.dapps_conf.enabled {
|
||||||
true => Some(cmd.dapps_conf.port),
|
true => Some(cmd.http_conf.port),
|
||||||
false => None,
|
false => None,
|
||||||
},
|
},
|
||||||
fetch: fetch.clone(),
|
fetch: fetch.clone(),
|
||||||
@ -445,21 +440,19 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
stats: rpc_stats.clone(),
|
stats: rpc_stats.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// start rpc servers
|
// the dapps middleware
|
||||||
let http_server = rpc::new_http(cmd.http_conf, &dependencies)?;
|
|
||||||
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
|
||||||
|
|
||||||
// the dapps server
|
|
||||||
let dapps_deps = dapps::Dependencies {
|
let dapps_deps = dapps::Dependencies {
|
||||||
apis: deps_for_rpc_apis.clone(),
|
|
||||||
client: client.clone(),
|
client: client.clone(),
|
||||||
sync: sync_provider.clone(),
|
sync: sync_provider.clone(),
|
||||||
remote: event_loop.raw_remote(),
|
remote: event_loop.raw_remote(),
|
||||||
fetch: fetch.clone(),
|
fetch: fetch.clone(),
|
||||||
signer: deps_for_rpc_apis.signer_service.clone(),
|
signer: deps_for_rpc_apis.signer_service.clone(),
|
||||||
stats: rpc_stats.clone(),
|
|
||||||
};
|
};
|
||||||
let dapps_server = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
|
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
|
||||||
|
|
||||||
|
// start rpc servers
|
||||||
|
let http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||||
|
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
||||||
|
|
||||||
// the signer server
|
// the signer server
|
||||||
let signer_deps = signer::Dependencies {
|
let signer_deps = signer::Dependencies {
|
||||||
@ -524,18 +517,18 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
|||||||
|
|
||||||
// start ui
|
// start ui
|
||||||
if cmd.ui {
|
if cmd.ui {
|
||||||
open_ui(&cmd.dapps_conf, &cmd.signer_conf)?;
|
open_ui(&cmd.signer_conf)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(dapp) = cmd.dapp {
|
if let Some(dapp) = cmd.dapp {
|
||||||
open_dapp(&cmd.dapps_conf, &dapp)?;
|
open_dapp(&cmd.dapps_conf, &cmd.http_conf, &dapp)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle exit
|
// Handle exit
|
||||||
let restart = wait_for_exit(panic_handler, Some(updater), Some(client), can_restart);
|
let restart = wait_for_exit(panic_handler, Some(updater), Some(client), can_restart);
|
||||||
|
|
||||||
// drop this stuff as soon as exit detected.
|
// drop this stuff as soon as exit detected.
|
||||||
drop((http_server, ipc_server, dapps_server, signer_server, secretstore_key_server, ipfs_server, event_loop));
|
drop((http_server, ipc_server, signer_server, secretstore_key_server, ipfs_server, event_loop));
|
||||||
|
|
||||||
info!("Finishing work, please wait...");
|
info!("Finishing work, please wait...");
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ transient-hashmap = "0.4"
|
|||||||
|
|
||||||
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-http-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
|
jsonrpc-minihttp-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-ipc-server = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
jsonrpc-macros = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.7" }
|
||||||
|
|
||||||
|
100
rpc/src/lib.rs
100
rpc/src/lib.rs
@ -29,8 +29,9 @@ extern crate time;
|
|||||||
extern crate transient_hashmap;
|
extern crate transient_hashmap;
|
||||||
|
|
||||||
extern crate jsonrpc_core;
|
extern crate jsonrpc_core;
|
||||||
pub extern crate jsonrpc_http_server as http;
|
extern crate jsonrpc_http_server as http;
|
||||||
pub extern crate jsonrpc_ipc_server as ipc;
|
extern crate jsonrpc_minihttp_server as minihttp;
|
||||||
|
extern crate jsonrpc_ipc_server as ipc;
|
||||||
|
|
||||||
extern crate ethash;
|
extern crate ethash;
|
||||||
extern crate ethcore;
|
extern crate ethcore;
|
||||||
@ -62,10 +63,15 @@ extern crate ethjson;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate ethcore_devtools as devtools;
|
extern crate ethcore_devtools as devtools;
|
||||||
|
|
||||||
|
mod metadata;
|
||||||
pub mod v1;
|
pub mod v1;
|
||||||
|
|
||||||
pub use ipc::{Server as IpcServer, MetaExtractor as IpcMetaExtractor, RequestContext as IpcRequestContext};
|
pub use ipc::{Server as IpcServer, MetaExtractor as IpcMetaExtractor, RequestContext as IpcRequestContext};
|
||||||
pub use http::{HttpMetaExtractor, Server as HttpServer, Error as HttpServerError, AccessControlAllowOrigin, Host};
|
pub use http::{
|
||||||
|
hyper,
|
||||||
|
RequestMiddleware, RequestMiddlewareAction,
|
||||||
|
AccessControlAllowOrigin, Host,
|
||||||
|
};
|
||||||
|
|
||||||
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, Metadata, Origin, informant, dispatch};
|
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, Metadata, Origin, informant, dispatch};
|
||||||
pub use v1::block_import::is_major_importing;
|
pub use v1::block_import::is_major_importing;
|
||||||
@ -73,26 +79,98 @@ pub use v1::block_import::is_major_importing;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use http::tokio_core;
|
use http::tokio_core;
|
||||||
|
|
||||||
|
/// RPC HTTP Server instance
|
||||||
|
pub enum HttpServer {
|
||||||
|
/// Fast MiniHTTP variant
|
||||||
|
Mini(minihttp::Server),
|
||||||
|
/// Hyper variant
|
||||||
|
Hyper(http::Server),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// RPC HTTP Server error
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HttpServerError {
|
||||||
|
/// IO error
|
||||||
|
Io(::std::io::Error),
|
||||||
|
/// Other hyper error
|
||||||
|
Hyper(hyper::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<http::Error> for HttpServerError {
|
||||||
|
fn from(e: http::Error) -> Self {
|
||||||
|
use self::HttpServerError::*;
|
||||||
|
match e {
|
||||||
|
http::Error::Io(io) => Io(io),
|
||||||
|
http::Error::Other(hyper) => Hyper(hyper),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<minihttp::Error> for HttpServerError {
|
||||||
|
fn from(e: minihttp::Error) -> Self {
|
||||||
|
use self::HttpServerError::*;
|
||||||
|
match e {
|
||||||
|
minihttp::Error::Io(io) => Io(io),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HTTP RPC server impl-independent metadata extractor
|
||||||
|
pub trait HttpMetaExtractor: Send + Sync + 'static {
|
||||||
|
/// Type of Metadata
|
||||||
|
type Metadata: jsonrpc_core::Metadata;
|
||||||
|
/// Extracts metadata from given params.
|
||||||
|
fn read_metadata(&self, origin: String, dapps_origin: Option<String>) -> Self::Metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HTTP server implementation-specific settings.
|
||||||
|
pub enum HttpSettings<R: RequestMiddleware> {
|
||||||
|
/// Enable fast minihttp server with given number of threads.
|
||||||
|
Threads(usize),
|
||||||
|
/// Enable standard server with optional dapps middleware.
|
||||||
|
Dapps(Option<R>),
|
||||||
|
}
|
||||||
|
|
||||||
/// Start http server asynchronously and returns result with `Server` handle on success or an error.
|
/// Start http server asynchronously and returns result with `Server` handle on success or an error.
|
||||||
pub fn start_http<M, S, H, T>(
|
pub fn start_http<M, S, H, T, R>(
|
||||||
addr: &SocketAddr,
|
addr: &SocketAddr,
|
||||||
cors_domains: http::DomainsValidation<http::AccessControlAllowOrigin>,
|
cors_domains: http::DomainsValidation<http::AccessControlAllowOrigin>,
|
||||||
allowed_hosts: http::DomainsValidation<http::Host>,
|
allowed_hosts: http::DomainsValidation<http::Host>,
|
||||||
handler: H,
|
handler: H,
|
||||||
remote: tokio_core::reactor::Remote,
|
remote: tokio_core::reactor::Remote,
|
||||||
extractor: T,
|
extractor: T,
|
||||||
|
settings: HttpSettings<R>,
|
||||||
) -> Result<HttpServer, HttpServerError> where
|
) -> Result<HttpServer, HttpServerError> where
|
||||||
M: jsonrpc_core::Metadata,
|
M: jsonrpc_core::Metadata,
|
||||||
S: jsonrpc_core::Middleware<M>,
|
S: jsonrpc_core::Middleware<M>,
|
||||||
H: Into<jsonrpc_core::MetaIoHandler<M, S>>,
|
H: Into<jsonrpc_core::MetaIoHandler<M, S>>,
|
||||||
T: HttpMetaExtractor<M>,
|
T: HttpMetaExtractor<Metadata=M>,
|
||||||
|
R: RequestMiddleware,
|
||||||
{
|
{
|
||||||
http::ServerBuilder::new(handler)
|
Ok(match settings {
|
||||||
.event_loop_remote(remote)
|
HttpSettings::Dapps(middleware) => {
|
||||||
.meta_extractor(extractor)
|
let mut builder = http::ServerBuilder::new(handler)
|
||||||
.cors(cors_domains.into())
|
.event_loop_remote(remote)
|
||||||
.allowed_hosts(allowed_hosts.into())
|
.meta_extractor(metadata::HyperMetaExtractor::new(extractor))
|
||||||
.start_http(addr)
|
.cors(cors_domains.into())
|
||||||
|
.allowed_hosts(allowed_hosts.into());
|
||||||
|
|
||||||
|
if let Some(dapps) = middleware {
|
||||||
|
builder = builder.request_middleware(dapps)
|
||||||
|
}
|
||||||
|
builder.start_http(addr)
|
||||||
|
.map(HttpServer::Hyper)?
|
||||||
|
},
|
||||||
|
HttpSettings::Threads(threads) => {
|
||||||
|
minihttp::ServerBuilder::new(handler)
|
||||||
|
.threads(threads)
|
||||||
|
.meta_extractor(metadata::MiniMetaExtractor::new(extractor))
|
||||||
|
.cors(cors_domains.into())
|
||||||
|
.allowed_hosts(allowed_hosts.into())
|
||||||
|
.start_http(addr)
|
||||||
|
.map(HttpServer::Mini)?
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start ipc server asynchronously and returns result with `Server` handle on success or an error.
|
/// Start ipc server asynchronously and returns result with `Server` handle on success or an error.
|
||||||
|
74
rpc/src/metadata.rs
Normal file
74
rpc/src/metadata.rs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use jsonrpc_core;
|
||||||
|
use http;
|
||||||
|
use hyper;
|
||||||
|
use minihttp;
|
||||||
|
use HttpMetaExtractor;
|
||||||
|
|
||||||
|
pub struct HyperMetaExtractor<T> {
|
||||||
|
extractor: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> HyperMetaExtractor<T> {
|
||||||
|
pub fn new(extractor: T) -> Self {
|
||||||
|
HyperMetaExtractor {
|
||||||
|
extractor: extractor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, T> http::MetaExtractor<M> for HyperMetaExtractor<T> where
|
||||||
|
T: HttpMetaExtractor<Metadata = M>,
|
||||||
|
M: jsonrpc_core::Metadata,
|
||||||
|
{
|
||||||
|
fn read_metadata(&self, req: &hyper::server::Request<hyper::net::HttpStream>) -> M {
|
||||||
|
let origin = req.headers().get::<hyper::header::Origin>()
|
||||||
|
.map(|origin| format!("{}://{}", origin.scheme, origin.host))
|
||||||
|
.unwrap_or_else(|| "unknown".into());
|
||||||
|
let dapps_origin = req.headers().get_raw("x-parity-origin")
|
||||||
|
.and_then(|raw| raw.one())
|
||||||
|
.map(|raw| String::from_utf8_lossy(raw).into_owned());
|
||||||
|
self.extractor.read_metadata(origin, dapps_origin)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MiniMetaExtractor<T> {
|
||||||
|
extractor: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> MiniMetaExtractor<T> {
|
||||||
|
pub fn new(extractor: T) -> Self {
|
||||||
|
MiniMetaExtractor {
|
||||||
|
extractor: extractor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M, T> minihttp::MetaExtractor<M> for MiniMetaExtractor<T> where
|
||||||
|
T: HttpMetaExtractor<Metadata = M>,
|
||||||
|
M: jsonrpc_core::Metadata,
|
||||||
|
{
|
||||||
|
fn read_metadata(&self, req: &minihttp::Req) -> M {
|
||||||
|
let origin = req.header("origin")
|
||||||
|
.unwrap_or_else(|| "unknown")
|
||||||
|
.to_owned();
|
||||||
|
let dapps_origin = req.header("x-parity-origin").map(|h| h.to_owned());
|
||||||
|
|
||||||
|
self.extractor.read_metadata(origin, dapps_origin)
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ export TARGETS="
|
|||||||
-p ethash \
|
-p ethash \
|
||||||
-p ethcore \
|
-p ethcore \
|
||||||
-p ethcore-bigint\
|
-p ethcore-bigint\
|
||||||
-p ethcore-dapps \
|
-p parity-dapps \
|
||||||
-p ethcore-rpc \
|
-p ethcore-rpc \
|
||||||
-p ethcore-signer \
|
-p ethcore-signer \
|
||||||
-p ethcore-util \
|
-p ethcore-util \
|
||||||
|
Loading…
Reference in New Issue
Block a user