diff --git a/Cargo.lock b/Cargo.lock index 434c4c7b5..7d65b2e7b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "aho-corasick" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -59,7 +59,7 @@ dependencies = [ "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -68,7 +68,7 @@ name = "backtrace-sys" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -81,15 +81,6 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "base64" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bindgen" version = "0.37.4" @@ -100,12 +91,12 @@ dependencies = [ "clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -128,18 +119,6 @@ dependencies = [ "constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bodyparser" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bodyparser" version = "0.7.0" @@ -148,8 +127,8 @@ dependencies = [ "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -201,13 +180,13 @@ name = "bzip2-sys" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -230,7 +209,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -263,7 +242,7 @@ name = "cmake" version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -323,7 +302,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -388,12 +367,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "dtoa" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -421,7 +395,7 @@ name = "enum-map-derive" version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -450,7 +424,7 @@ dependencies = [ "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -491,6 +465,11 @@ dependencies = [ "miniz_oxide_c_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -507,7 +486,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -515,7 +494,7 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -531,9 +510,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -560,8 +539,8 @@ dependencies = [ "grin_servers 0.3.0", "grin_util 0.3.0", "grin_wallet 0.3.0", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -572,23 +551,25 @@ version = "0.3.0" dependencies = [ "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "grin_chain 0.3.0", "grin_core 0.3.0", "grin_p2p 0.3.0", "grin_pool 0.3.0", "grin_store 0.3.0", "grin_util 0.3.0", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "mount 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -610,8 +591,8 @@ dependencies = [ "lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -624,8 +605,8 @@ dependencies = [ "grin_util 0.3.0", "grin_wallet 0.3.0", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -643,11 +624,11 @@ dependencies = [ "grin_keychain 0.3.0", "grin_util 0.3.0", "grin_wallet 0.3.0", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -660,9 +641,9 @@ dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "grin_util 0.3.0", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -683,8 +664,8 @@ dependencies = [ "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -701,8 +682,8 @@ dependencies = [ "grin_util 0.3.0", "grin_wallet 0.3.0", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -723,15 +704,14 @@ dependencies = [ "grin_store 0.3.0", "grin_util 0.3.0", "grin_wallet 0.3.0", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "router 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,8 +731,8 @@ dependencies = [ "lmdb-zero 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "memmap 0.6.2 (git+https://github.com/danburkert/memmap-rs?tag=0.6.2)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -762,11 +742,11 @@ version = "0.3.0" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "secp256k1zkp 0.7.1 (git+https://github.com/mimblewimble/rust-secp256k1-zkp?branch=testnet3)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -784,29 +764,55 @@ dependencies = [ "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "grin_api 0.3.0", "grin_chain 0.3.0", "grin_core 0.3.0", "grin_keychain 0.3.0", "grin_store 0.3.0", "grin_util 0.3.0", - "hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)", "prettytable-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "h2" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "http" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" version = "1.3.2" @@ -835,45 +841,49 @@ dependencies = [ "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper" -version = "0.11.27" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "idna" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "iovec" version = "0.1.2" @@ -897,22 +907,7 @@ dependencies = [ "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "iron" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime_guess 1.8.5 (registry+https://github.com/rust-lang/crates.io-index)", - "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -935,12 +930,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -948,11 +938,11 @@ name = "jsonrpc-core" version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -976,7 +966,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -991,14 +981,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1015,7 +1005,7 @@ name = "libloading" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1024,9 +1014,9 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1077,7 +1067,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "matches" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1118,25 +1108,6 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mime" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime_guess" -version = "1.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "miniz_oxide" version = "0.1.3" @@ -1151,7 +1122,7 @@ name = "miniz_oxide_c_api" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "miniz_oxide 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1216,7 +1187,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1235,7 +1206,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1377,44 +1348,9 @@ dependencies = [ "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "phf" -version = "0.7.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_codegen" -version = "0.7.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_generator" -version = "0.7.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "phf_shared" -version = "0.7.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pkg-config" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1447,7 +1383,7 @@ dependencies = [ "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "csv 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "encode_unicode 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1462,7 +1398,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1491,7 +1427,7 @@ name = "quote" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1534,60 +1470,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "regex" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "relay" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "route-recognizer" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "router" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "router" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rustc-demangle" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1628,8 +1531,8 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1652,43 +1555,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "serde" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "0.8.6" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_json" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1696,11 +1583,6 @@ name = "siphasher" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "slab" version = "0.4.0" @@ -1734,13 +1616,13 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "0.2.1" +name = "stable_deref_trait" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "stable_deref_trait" -version = "1.1.0" +name = "string" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1768,7 +1650,7 @@ name = "syn" version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1790,11 +1672,6 @@ dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "take" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "take_mut" version = "0.2.2" @@ -1840,7 +1717,7 @@ name = "thread_local" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1859,14 +1736,14 @@ name = "tokio" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1877,7 +1754,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1887,7 +1764,7 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1904,17 +1781,17 @@ name = "tokio-executor" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1923,33 +1800,16 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-proto" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (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.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.7 (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-reactor" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1962,7 +1822,7 @@ name = "tokio-retry" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1973,7 +1833,7 @@ name = "tokio-service" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1982,7 +1842,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1991,11 +1851,11 @@ dependencies = [ [[package]] name = "tokio-threadpool" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2007,7 +1867,7 @@ name = "tokio-timer" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2017,7 +1877,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2030,7 +1890,7 @@ name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2040,7 +1900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "try-lock" -version = "0.1.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2066,15 +1926,7 @@ name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicase" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2082,7 +1934,7 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2128,25 +1980,14 @@ dependencies = [ [[package]] name = "url" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "urlencoded" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "utf8-ranges" version = "1.0.0" @@ -2159,7 +2000,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2174,7 +2015,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "version_check" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2193,12 +2034,12 @@ dependencies = [ [[package]] name = "want" -version = "0.0.4" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2274,7 +2115,7 @@ dependencies = [ [metadata] "checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c" -"checksum aho-corasick 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f0ba20154ea1f47ce2793322f049c5646cc6d0fa9759d5f333f286e507bf8080" +"checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum array-macro 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8b1b1a00de235e9f2cc0e650423dc249d875c116a5934188c08fdd0c02d840ef" "checksum arrayvec 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "06f59fe10306bb78facd90d28c2038ad23ffaaefa85bac43c8a434cde383334f" @@ -2283,12 +2124,10 @@ dependencies = [ "checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" "checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" -"checksum base64 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "85415d2594767338a74a30c1d370b2f3262ec1b4ed2d7bba5b3faf4de40467d9" "checksum bindgen 0.37.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1b25ab82877ea8fe6ce1ce1f8ac54361f0218bad900af9eb11803994bf67c221" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum blake2-rfc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6d530bdd2d52966a6d03b7a964add7ae1a288d25214066fd4b600f0f796400" -"checksum bodyparser 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6928e817538b74a73d1dd6e9a942a2a35c632a597b6bb14fd009480f859a6bf5" "checksum bodyparser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f82c118499b1f91bfe399833d9b6d320ec8775a98cf9ad77af8cc6308b10060c" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" @@ -2297,7 +2136,7 @@ dependencies = [ "checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" "checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b" "checksum bzip2-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2c5162604199bbb17690ede847eaa6120a3f33d5ab4dcc8e7c25b16d849ae79b" -"checksum cc 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "49ec142f5768efb5b7622aebc3fdbdbb8950a4b9ba996393cb76ef7466e8747d" +"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" "checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" "checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" @@ -2317,8 +2156,7 @@ dependencies = [ "checksum cursive 0.8.2-alpha.0 (git+https://github.com/yeastplume/Cursive?tag=grin_integration_1)" = "" "checksum daemonize 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4093d27eb267d617f03c2ee25d4c3ca525b89a76154001954a11984508ffbde5" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum dtoa 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd841b58510c9618291ffa448da2e4e0f699d984d436122372f446dae62263d" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" "checksum encode_unicode 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c088ec0ed2282dcd054f2c124c0327f953563e6c75fdc6ff5141779596289830" "checksum enum-map 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "b5b9d0ef2d88f806ff7ab06c8eee3b8d48d50dc74277efb7bb6877e47a79a1e3" @@ -2330,33 +2168,35 @@ dependencies = [ "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" +"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" +"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum git2 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "910a2df52d2354e4eb27aa12f3803ea86bf461a93e17028908ec0e356572aa7b" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" +"checksum h2 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "6229ac66d3392dd83288fe04defd4b353354b15bbe07820d53dda063a736afcc" +"checksum http 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "4fbced8864b04c030eebcb7d0dc3a81ba5231ac559f5116a29a8ba83ecee22cd" "checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" -"checksum hyper 0.11.27 (registry+https://github.com/rust-lang/crates.io-index)" = "34a590ca09d341e94cddf8e5af0bbccde205d5fbc2fa3c09dd67c7f85cea59d7" -"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum hyper 0.12.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bd2dbf44d0eb8b32ac0cb7b0d75c31313554dd04d6f5dd1085e150ec5383d9b8" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum iron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2440ae846e7a8c7f9b401db8f6e31b4ea5e7d3688b91761337da7e054520c75b" -"checksum iron 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d8e17268922834707e1c29e8badbf9c712c9c43378e1b6a3388946baff10be2" "checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" -"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1" -"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" +"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" +"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" -"checksum libgit2-sys 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7adce4cc6db027611f537837a7c404319b6314dae49c5db80ad5332229894751" +"checksum libgit2-sys 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "9dcce5a1ecca1891ab06c1545a422fd4b35f65c19acec51ea638c66d5be0810d" "checksum liblmdb-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "feed38a3a580f60bf61aaa067b0ff4123395966839adeaf67258a9e50c4d2e49" "checksum libloading 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3ad660d7cb8c5822cd83d10897b0f1f1526792737a179e73896152f85b88c2" "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" @@ -2366,14 +2206,12 @@ dependencies = [ "checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (git+https://github.com/danburkert/memmap-rs?tag=0.6.2)" = "" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mime 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "fe51c8699d2dc522bf8c1ebe26ea2193d151fb54bcdfd7d0318750c189994cd9" -"checksum mime_guess 1.8.5 (registry+https://github.com/rust-lang/crates.io-index)" = "7287ba93031813826d8974566e54eb5e49d4473752f7df21c610dab289aee8cb" "checksum miniz_oxide 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9ba430291c9d6cedae28bcd2d49d1c32fc57d60cd49086646c5dd5673a870eb5" "checksum miniz_oxide_c_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5a5b8234d6103ebfba71e29786da4608540f862de5ce980a1c94f86a40ca0d51" "checksum mio 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "4fcfcb32d63961fb6f367bfd5d21e4600b92cd310f71f9dca25acae196eb1560" @@ -2401,17 +2239,13 @@ dependencies = [ "checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum persistent 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c9c94f2ef72dc272c6bcc8157ccf2bc7da14f4c58c69059ac2fc48492d6916" -"checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2" -"checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b" -"checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" -"checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" -"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" +"checksum pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6a52e4dbc8354505ee07e484ab07127e06d87ca6fa7f0a516a2b294e5ad5ad16" "checksum plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a6a0dc3910bc8db877ffed8e457763b317cf880df4ae19109b9f77d277cf6e0" "checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" "checksum prettytable-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5511ca4c805aa35f0abff6be7923231d664408b60c09f44ef715f2bce106cd9e" "checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4" -"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" +"checksum proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c65b1ea15bb859d922cade2d1765b4b88beac339cbfad545ef2d2ef8c8215ee6" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" @@ -2421,13 +2255,9 @@ dependencies = [ "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum reexport-proc-macro 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "438fe63770eda15baf98e30b4d27ada49b932866307fa04fec24d9043fe63324" -"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" -"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54" -"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" -"checksum route-recognizer 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3255338088df8146ba63d60a9b8e3556f1146ce2973bc05a75181a42ce2256" -"checksum router 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b9b1797ff166029cb632237bb5542696e54961b4cf75a324c6f05c9cf0584e4e" -"checksum router 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc63b6f3b8895b0d04e816b2b1aa58fdba2d5acca3cbb8f0ab8e017347d57397" -"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" +"checksum regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5bbbea44c5490a1e84357ff28b7d518b4619a159fed5d25f6c1de2d19cc42814" +"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d" +"checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" @@ -2437,26 +2267,22 @@ dependencies = [ "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum sequence_trie 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c915714ca833b1d4d6b8f6a9d72a3ff632fe45b40a8d184ef79c81bec6327eed" -"checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" -"checksum serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "210e5a3b159c566d7527e9b22e44be73f2e0fcc330bb78fef4dbccb56d2e74c8" -"checksum serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "dd724d68017ae3a7e63600ee4b2fdb3cad2158ffd1821d44aff4580f63e2b593" -"checksum serde_json 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "67f7d2e9edc3523a9c8ec8cd6ec481b3a27810aafee3e625d311febd3e656b4c" -"checksum serde_json 1.0.22 (registry+https://github.com/rust-lang/crates.io-index)" = "84b8035cabe9b35878adec8ac5fe03d5f6bc97ff6edd7ccb96b44c1276ba390e" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" +"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" +"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum slog 2.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2f7bfce6405155042d42ec0e645efe43eddedd7be280063ce0623b120014e7f9" "checksum slog-async 2.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e544d16c6b230d84c866662fe55e31aacfca6ae71e6fc49ae9a311cb379bfc2f" "checksum slog-term 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5951a808c40f419922ee014c15b6ae1cd34d963538b57d8a4778b9ca3fff1e0b" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" "checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" +"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum supercow 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "171758edb47aa306a78dfa4ab9aeb5167405bd4e3dc2b64e88f6a84bbe98bd63" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum take_mut 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" @@ -2468,24 +2294,22 @@ dependencies = [ "checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb" "checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" "checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" -"checksum tokio-fs 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fc42bae2f6e33865b99069d95bcddfc85c9f0849b4e7e7399eeee71956ef34d7" +"checksum tokio-fs 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "40697ecbea5660df15b15d50a077386477d2f6a35002adf01ce76ff9dd9dce48" "checksum tokio-io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a5c9635ee806f26d302b8baa1e145689a280d8f5aa8d0552e7344808da54cc21" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" "checksum tokio-reactor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e00ec63bbec2c97ce1178cb0587b2c438b2f6b09d3ee54a33c45a9cf0d530810" "checksum tokio-retry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f05746ae87dca83a2016b4f5dba5b237b897dd12fd324f60afe282112f16969a" "checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" -"checksum tokio-threadpool 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c3873a6d8d0b636e024e77b9a82eaab6739578a06189ecd0e731c7308fbc5d" +"checksum tokio-threadpool 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "24ab84f574027b0e875378f31575cf175360891919e93a3490f07e76e00e4efb" "checksum tokio-timer 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "028b94314065b90f026a21826cffd62a4e40a92cda3e5c069cc7b02e5945f5e9" "checksum tokio-udp 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "43eb534af6e8f37d43ab1b612660df14755c42bd003c5f8d2475ee78cc4600c0" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2aa4715743892880f70885373966c83d73ef1b0838a664ef0c76fffd35e7c2" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "653be63c80a3296da5551e1bfd2cca35227e13cdd08c6668903ae2f4f77aa1f6" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" -"checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" @@ -2494,16 +2318,15 @@ dependencies = [ "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum unsafe-any 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f30360d7979f5e9c6e6cea48af192ea8fab4afb3cf72597154b8f08935bc9c7f" -"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" -"checksum urlencoded 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8c28708636d6f7298a53b1cdb6af40f1ab523209a7cb83cf4d41b3ebc671d319" +"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" "checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474" "checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" -"checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" +"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" diff --git a/api/Cargo.toml b/api/Cargo.toml index bc12a5fcb..54ed708b9 100644 --- a/api/Cargo.toml +++ b/api/Cargo.toml @@ -6,19 +6,21 @@ workspace = ".." publish = false [dependencies] -failure = "0.1" -failure_derive = "0.1" -hyper = "0.10" -iron = "0.5" +failure = "0.1.1" +failure_derive = "0.1.1" +hyper = "0.12" lazy_static = "1" mount = "0.3" regex = "1" -router = "0.5" serde = "1" serde_derive = "1" serde_json = "1" slog = { version = "~2.2", features = ["max_level_trace", "release_max_level_trace"] } -urlencoded = "0.5" # 0.6+ lacks trait `plugin::Plugin>` +tokio = "0.1.7" +tokio-core = "0.1.17" +http = "0.1.5" +futures = "0.1.21" +url = "1.7.0" grin_core = { path = "../core" } grin_chain = { path = "../chain" } diff --git a/api/src/client.rs b/api/src/client.rs index 18d26ccbc..6a49b6de0 100644 --- a/api/src/client.rs +++ b/api/src/client.rs @@ -15,12 +15,15 @@ //! High level JSON/HTTP client API use failure::{Fail, ResultExt}; -use hyper; -use hyper::client::Response; -use hyper::status::{StatusClass, StatusCode}; +use http::uri::{InvalidUri, Uri}; +use hyper::header::{ACCEPT, USER_AGENT}; +use hyper::rt::{Future, Stream}; +use hyper::{Body, Client, Request}; use serde::{Deserialize, Serialize}; use serde_json; -use std::io::Read; + +use futures::future::{err, ok, Either}; +use tokio_core::reactor::Core; use rest::{Error, ErrorKind}; @@ -31,63 +34,104 @@ pub fn get<'a, T>(url: &'a str) -> Result where for<'de> T: Deserialize<'de>, { - let client = hyper::Client::new(); - let res = check_error(client.get(url).send())?; - serde_json::from_reader(res).map_err(|e| { - e.context(ErrorKind::Internal( - "Server returned invalid JSON".to_owned(), - )).into() - }) + let uri = url.parse::().map_err::(|e: InvalidUri| { + e.context(ErrorKind::Argument(format!("Invalid url {}", url))) + .into() + })?; + let req = Request::builder() + .method("GET") + .uri(uri) + .header(USER_AGENT, "grin-client") + .header(ACCEPT, "application/json") + .body(Body::empty()) + .map_err(|_e| ErrorKind::RequestError("Bad request".to_owned()))?; + + handle_request(req) } /// Helper function to easily issue a HTTP POST request with the provided JSON /// object as body on a given URL that returns a JSON object. Handles request /// building, JSON serialization and deserialization, and response code /// checking. -pub fn post<'a, IN>(url: &'a str, input: &IN) -> Result<(), Error> +pub fn post(url: &str, input: &IN) -> Result +where + IN: Serialize, + for<'de> OUT: Deserialize<'de>, +{ + let req = create_post_request(url, input)?; + handle_request(req) +} + +/// Helper function to easily issue a HTTP POST request with the provided JSON +/// object as body on a given URL that returns nothing. Handles request +/// building, JSON serialization, and response code +/// checking. +pub fn post_no_ret(url: &str, input: &IN) -> Result<(), Error> where IN: Serialize, { - let in_json = serde_json::to_string(input).context(ErrorKind::Internal( - "Could not serialize data to JSON".to_owned(), - ))?; - let client = hyper::Client::new(); - let _res = check_error(client.post(url).body(&mut in_json.as_bytes()).send())?; + let req = create_post_request(url, input)?; + send_request(req)?; Ok(()) } -// convert hyper error and check for non success response codes -fn check_error(res: hyper::Result) -> Result { - if let Err(e) = res { - return Err( - e.context(ErrorKind::Internal("Error during request".to_owned())) - .into(), - ); - } - let mut response = res.unwrap(); - match response.status.class() { - StatusClass::Success => Ok(response), - StatusClass::ServerError => Err(ErrorKind::Internal(format!( - "Server error: {}", - err_msg(&mut response) - )))?, - StatusClass::ClientError => if response.status == StatusCode::NotFound { - Err(ErrorKind::NotFound)? - } else { - Err(ErrorKind::Argument(format!( - "Argument error: {}", - err_msg(&mut response) - )))? - }, - _ => Err(ErrorKind::Internal(format!("Unrecognized error.")))?, - } +fn create_post_request(url: &str, input: &IN) -> Result, Error> +where + IN: Serialize, +{ + let json = serde_json::to_string(input).context(ErrorKind::Internal( + "Could not serialize data to JSON".to_owned(), + ))?; + let uri = url.parse::().map_err::(|e: InvalidUri| { + e.context(ErrorKind::Argument(format!("Invalid url {}", url))) + .into() + })?; + Request::builder() + .method("POST") + .uri(uri) + .header(USER_AGENT, "grin-client") + .header(ACCEPT, "application/json") + .body(json.into()) + .map_err::(|e| { + e.context(ErrorKind::RequestError("Bad request".to_owned())) + .into() + }) } -fn err_msg(resp: &mut Response) -> String { - let mut msg = String::new(); - if let Err(_) = resp.read_to_string(&mut msg) { - "".to_owned() - } else { - msg - } +fn handle_request(req: Request) -> Result +where + for<'de> T: Deserialize<'de>, +{ + let data = send_request(req)?; + serde_json::from_str(&data).map_err(|e| { + e.context(ErrorKind::ResponseError("Cannot parse response".to_owned())) + .into() + }) +} + +fn send_request(req: Request) -> Result { + let mut event_loop = Core::new().unwrap(); + let client = Client::new(); + + let task = client + .request(req) + .map_err(|_e| ErrorKind::RequestError("Cannot make request".to_owned())) + .and_then(|resp| { + if !resp.status().is_success() { + Either::A(err(ErrorKind::RequestError( + "Wrong response code".to_owned(), + ))) + } else { + Either::B( + resp.into_body() + .map_err(|_e| { + ErrorKind::RequestError("Cannot read response body".to_owned()) + }) + .concat2() + .and_then(|ch| ok(String::from_utf8_lossy(&ch.to_vec()).to_string())), + ) + } + }); + + Ok(event_loop.run(task)?) } diff --git a/api/src/handlers.rs b/api/src/handlers.rs index 6e20106af..b9ad55f55 100644 --- a/api/src/handlers.rs +++ b/api/src/handlers.rs @@ -12,16 +12,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::io::Read; +use std::cell::RefCell; +use std::collections::HashMap; +use std::fmt::Debug; +use std::net::SocketAddr; use std::sync::{Arc, RwLock, Weak}; use std::thread; -use failure::{Fail, ResultExt}; -use iron::prelude::{IronError, IronResult, Plugin, Request, Response}; -use iron::{status, Handler}; -use serde::Serialize; +use failure::ResultExt; +use futures::future::{err, ok}; +use futures::{Future, Stream}; +use hyper::{Body, Request, Response, StatusCode}; +use rest::{Error, ErrorKind}; +use serde::{Deserialize, Serialize}; use serde_json; -use urlencoded::UrlEncodedQuery; use chain; use core::core::hash::{Hash, Hashed}; @@ -31,10 +35,13 @@ use p2p; use p2p::types::ReasonForBan; use pool; use regex::Regex; -use rest::{ApiServer, Error, ErrorKind}; +use rest::*; +use router::{Handler, ResponseFuture, Router, RouterError}; use types::*; +use url::form_urlencoded; +use util; use util::secp::pedersen::Commitment; -use util::{self, LOGGER}; +use util::LOGGER; // All handlers use `Weak` references instead of `Arc` to avoid cycles that // can never be destroyed. These 2 functions are simple helpers to reduce the @@ -52,7 +59,7 @@ struct IndexHandler { impl IndexHandler {} impl Handler for IndexHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { json_response_pretty(&self.list) } } @@ -90,14 +97,16 @@ impl OutputHandler { Err(ErrorKind::NotFound)? } - fn outputs_by_ids(&self, req: &mut Request) -> Vec { - let mut commitments: Vec<&str> = vec![]; - if let Ok(params) = req.get_ref::() { - if let Some(ids) = params.get("id") { - for id in ids { - for id in id.split(",") { - commitments.push(id.clone()); - } + fn outputs_by_ids(&self, req: &Request) -> Vec { + let mut commitments: Vec = vec![]; + let params = form_urlencoded::parse(req.uri().query().unwrap().as_bytes()) + .into_owned() + .collect::>(); + + for (k, id) in params { + if k == "id" { + for id in id.split(",") { + commitments.push(id.to_owned()); } } } @@ -106,7 +115,7 @@ impl OutputHandler { let mut outputs: Vec = vec![]; for x in commitments { - if let Ok(output) = self.get_output(x) { + if let Ok(output) = self.get_output(&x) { outputs.push(output); } } @@ -158,36 +167,41 @@ impl OutputHandler { } // returns outputs for a specified range of blocks - fn outputs_block_batch(&self, req: &mut Request) -> Vec { + fn outputs_block_batch(&self, req: &Request) -> Vec { let mut commitments: Vec = vec![]; let mut start_height = 1; let mut end_height = 1; let mut include_rp = false; - if let Ok(params) = req.get_ref::() { - if let Some(ids) = params.get("id") { - for id in ids { - for id in id.split(",") { - if let Ok(x) = util::from_hex(String::from(id)) { - commitments.push(Commitment::from_vec(x)); - } + let params = form_urlencoded::parse(req.uri().query().unwrap().as_bytes()) + .into_owned() + .fold(HashMap::new(), |mut hm, (k, v)| { + hm.entry(k).or_insert(vec![]).push(v); + hm + }); + + if let Some(ids) = params.get("id") { + for id in ids { + for id in id.split(",") { + if let Ok(x) = util::from_hex(String::from(id)) { + commitments.push(Commitment::from_vec(x)); } } } - if let Some(heights) = params.get("start_height") { - for height in heights { - start_height = height.parse().unwrap(); - } + } + if let Some(heights) = params.get("start_height") { + for height in heights { + start_height = height.parse().unwrap(); } - if let Some(heights) = params.get("end_height") { - for height in heights { - end_height = height.parse().unwrap(); - } - } - if let Some(_) = params.get("include_rp") { - include_rp = true; + } + if let Some(heights) = params.get("end_height") { + for height in heights { + end_height = height.parse().unwrap(); } } + if let Some(_) = params.get("include_rp") { + include_rp = true; + } debug!( LOGGER, @@ -211,16 +225,17 @@ impl OutputHandler { } impl Handler for OutputHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); - if *path_elems.last().unwrap() == "" { - path_elems.pop(); - } - match *path_elems.last().unwrap() { - "byids" => json_response(&self.outputs_by_ids(req)), - "byheight" => json_response(&self.outputs_block_batch(req)), - _ => Ok(Response::with((status::BadRequest, ""))), + fn get(&self, req: Request) -> ResponseFuture { + match req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + { + "byids" => json_response(&self.outputs_by_ids(&req)), + "byheight" => json_response(&self.outputs_block_batch(&req)), + _ => response(StatusCode::BAD_REQUEST, ""), } } } @@ -306,18 +321,20 @@ impl TxHashSetHandler { } impl Handler for TxHashSetHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); + fn get(&self, req: Request) -> ResponseFuture { let mut start_index = 1; let mut max = 100; - let mut id = ""; - if *path_elems.last().unwrap() == "" { - path_elems.pop(); - } + let mut id = "".to_owned(); + // TODO: probably need to set a reasonable max limit here let mut last_n = 10; - if let Ok(params) = req.get_ref::() { + if let Some(query_string) = req.uri().query() { + let params = form_urlencoded::parse(query_string.as_bytes()) + .into_owned() + .fold(HashMap::new(), |mut hm, (k, v)| { + hm.entry(k).or_insert(vec![]).push(v); + hm + }); if let Some(nums) = params.get("n") { for num in nums { if let Ok(n) = str::parse(num) { @@ -340,19 +357,26 @@ impl Handler for TxHashSetHandler { } } if let Some(ids) = params.get("id") { - for i in ids { - id = i; + if !ids.is_empty() { + id = ids.last().unwrap().to_owned(); } } } - match *path_elems.last().unwrap() { + match req.uri() + .path() + .trim_right() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + { "roots" => json_response_pretty(&self.get_roots()), "lastoutputs" => json_response_pretty(&self.get_last_n_output(last_n)), "lastrangeproofs" => json_response_pretty(&self.get_last_n_rangeproof(last_n)), "lastkernels" => json_response_pretty(&self.get_last_n_kernel(last_n)), "outputs" => json_response_pretty(&self.outputs(start_index, max)), - "merkleproof" => json_response_pretty(&self.get_merkle_proof_for_output(id).unwrap()), - _ => Ok(Response::with((status::BadRequest, ""))), + "merkleproof" => json_response_pretty(&self.get_merkle_proof_for_output(&id).unwrap()), + _ => response(StatusCode::BAD_REQUEST, ""), } } } @@ -362,7 +386,7 @@ pub struct PeersAllHandler { } impl Handler for PeersAllHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { let peers = &w(&self.peers).all_peers(); json_response_pretty(&peers) } @@ -373,7 +397,7 @@ pub struct PeersConnectedHandler { } impl Handler for PeersConnectedHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { let mut peers = vec![]; for p in &w(&self.peers).connected_peers() { let p = p.read().unwrap(); @@ -385,62 +409,54 @@ impl Handler for PeersConnectedHandler { } /// Peer operations +/// GET /v1/peers/10.12.12.13 /// POST /v1/peers/10.12.12.13/ban /// POST /v1/peers/10.12.12.13/unban -pub struct PeerPostHandler { +pub struct PeerHandler { pub peers: Weak, } -impl Handler for PeerPostHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); - if *path_elems.last().unwrap() == "" { - path_elems.pop(); +impl Handler for PeerHandler { + fn get(&self, req: Request) -> ResponseFuture { + if let Ok(addr) = req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + .parse() + { + match w(&self.peers).get_peer(addr) { + Ok(peer) => json_response(&peer), + Err(_) => response(StatusCode::BAD_REQUEST, ""), + } + } else { + response( + StatusCode::BAD_REQUEST, + format!("url unrecognized: {}", req.uri().path()), + ) } - match *path_elems.last().unwrap() { + } + fn post(&self, req: Request) -> ResponseFuture { + let mut path_elems = req.uri().path().trim_right_matches("/").rsplit("/"); + match path_elems.next().unwrap() { "ban" => { - path_elems.pop(); - if let Ok(addr) = path_elems.last().unwrap().parse() { + if let Ok(addr) = path_elems.next().unwrap().parse() { w(&self.peers).ban_peer(&addr, ReasonForBan::ManualBan); - Ok(Response::with((status::Ok, ""))) + response(StatusCode::OK, "") } else { - Ok(Response::with((status::BadRequest, ""))) + response(StatusCode::BAD_REQUEST, "bad address to ban") } } "unban" => { - path_elems.pop(); - if let Ok(addr) = path_elems.last().unwrap().parse() { + if let Ok(addr) = path_elems.next().unwrap().parse() { w(&self.peers).unban_peer(&addr); - Ok(Response::with((status::Ok, ""))) + response(StatusCode::OK, "") } else { - Ok(Response::with((status::BadRequest, ""))) + response(StatusCode::BAD_REQUEST, "bad address to unban") } } - _ => Ok(Response::with((status::BadRequest, ""))), - } - } -} - -/// Get details about a given peer -pub struct PeerGetHandler { - pub peers: Weak, -} - -impl Handler for PeerGetHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); - if *path_elems.last().unwrap() == "" { - path_elems.pop(); - } - if let Ok(addr) = path_elems.last().unwrap().parse() { - match w(&self.peers).get_peer(addr) { - Ok(peer) => json_response(&peer), - Err(_) => Ok(Response::with((status::BadRequest, ""))), - } - } else { - Ok(Response::with((status::BadRequest, ""))) + _ => response(StatusCode::BAD_REQUEST, "unrecognized command"), } } } @@ -459,7 +475,7 @@ impl StatusHandler { } impl Handler for StatusHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { json_response(&self.get_status()) } } @@ -477,7 +493,7 @@ impl ChainHandler { } impl Handler for ChainHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { json_response(&self.get_tip()) } } @@ -489,10 +505,10 @@ pub struct ChainValidationHandler { } impl Handler for ChainValidationHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { // TODO - read skip_rproofs from query params w(&self.chain).validate(true).unwrap(); - Ok(Response::with((status::Ok, "{}"))) + response(StatusCode::OK, "") } } @@ -504,9 +520,9 @@ pub struct ChainCompactHandler { } impl Handler for ChainCompactHandler { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { w(&self.chain).compact().unwrap(); - Ok(Response::with((status::Ok, "{}"))) + response(StatusCode::OK, "") } } @@ -529,7 +545,9 @@ impl HeaderHandler { check_block_param(&input)?; let vec = util::from_hex(input).unwrap(); let h = Hash::from_vec(&vec); - let header = w(&self.chain).get_block_header(&h).context(ErrorKind::NotFound)?; + let header = w(&self.chain) + .get_block_header(&h) + .context(ErrorKind::NotFound)?; Ok(BlockHeaderPrintable::from_header(&header)) } } @@ -573,58 +591,82 @@ impl BlockHandler { } fn check_block_param(input: &String) -> Result<(), Error> { - lazy_static! { - static ref RE: Regex = Regex::new(r"[0-9a-fA-F]{64}").unwrap(); - } - if !RE.is_match(&input) { - return Err(ErrorKind::Argument( - "Not a valid hash or height.".to_owned(), - ))?; - } - return Ok(()) + lazy_static! { + static ref RE: Regex = Regex::new(r"[0-9a-fA-F]{64}").unwrap(); + } + if !RE.is_match(&input) { + return Err(ErrorKind::Argument( + "Not a valid hash or height.".to_owned(), + ))?; + } + return Ok(()); } impl Handler for BlockHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); - if *path_elems.last().unwrap() == "" { - path_elems.pop(); - } - let el = *path_elems.last().unwrap(); - let h = self.parse_input(el.to_string()) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?; + fn get(&self, req: Request) -> ResponseFuture { + let el = req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap(); - let mut compact = false; - if let Ok(params) = req.get_ref::() { - if let Some(_) = params.get("compact") { - compact = true; + let h = self.parse_input(el.to_string()); + if h.is_err() { + error!(LOGGER, "block_handler: bad parameter {}", el.to_string()); + return response(StatusCode::BAD_REQUEST, ""); + } + + let h = h.unwrap(); + + if let Some(param) = req.uri().query() { + if param == "compact" { + match self.get_compact_block(&h) { + Ok(b) => json_response(&b), + Err(_) => { + error!(LOGGER, "block_handler: can not get compact block {}", h); + response(StatusCode::INTERNAL_SERVER_ERROR, "") + } + } + } else { + debug!( + LOGGER, + "block_handler: unsupported query parameter {}", param + ); + response(StatusCode::BAD_REQUEST, "") } - } - - if compact { - let b = self.get_compact_block(&h) - .map_err(|e| IronError::new(Fail::compat(e), status::InternalServerError))?; - json_response(&b) } else { - let b = self.get_block(&h) - .map_err(|e| IronError::new(Fail::compat(e), status::InternalServerError))?; - json_response(&b) + match self.get_block(&h) { + Ok(b) => json_response(&b), + Err(_) => { + error!(LOGGER, "block_handler: can not get block {}", h); + response(StatusCode::INTERNAL_SERVER_ERROR, "") + } + } } } } impl Handler for HeaderHandler { - fn handle(&self, req: &mut Request) -> IronResult { - let url = req.url.clone(); - let mut path_elems = url.path(); - if *path_elems.last().unwrap() == "" { - path_elems.pop(); + fn get(&self, req: Request) -> ResponseFuture { + let el = req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap(); + + match self.get_header(el.to_string()) { + Ok(h) => json_response(&h), + Err(_) => { + error!( + LOGGER, + "header_handler: can not get header {}", + el.to_string() + ); + response(StatusCode::INTERNAL_SERVER_ERROR, "") + } } - let el = *path_elems.last().unwrap(); - let h = self.get_header(el.to_string()) - .map_err(|e| IronError::new(Fail::compat(e), status::InternalServerError))?; - json_response(&h) } } @@ -635,9 +677,9 @@ struct PoolInfoHandler { impl Handler for PoolInfoHandler where - T: pool::BlockChain + Send + Sync + 'static, + T: pool::BlockChain + Send + Sync, { - fn handle(&self, _req: &mut Request) -> IronResult { + fn get(&self, _req: Request) -> ResponseFuture { let pool_arc = w(&self.tx_pool); let pool = pool_arc.read().unwrap(); @@ -658,78 +700,106 @@ struct PoolPushHandler { tx_pool: Weak>>, } +impl PoolPushHandler +where + T: pool::BlockChain + Send + Sync + 'static, +{ + fn update_pool(&self, req: Request) -> Box + Send> { + let params = match req.uri().query() { + Some(query_string) => form_urlencoded::parse(query_string.as_bytes()) + .into_owned() + .fold(HashMap::new(), |mut hm, (k, v)| { + hm.entry(k).or_insert(vec![]).push(v); + hm + }), + None => HashMap::new(), + }; + + let fluff = params.get("fluff").is_some(); + let pool_arc = w(&self.tx_pool).clone(); + + Box::new( + parse_body(req) + .and_then(move |wrapper: TxWrapper| { + util::from_hex(wrapper.tx_hex) + .map_err(|_| ErrorKind::RequestError("Bad request".to_owned()).into()) + }) + .and_then(move |tx_bin| { + ser::deserialize(&mut &tx_bin[..]) + .map_err(|_| ErrorKind::RequestError("Bad request".to_owned()).into()) + }) + .and_then(move |tx: Transaction| { + let source = pool::TxSource { + debug_name: "push-api".to_string(), + identifier: "?.?.?.?".to_string(), + }; + info!( + LOGGER, + "Pushing transaction with {} inputs and {} outputs to pool.", + tx.inputs.len(), + tx.outputs.len() + ); + + // Push to tx pool. + let mut tx_pool = pool_arc.write().unwrap(); + tx_pool + .add_to_pool(source, tx, !fluff) + .map_err(|_| ErrorKind::RequestError("Bad request".to_owned()).into()) + }), + ) + } +} + impl Handler for PoolPushHandler where T: pool::BlockChain + Send + Sync + 'static, { - fn handle(&self, req: &mut Request) -> IronResult { - let wrapper: TxWrapper = serde_json::from_reader(req.body.by_ref()) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?; - - let tx_bin = util::from_hex(wrapper.tx_hex) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?; - - let tx: Transaction = ser::deserialize(&mut &tx_bin[..]) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?; - - let source = pool::TxSource { - debug_name: "push-api".to_string(), - identifier: "?.?.?.?".to_string(), - }; - info!( - LOGGER, - "Pushing transaction with {} inputs and {} outputs to pool.", - tx.inputs.len(), - tx.outputs.len() - ); - - let mut fluff = false; - if let Ok(params) = req.get_ref::() { - if let Some(_) = params.get("fluff") { - fluff = true; - } - } - - // Push to tx pool. - let res = { - let pool_arc = w(&self.tx_pool); - let mut tx_pool = pool_arc.write().unwrap(); - tx_pool.add_to_pool(source, tx, !fluff) - }; - - match res { - Ok(()) => Ok(Response::with(status::Ok)), - Err(e) => { - debug!(LOGGER, "error - {:?}", e); - Err(IronError::new(Fail::compat(e), status::BadRequest)) - } - } + fn post(&self, req: Request) -> ResponseFuture { + Box::new( + self.update_pool(req) + .and_then(|_| ok(just_response(StatusCode::OK, ""))) + .or_else(|_| ok(just_response(StatusCode::BAD_REQUEST, ""))), + ) } } -// Utility to serialize a struct into JSON and produce a sensible IronResult +// Utility to serialize a struct into JSON and produce a sensible Response // out of it. -fn json_response(s: &T) -> IronResult +fn json_response(s: &T) -> ResponseFuture where T: Serialize, { match serde_json::to_string(s) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::InternalServerError, ""))), + Ok(json) => response(StatusCode::OK, json), + Err(_) => response(StatusCode::INTERNAL_SERVER_ERROR, ""), } } // pretty-printed version of above -fn json_response_pretty(s: &T) -> IronResult +fn json_response_pretty(s: &T) -> ResponseFuture where T: Serialize, { match serde_json::to_string_pretty(s) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::InternalServerError, ""))), + Ok(json) => response(StatusCode::OK, json), + Err(_) => response(StatusCode::INTERNAL_SERVER_ERROR, ""), } } -/// Start all server HTTP handlers. Register all of them with Iron + +fn response + Debug>(status: StatusCode, text: T) -> ResponseFuture { + Box::new(ok(just_response(status, text))) +} + +fn just_response + Debug>(status: StatusCode, text: T) -> Response { + debug!(LOGGER, "HTTP API -> status: {}, text: {:?}", status, text); + let mut resp = Response::new(text.into()); + *resp.status_mut() = status; + resp +} + +thread_local!( static ROUTER: RefCell> = RefCell::new(None) ); + +/// Start all server HTTP handlers. Register all of them with Router /// and runs the corresponding HTTP server. /// /// Hyper currently has a bug that prevents clean shutdown. In order @@ -748,98 +818,132 @@ pub fn start_rest_apis( let _ = thread::Builder::new() .name("apis".to_string()) .spawn(move || { - // build handlers and register them under the appropriate endpoint - let output_handler = OutputHandler { - chain: chain.clone(), - }; - let block_handler = BlockHandler { - chain: chain.clone(), - }; - let header_handler = HeaderHandler { - chain: chain.clone(), - }; - let chain_tip_handler = ChainHandler { - chain: chain.clone(), - }; - let chain_compact_handler = ChainCompactHandler { - chain: chain.clone(), - }; - let chain_validation_handler = ChainValidationHandler { - chain: chain.clone(), - }; - let status_handler = StatusHandler { - chain: chain.clone(), - peers: peers.clone(), - }; - let txhashset_handler = TxHashSetHandler { - chain: chain.clone(), - }; - let pool_info_handler = PoolInfoHandler { - tx_pool: tx_pool.clone(), - }; - let pool_push_handler = PoolPushHandler { - tx_pool: tx_pool.clone(), - }; - let peers_all_handler = PeersAllHandler { - peers: peers.clone(), - }; - let peers_connected_handler = PeersConnectedHandler { - peers: peers.clone(), - }; - let peer_post_handler = PeerPostHandler { - peers: peers.clone(), - }; - let peer_get_handler = PeerGetHandler { - peers: peers.clone(), - }; + let mut apis = ApiServer::new(); - let route_list = vec![ - "get blocks".to_string(), - "get chain".to_string(), - "get chain/compact".to_string(), - "get chain/validate".to_string(), - "get chain/outputs".to_string(), - "post chain/height-index".to_string(), - "get status".to_string(), - "get txhashset/roots".to_string(), - "get txhashset/lastoutputs?n=10".to_string(), - "get txhashset/lastrangeproofs".to_string(), - "get txhashset/lastkernels".to_string(), - "get txhashset/outputs?start_index=1&max=100".to_string(), - "get pool".to_string(), - "post pool/push".to_string(), - "post peers/a.b.c.d:p/ban".to_string(), - "post peers/a.b.c.d:p/unban".to_string(), - "get peers/all".to_string(), - "get peers/connected".to_string(), - "get peers/a.b.c.d".to_string(), - ]; - let index_handler = IndexHandler { list: route_list }; + ROUTER.with(|router| { + *router.borrow_mut() = + Some(build_router(chain, tx_pool, peers).expect("unbale to build API router")); - let router = router!( - index: get "/" => index_handler, - blocks: get "/blocks/*" => block_handler, - headers: get "/headers/*" => header_handler, - chain_tip: get "/chain" => chain_tip_handler, - chain_compact: get "/chain/compact" => chain_compact_handler, - chain_validate: get "/chain/validate" => chain_validation_handler, - chain_outputs: get "/chain/outputs/*" => output_handler, - status: get "/status" => status_handler, - txhashset_roots: get "/txhashset/*" => txhashset_handler, - pool_info: get "/pool" => pool_info_handler, - pool_push: post "/pool/push" => pool_push_handler, - peers_all: get "/peers/all" => peers_all_handler, - peers_connected: get "/peers/connected" => peers_connected_handler, - peer: post "/peers/*" => peer_post_handler, - peer: get "/peers/*" => peer_get_handler - ); - - let mut apis = ApiServer::new("/v1".to_string()); - apis.register_handler(router); - - info!(LOGGER, "Starting HTTP API server at {}.", addr); - apis.start(&addr[..]).unwrap_or_else(|e| { - error!(LOGGER, "Failed to start API HTTP server: {}.", e); + info!(LOGGER, "Starting HTTP API server at {}.", addr); + let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address"); + apis.start(socket_addr, &handle).unwrap_or_else(|e| { + error!(LOGGER, "Failed to start API HTTP server: {}.", e); + }); }); }); } + +pub fn handle(req: Request) -> ResponseFuture { + ROUTER.with(|router| match *router.borrow() { + Some(ref h) => h.handle(req), + None => { + error!(LOGGER, "No HTTP API router configured"); + response(StatusCode::INTERNAL_SERVER_ERROR, "No router configured") + } + }) +} + +fn parse_body(req: Request) -> Box + Send> +where + for<'de> T: Deserialize<'de> + Send + 'static, +{ + Box::new( + req.into_body() + .concat2() + .map_err(|_e| ErrorKind::RequestError("Failed to read request".to_owned()).into()) + .and_then(|body| match serde_json::from_reader(&body.to_vec()[..]) { + Ok(obj) => ok(obj), + Err(_) => err(ErrorKind::RequestError("Invalid request body".to_owned()).into()), + }), + ) +} + +pub fn build_router( + chain: Weak, + tx_pool: Weak>>, + peers: Weak, +) -> Result +where + T: pool::BlockChain + Send + Sync + 'static, +{ + let route_list = vec![ + "get blocks".to_string(), + "get chain".to_string(), + "get chain/compact".to_string(), + "get chain/validate".to_string(), + "get chain/outputs".to_string(), + "get status".to_string(), + "get txhashset/roots".to_string(), + "get txhashset/lastoutputs?n=10".to_string(), + "get txhashset/lastrangeproofs".to_string(), + "get txhashset/lastkernels".to_string(), + "get txhashset/outputs?start_index=1&max=100".to_string(), + "get pool".to_string(), + "post pool/push".to_string(), + "post peers/a.b.c.d:p/ban".to_string(), + "post peers/a.b.c.d:p/unban".to_string(), + "get peers/all".to_string(), + "get peers/connected".to_string(), + "get peers/a.b.c.d".to_string(), + ]; + let index_handler = IndexHandler { list: route_list }; + + let output_handler = OutputHandler { + chain: chain.clone(), + }; + + let block_handler = BlockHandler { + chain: chain.clone(), + }; + let header_handler = HeaderHandler { + chain: chain.clone(), + }; + let chain_tip_handler = ChainHandler { + chain: chain.clone(), + }; + let chain_compact_handler = ChainCompactHandler { + chain: chain.clone(), + }; + let chain_validation_handler = ChainValidationHandler { + chain: chain.clone(), + }; + let status_handler = StatusHandler { + chain: chain.clone(), + peers: peers.clone(), + }; + let txhashset_handler = TxHashSetHandler { + chain: chain.clone(), + }; + let pool_info_handler = PoolInfoHandler { + tx_pool: tx_pool.clone(), + }; + let pool_push_handler = PoolPushHandler { + tx_pool: tx_pool.clone(), + }; + let peers_all_handler = PeersAllHandler { + peers: peers.clone(), + }; + let peers_connected_handler = PeersConnectedHandler { + peers: peers.clone(), + }; + let peer_handler = PeerHandler { + peers: peers.clone(), + }; + + let mut router = Router::new(); + router.add_route("/v1/", Box::new(index_handler))?; + router.add_route("/v1/blocks/*", Box::new(block_handler))?; + router.add_route("/v1/headers/*", Box::new(header_handler))?; + router.add_route("/v1/chain", Box::new(chain_tip_handler))?; + router.add_route("/v1/chain/outputs/*", Box::new(output_handler))?; + router.add_route("/v1/chain/compact", Box::new(chain_compact_handler))?; + router.add_route("/v1/chain/validate", Box::new(chain_validation_handler))?; + router.add_route("/v1/txhashset/*", Box::new(txhashset_handler))?; + router.add_route("/v1/status", Box::new(status_handler))?; + router.add_route("/v1/pool", Box::new(pool_info_handler))?; + router.add_route("/v1/pool/push", Box::new(pool_push_handler))?; + router.add_route("/v1/peers/all", Box::new(peers_all_handler))?; + router.add_route("/v1/peers/connected", Box::new(peers_connected_handler))?; + router.add_route("/v1/peers/**", Box::new(peer_handler))?; + Ok(router) +} diff --git a/api/src/lib.rs b/api/src/lib.rs index cc3609adc..3ec57ba24 100644 --- a/api/src/lib.rs +++ b/api/src/lib.rs @@ -18,31 +18,34 @@ extern crate grin_p2p as p2p; extern crate grin_pool as pool; extern crate grin_store as store; extern crate grin_util as util; +extern crate url; extern crate failure; #[macro_use] extern crate failure_derive; extern crate hyper; -extern crate iron; #[macro_use] extern crate lazy_static; extern crate mount; extern crate regex; -#[macro_use] -extern crate router; extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; #[macro_use] extern crate slog; -extern crate urlencoded; +extern crate futures; +extern crate http; +extern crate tokio; +extern crate tokio_core; pub mod client; mod handlers; mod rest; +mod router; mod types; pub use handlers::start_rest_apis; pub use rest::*; +pub use router::*; pub use types::*; diff --git a/api/src/rest.rs b/api/src/rest.rs index a64fc40b8..3513474a9 100644 --- a/api/src/rest.rs +++ b/api/src/rest.rs @@ -18,20 +18,17 @@ //! To use it, just have your service(s) implement the ApiEndpoint trait and //! register them on a ApiServer. +use hyper::rt::Future; +use hyper::service::service_fn; +use hyper::{Body, Request, Server}; +use router::ResponseFuture; use std::fmt::{self, Display}; -use std::mem; -use std::net::ToSocketAddrs; -use std::string::ToString; +use std::net::SocketAddr; +use tokio::runtime::current_thread::Runtime; use failure::{Backtrace, Context, Fail}; -use iron::Listening; -use iron::middleware::Handler; -use iron::prelude::Iron; -use mount::Mount; -use router::Router; /// Errors that can be returned by an ApiEndpoint implementation. - #[derive(Debug)] pub struct Error { inner: Context, @@ -45,6 +42,10 @@ pub enum ErrorKind { Argument(String), #[fail(display = "Not found.")] NotFound, + #[fail(display = "Request error: {}", _0)] + RequestError(String), + #[fail(display = "ResponseError error: {}", _0)] + ResponseError(String), } impl Fail for Error { @@ -84,45 +85,37 @@ impl From> for Error { } /// HTTP server allowing the registration of ApiEndpoint implementations. -pub struct ApiServer { - root: String, - router: Router, - mount: Mount, - server_listener: Option, -} +pub struct ApiServer {} impl ApiServer { /// Creates a new ApiServer that will serve ApiEndpoint implementations /// under the root URL. - pub fn new(root: String) -> ApiServer { - ApiServer { - root: root, - router: Router::new(), - mount: Mount::new(), - server_listener: None, - } + pub fn new() -> ApiServer { + ApiServer {} } /// Starts the ApiServer at the provided address. - pub fn start(&mut self, addr: A) -> Result<(), String> { - // replace this value to satisfy borrow checker - let r = mem::replace(&mut self.router, Router::new()); - let mut m = mem::replace(&mut self.mount, Mount::new()); - m.mount("/", r); - let result = Iron::new(m).http(addr); - let return_value = result.as_ref().map(|_| ()).map_err(|e| e.to_string()); - self.server_listener = Some(result.unwrap()); - return_value + pub fn start(&mut self, addr: SocketAddr, f: &'static F) -> Result<(), String> + where + F: Fn(Request) -> ResponseFuture + Send + Sync + 'static, + { + let server = Server::bind(&addr) + .serve(move || service_fn(f)) + .map_err(|e| eprintln!("server error: {}", e)); + + let mut rt = Runtime::new().unwrap(); + if rt.block_on(server).is_err() { + return Err("tokio block_on error".to_owned()); + } + Ok(()) } /// Stops the API server pub fn stop(&mut self) { - let r = mem::replace(&mut self.server_listener, None); - r.unwrap().close().unwrap(); - } - - /// Registers an iron handler (via mount) - pub fn register_handler(&mut self, handler: H) -> &mut Mount { - self.mount.mount(&self.root, handler) + // TODO implement proper stop, the following method doesn't + // work for current_thread runtime. + // if let Some(rt) = self.rt.take() { + // rt.shutdown_now().wait().unwrap(); + // } } } diff --git a/api/src/router.rs b/api/src/router.rs new file mode 100644 index 000000000..49231d942 --- /dev/null +++ b/api/src/router.rs @@ -0,0 +1,309 @@ +use futures::future; +use hyper; +use hyper::rt::Future; +use hyper::{Body, Method, Request, Response, StatusCode}; +use std::collections::hash_map::DefaultHasher; +use std::hash::{Hash, Hasher}; +use std::sync::Arc; +use util::LOGGER; + +lazy_static! { + static ref WILDCARD_HASH: u64 = calculate_hash(&"*"); + static ref WILDCARD_STOP_HASH: u64 = calculate_hash(&"**"); +} + +pub type ResponseFuture = Box, Error = hyper::Error> + Send>; + +pub trait Handler { + fn get(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn post(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn put(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn patch(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn delete(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn head(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn options(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn trace(&self, _req: Request) -> ResponseFuture { + not_found() + } + + fn connect(&self, _req: Request) -> ResponseFuture { + not_found() + } +} +#[derive(Fail, Debug)] +pub enum RouterError { + #[fail(display = "Route already exists")] + RouteAlreadyExists, + #[fail(display = "Route not found")] + RouteNotFound, + #[fail(display = "Value not found")] + NoValue, +} + +#[derive(Clone)] +pub struct Router { + nodes: Vec, +} + +#[derive(Debug, Clone, Copy)] +struct NodeId(usize); + +const MAX_CHILDREN: usize = 16; + +type HandlerObj = Box; + +#[derive(Clone)] +struct Node { + key: u64, + value: Option>, + children: [NodeId; MAX_CHILDREN], + children_count: usize, +} + +impl Router { + pub fn new() -> Router { + let root = Node::new(calculate_hash(&""), None); + let mut nodes = vec![]; + nodes.push(root); + Router { nodes } + } + + fn root(&self) -> NodeId { + NodeId(0) + } + + fn node(&self, id: NodeId) -> &Node { + &self.nodes[id.0] + } + + fn node_mut(&mut self, id: NodeId) -> &mut Node { + &mut self.nodes[id.0] + } + + fn find(&self, parent: NodeId, key: u64) -> Option { + let node = self.node(parent); + node.children + .iter() + .find(|&id| { + let node_key = self.node(*id).key; + node_key == key || node_key == *WILDCARD_HASH || node_key == *WILDCARD_STOP_HASH + }) + .cloned() + } + + fn add_empty_node(&mut self, parent: NodeId, key: u64) -> NodeId { + let id = NodeId(self.nodes.len()); + self.nodes.push(Node::new(key, None)); + self.node_mut(parent).add_child(id); + id + } + + pub fn add_route(&mut self, route: &'static str, value: HandlerObj) -> Result<(), RouterError> { + let keys = generate_path(route); + let mut node_id = self.root(); + for key in keys { + node_id = self.find(node_id, key) + .unwrap_or_else(|| self.add_empty_node(node_id, key)); + } + match self.node(node_id).value() { + None => { + self.node_mut(node_id).set_value(value); + Ok(()) + } + Some(_) => Err(RouterError::RouteAlreadyExists), + } + } + + pub fn get(&self, path: &str) -> Result, RouterError> { + let keys = generate_path(path); + let mut node_id = self.root(); + for key in keys { + node_id = self.find(node_id, key).ok_or(RouterError::RouteNotFound)?; + if self.node(node_id).key == *WILDCARD_STOP_HASH { + debug!(LOGGER, "ROUTER stop card"); + break; + } + } + self.node(node_id).value().ok_or(RouterError::NoValue) + } + + pub fn handle(&self, req: Request) -> ResponseFuture { + match self.get(req.uri().path()) { + Err(_) => not_found(), + Ok(h) => match req.method() { + &Method::GET => h.get(req), + &Method::POST => h.post(req), + &Method::PUT => h.put(req), + &Method::DELETE => h.delete(req), + &Method::PATCH => h.patch(req), + &Method::OPTIONS => h.options(req), + &Method::CONNECT => h.connect(req), + &Method::TRACE => h.trace(req), + &Method::HEAD => h.head(req), + _ => not_found(), + }, + } + } +} + +impl Node { + fn new(key: u64, value: Option>) -> Node { + Node { + key, + value, + children: [NodeId(0); MAX_CHILDREN], + children_count: 0, + } + } + + fn value(&self) -> Option> { + match &self.value { + None => None, + Some(v) => Some(v.clone()), + } + } + + fn set_value(&mut self, value: HandlerObj) { + self.value = Some(Arc::new(value)); + } + + fn add_child(&mut self, child_id: NodeId) { + if self.children_count == MAX_CHILDREN { + panic!("Can't add a route, children limit exceeded"); + } + self.children[self.children_count] = child_id; + self.children_count += 1; + } +} + +pub fn not_found() -> ResponseFuture { + let mut response = Response::new(Body::empty()); + *response.status_mut() = StatusCode::NOT_FOUND; + Box::new(future::ok(response)) +} + +fn calculate_hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() +} + +fn generate_path(route: &str) -> Vec { + route + .split('/') + .skip(1) + .map(|path| calculate_hash(&path)) + .collect() +} + +#[cfg(test)] +mod tests { + + use super::*; + use tokio::prelude::future::ok; + use tokio_core::reactor::Core; + + struct HandlerImpl(u16); + + impl Handler for HandlerImpl { + fn get(&self, _req: Request) -> ResponseFuture { + Box::new(future::ok( + Response::builder() + .status(self.0) + .body(Body::default()) + .unwrap(), + )) + } + } + + #[test] + fn test_add_route() { + let mut routes = Router::new(); + routes + .add_route("/v1/users", Box::new(HandlerImpl(1))) + .unwrap(); + assert!( + routes + .add_route("/v1/users", Box::new(HandlerImpl(2))) + .is_err() + ); + routes + .add_route("/v1/users/xxx", Box::new(HandlerImpl(3))) + .unwrap(); + routes + .add_route("/v1/users/xxx/yyy", Box::new(HandlerImpl(3))) + .unwrap(); + routes + .add_route("/v1/zzz/*", Box::new(HandlerImpl(3))) + .unwrap(); + assert!( + routes + .add_route("/v1/zzz/ccc", Box::new(HandlerImpl(2))) + .is_err() + ); + routes + .add_route("/v1/zzz/*/zzz", Box::new(HandlerImpl(6))) + .unwrap(); + } + + #[test] + fn test_get() { + let mut routes = Router::new(); + routes + .add_route("/v1/users", Box::new(HandlerImpl(101))) + .unwrap(); + routes + .add_route("/v1/users/xxx", Box::new(HandlerImpl(103))) + .unwrap(); + routes + .add_route("/v1/users/xxx/yyy", Box::new(HandlerImpl(103))) + .unwrap(); + routes + .add_route("/v1/zzz/*", Box::new(HandlerImpl(103))) + .unwrap(); + routes + .add_route("/v1/zzz/*/zzz", Box::new(HandlerImpl(106))) + .unwrap(); + + let call_handler = |url| { + let mut event_loop = Core::new().unwrap(); + let task = routes + .get(url) + .unwrap() + .get(Request::new(Body::default())) + .and_then(|resp| ok(resp.status().as_u16())); + event_loop.run(task).unwrap() + }; + + assert_eq!(call_handler("/v1/users"), 101); + assert_eq!(call_handler("/v1/users/xxx"), 103); + assert!(routes.get("/v1/users/yyy").is_err()); + assert_eq!(call_handler("/v1/users/xxx/yyy"), 103); + assert!(routes.get("/v1/zzz").is_err()); + assert_eq!(call_handler("/v1/zzz/1"), 103); + assert_eq!(call_handler("/v1/zzz/2"), 103); + assert_eq!(call_handler("/v1/zzz/2/zzz"), 106); + } + +} diff --git a/p2p/src/peers.rs b/p2p/src/peers.rs index 60966e1ac..4d7499169 100644 --- a/p2p/src/peers.rs +++ b/p2p/src/peers.rs @@ -27,8 +27,10 @@ use util::LOGGER; use peer::Peer; use store::{PeerData, PeerStore, State}; -use types::{Capabilities, ChainAdapter, Direction, Error, NetAdapter, P2PConfig, ReasonForBan, - TxHashSetRead, MAX_PEER_ADDRS}; +use types::{ + Capabilities, ChainAdapter, Direction, Error, NetAdapter, P2PConfig, ReasonForBan, + TxHashSetRead, MAX_PEER_ADDRS, +}; pub struct Peers { pub adapter: Arc, @@ -615,17 +617,8 @@ impl ChainAdapter for Peers { self.adapter.txhashset_receive_ready() } - fn txhashset_write( - &self, - h: Hash, - txhashset_data: File, - peer_addr: SocketAddr, - ) -> bool { - if !self.adapter.txhashset_write( - h, - txhashset_data, - peer_addr, - ) { + fn txhashset_write(&self, h: Hash, txhashset_data: File, peer_addr: SocketAddr) -> bool { + if !self.adapter.txhashset_write(h, txhashset_data, peer_addr) { debug!( LOGGER, "Received a bad txhashset data from {}, the peer will be banned", &peer_addr diff --git a/p2p/src/protocol.rs b/p2p/src/protocol.rs index 715b5447f..91dc29bd4 100644 --- a/p2p/src/protocol.rs +++ b/p2p/src/protocol.rs @@ -20,8 +20,10 @@ use std::sync::Arc; use conn::{Message, MessageHandler, Response}; use core::core; use core::core::hash::{Hash, Hashed}; -use msg::{BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, SockAddr, - TxHashSetArchive, TxHashSetRequest, Type}; +use msg::{ + BanReason, GetPeerAddrs, Headers, Locator, PeerAddrs, Ping, Pong, SockAddr, TxHashSetArchive, + TxHashSetRequest, Type, +}; use rand::{self, Rng}; use types::{Error, NetAdapter}; use util::LOGGER; @@ -241,21 +243,19 @@ impl MessageHandler for Protocol { ); return Err(Error::BadMessage); } - let mut tmp = env::temp_dir(); tmp.push("txhashset.zip"); - let mut save_txhashset_to_file = |file| -> Result<(), Error> { + let mut save_txhashset_to_file = |file| -> Result<(), Error> { let mut tmp_zip = File::create(file)?; msg.copy_attachment(sm_arch.bytes as usize, &mut tmp_zip)?; tmp_zip.sync_all()?; Ok(()) }; - if let Err(e) = save_txhashset_to_file(tmp.clone()){ + if let Err(e) = save_txhashset_to_file(tmp.clone()) { error!( LOGGER, - "handle_payload: txhashset archive save to file fail. err={:?}", - e + "handle_payload: txhashset archive save to file fail. err={:?}", e ); return Err(e); } @@ -267,11 +267,8 @@ impl MessageHandler for Protocol { ); let tmp_zip = File::open(tmp)?; - let res = self.adapter.txhashset_write( - sm_arch.hash, - tmp_zip, - self.addr, - ); + let res = self.adapter + .txhashset_write(sm_arch.hash, tmp_zip, self.addr); debug!( LOGGER, diff --git a/p2p/src/serv.rs b/p2p/src/serv.rs index 57ecb0db2..40dc39c23 100644 --- a/p2p/src/serv.rs +++ b/p2p/src/serv.rs @@ -254,12 +254,7 @@ impl ChainAdapter for DummyAdapter { false } - fn txhashset_write( - &self, - _h: Hash, - _txhashset_data: File, - _peer_addr: SocketAddr, - ) -> bool { + fn txhashset_write(&self, _h: Hash, _txhashset_data: File, _peer_addr: SocketAddr) -> bool { false } } diff --git a/servers/Cargo.toml b/servers/Cargo.toml index 478aea6f1..d452ec879 100644 --- a/servers/Cargo.toml +++ b/servers/Cargo.toml @@ -6,11 +6,10 @@ workspace = ".." publish = false [dependencies] -hyper = "0.10" +hyper = "0.12" itertools = "0.7" lmdb-zero = "0.4.4" rand = "0.3" -router = "0.6" slog = { version = "~2.2", features = ["max_level_trace", "release_max_level_trace"] } serde = "1" serde_derive = "1" diff --git a/servers/src/grin/seed.rs b/servers/src/grin/seed.rs index d98fae8b6..f55509f3e 100644 --- a/servers/src/grin/seed.rs +++ b/servers/src/grin/seed.rs @@ -16,7 +16,6 @@ //! a mining worker implementation //! -use std::io::Read; use std::net::{SocketAddr, ToSocketAddrs}; use std::str; use std::sync::atomic::{AtomicBool, Ordering}; @@ -26,7 +25,7 @@ use std::time; use chrono::prelude::{Utc}; use chrono::Duration; -use hyper; +use api; use p2p; use pool::DandelionConfig; @@ -35,7 +34,7 @@ use util::LOGGER; const SEEDS_URL: &'static str = "http://grin-tech.org/seeds.txt"; // DNS Seeds with contact email associated const DNS_SEEDS: &'static [&'static str] = &[ - "t3.seed.grin-tech.org", // igno.peverell@protonmail.com + "t3.seed.grin-tech.org", // igno.peverell@protonmail.com ]; pub fn connect_and_monitor( @@ -268,22 +267,7 @@ pub fn dns_seeds() -> Box Vec + Send> { /// http. Easy method until we have a set of DNS names we can rely on. pub fn web_seeds() -> Box Vec + Send> { Box::new(|| { - let client = hyper::Client::new(); - debug!(LOGGER, "Retrieving seed nodes from {}", &SEEDS_URL); - - // http get, filtering out non 200 results - let mut res = client - .get(SEEDS_URL) - .send() - .expect("Failed to resolve seeds."); - if res.status != hyper::Ok { - panic!("Failed to resolve seeds, got status {}.", res.status); - } - let mut buf = vec![]; - res.read_to_end(&mut buf) - .expect("Could not read seed list."); - - let text = str::from_utf8(&buf[..]).expect("Corrupted seed list."); + let text: String = api::client::get(SEEDS_URL).expect("Failed to resolve seeds"); let addrs = text.split_whitespace() .map(|s| s.parse().unwrap()) .collect::>(); diff --git a/servers/tests/api.rs b/servers/tests/api.rs index 21ebbd776..5efef295b 100644 --- a/servers/tests/api.rs +++ b/servers/tests/api.rs @@ -188,15 +188,19 @@ fn test_p2p() { let base_addr = server_config_one.base_addr; let api_server_port = server_config_one.api_server_port; - // Check that when we get peer connected the peer is here - let peers_connected = get_connected_peers(&base_addr, api_server_port); - assert!(peers_connected.is_ok()); - assert_eq!(peers_connected.unwrap().len(), 1); - // Check that peer all is also working let mut peers_all = get_all_peers(&base_addr, api_server_port); assert!(peers_all.is_ok()); - assert_eq!(peers_all.unwrap().len(), 1); + let pall = peers_all.unwrap(); + println!("Peers: {:?}", &pall); + assert_eq!(pall.len(), 1); + + // Check that when we get peer connected the peer is here + let peers_connected = get_connected_peers(&base_addr, api_server_port); + assert!(peers_connected.is_ok()); + let pc = peers_connected.unwrap(); + println!("Peers connected: {:?}", &pc); + assert_eq!(pc.len(), 1); // Check that the peer status is Healthy let addr = format!( @@ -431,7 +435,7 @@ pub fn ban_peer(base_addr: &String, api_server_port: u16, peer_addr: &String) -> "http://{}:{}/v1/peers/{}/ban", base_addr, api_server_port, peer_addr ); - api::client::post(url.as_str(), &"").map_err(|e| Error::API(e)) + api::client::post_no_ret(url.as_str(), &"").map_err(|e| Error::API(e)) } pub fn unban_peer( @@ -443,7 +447,7 @@ pub fn unban_peer( "http://{}:{}/v1/peers/{}/unban", base_addr, api_server_port, peer_addr ); - api::client::post(url.as_str(), &"").map_err(|e| Error::API(e)) + api::client::post_no_ret(url.as_str(), &"").map_err(|e| Error::API(e)) } pub fn get_peer( @@ -455,7 +459,10 @@ pub fn get_peer( "http://{}:{}/v1/peers/{}", base_addr, api_server_port, peer_addr ); - api::client::get::(url.as_str()).map_err(|e| Error::API(e)) + api::client::get::(url.as_str()).map_err(|e| { + println!("got error {:}", e); + Error::API(e) + }) } pub fn get_connected_peers( diff --git a/servers/tests/dandelion.rs b/servers/tests/dandelion.rs index 937c12086..1e24a404c 100644 --- a/servers/tests/dandelion.rs +++ b/servers/tests/dandelion.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate router; #[macro_use] extern crate slog; diff --git a/servers/tests/framework/mod.rs b/servers/tests/framework/mod.rs index f3c18cfb4..4db11eec7 100644 --- a/servers/tests/framework/mod.rs +++ b/servers/tests/framework/mod.rs @@ -337,30 +337,27 @@ impl LocalServerContainer { .unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config)); wallet.keychain = Some(keychain); let _ = - wallet::controller::owner_single_use( - Arc::new(Mutex::new(Box::new(wallet))), - |api| { - let result = api.issue_send_tx( - amount, - minimum_confirmations, + wallet::controller::owner_single_use(Arc::new(Mutex::new(Box::new(wallet))), |api| { + let result = api.issue_send_tx( + amount, + minimum_confirmations, + dest, + max_outputs, + selection_strategy == "all", + ); + match result { + Ok(_) => println!( + "Tx sent: {} grin to {} (strategy '{}')", + core::core::amount_to_hr_string(amount), dest, - max_outputs, - selection_strategy == "all", - ); - match result { - Ok(_) => println!( - "Tx sent: {} grin to {} (strategy '{}')", - core::core::amount_to_hr_string(amount), - dest, - selection_strategy, - ), - Err(e) => { - println!("Tx not sent to {}: {:?}", dest, e); - } - }; - Ok(()) - }, - ).unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config)); + selection_strategy, + ), + Err(e) => { + println!("Tx not sent to {}: {:?}", dest, e); + } + }; + Ok(()) + }).unwrap_or_else(|e| panic!("Error creating wallet: {:?} Config: {:?}", e, config)); } /// Stops the running wallet server diff --git a/servers/tests/wallet.rs b/servers/tests/wallet.rs index c0fdd59f5..884bbc17a 100644 --- a/servers/tests/wallet.rs +++ b/servers/tests/wallet.rs @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -extern crate router; #[macro_use] extern crate slog; @@ -59,7 +58,6 @@ fn basic_wallet_transactions() { let coinbase_wallet_config = { coinbase_wallet.lock().unwrap().wallet_config.clone() }; let coinbase_seed = LocalServerContainer::get_wallet_seed(&coinbase_wallet_config); - let _ = thread::spawn(move || { let mut w = coinbase_wallet.lock().unwrap(); w.run_wallet(0); @@ -72,7 +70,6 @@ fn basic_wallet_transactions() { let target_wallet = Arc::new(Mutex::new(LocalServerContainer::new(recp_config).unwrap())); let target_wallet_cloned = target_wallet.clone(); let recp_wallet_config = { target_wallet.lock().unwrap().wallet_config.clone() }; - let recp_seed = LocalServerContainer::get_wallet_seed(&recp_wallet_config); //Start up a second wallet, to receive let _ = thread::spawn(move || { @@ -80,16 +77,16 @@ fn basic_wallet_transactions() { w.run_wallet(0); }); + let mut server_config = LocalServerContainerConfig::default(); + server_config.name = String::from("server_one"); + server_config.p2p_server_port = 30000; + server_config.api_server_port = 30001; + server_config.start_miner = true; + server_config.start_wallet = false; + server_config.coinbase_wallet_address = + String::from(format!("http://{}:{}", server_config.base_addr, 10002)); // Spawn server and let it run for a bit let _ = thread::spawn(move || { - let mut server_config = LocalServerContainerConfig::default(); - server_config.name = String::from("server_one"); - server_config.p2p_server_port = 30000; - server_config.api_server_port = 30001; - server_config.start_miner = true; - server_config.start_wallet = false; - server_config.coinbase_wallet_address = - String::from(format!("http://{}:{}", server_config.base_addr, 10002)); let mut server_one = LocalServerContainer::new(server_config).unwrap(); server_one.run_server(120); }); diff --git a/src/bin/client.rs b/src/bin/client.rs index 2e6187cd7..4d0bc99c7 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -56,7 +56,7 @@ pub fn ban_peer(config: &ServerConfig, peer_addr: &SocketAddr) { config.api_http_addr, peer_addr.to_string() ); - match api::client::post(url.as_str(), ¶ms).map_err(|e| Error::API(e)) { + match api::client::post_no_ret(url.as_str(), ¶ms).map_err(|e| Error::API(e)) { Ok(_) => writeln!(e, "Successfully banned peer {}", peer_addr.to_string()).unwrap(), Err(_) => writeln!(e, "Failed to ban peer {}", peer_addr).unwrap(), }; @@ -71,7 +71,7 @@ pub fn unban_peer(config: &ServerConfig, peer_addr: &SocketAddr) { config.api_http_addr, peer_addr.to_string() ); - match api::client::post(url.as_str(), ¶ms).map_err(|e| Error::API(e)) { + match api::client::post_no_ret(url.as_str(), ¶ms).map_err(|e| Error::API(e)) { Ok(_) => writeln!(e, "Successfully unbanned peer {}", peer_addr).unwrap(), Err(_) => writeln!(e, "Failed to unban peer {}", peer_addr).unwrap(), }; diff --git a/wallet/Cargo.toml b/wallet/Cargo.toml index d217cf7b6..c1bc9695e 100644 --- a/wallet/Cargo.toml +++ b/wallet/Cargo.toml @@ -12,20 +12,19 @@ byteorder = "1" failure = "0.1" failure_derive = "0.1" futures = "0.1" -hyper = "0.11" -iron = "0.5" +hyper = "0.12" prettytable-rs = "0.7" rand = "0.3" -router = "0.5" serde = "1" serde_derive = "1" serde_json = "1" slog = { version = "~2.2", features = ["max_level_trace", "release_max_level_trace"] } term = "0.5" +tokio = "0.1.7" tokio-core = "0.1" tokio-retry = "0.1" uuid = { version = "0.6", features = ["serde", "v4"] } -urlencoded = "0.5" +url = "1.7.0" chrono = { version = "0.4.4", features = ["serde"] } grin_api = { path = "../api" } diff --git a/wallet/src/client.rs b/wallet/src/client.rs index 8be5433fe..e1b178c33 100644 --- a/wallet/src/client.rs +++ b/wallet/src/client.rs @@ -18,13 +18,6 @@ use failure::ResultExt; use libwallet::types::*; use std::collections::HashMap; -use std::io; - -use futures::{Future, Stream}; -use hyper::header::ContentType; -use hyper::{self, Method, Request}; -use serde_json; -use tokio_core::reactor; use api; use error::{Error, ErrorKind}; @@ -90,38 +83,9 @@ impl WalletClient for HTTPWalletClient { let url = format!("{}/v1/wallet/foreign/receive_tx", dest); debug!(LOGGER, "Posting transaction slate to {}", url); - let mut core = reactor::Core::new().context(libwallet::ErrorKind::ClientCallback( - "Sending transaction: Initialise API", - ))?; - let client = hyper::Client::new(&core.handle()); - - let url_pool = url.to_owned(); - - let mut req = Request::new( - Method::Post, - url_pool - .parse::() - .context(libwallet::ErrorKind::ClientCallback( - "Sending transaction: parsing URL", - ))?, - ); - req.headers_mut().set(ContentType::json()); - let json = serde_json::to_string(&slate).context(libwallet::ErrorKind::ClientCallback( - "Sending transaction: parsing response", - ))?; - req.set_body(json); - - let work = client.request(req).and_then(|res| { - res.body().concat2().and_then(move |body| { - let slate: Slate = serde_json::from_slice(&body) - .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - Ok(slate) - }) - }); - let res = core.run(work) - .context(libwallet::ErrorKind::ClientCallback( - "Sending transaction: posting request", - ))?; + let res = api::client::post(url.as_str(), slate).context( + libwallet::ErrorKind::ClientCallback("Posting transaction slate"), + )?; Ok(res) } @@ -134,7 +98,7 @@ impl WalletClient for HTTPWalletClient { } else { url = format!("{}/v1/pool/push", dest); } - api::client::post(url.as_str(), tx).context(libwallet::ErrorKind::ClientCallback( + api::client::post_no_ret(url.as_str(), tx).context(libwallet::ErrorKind::ClientCallback( "Posting transaction to node", ))?; Ok(()) @@ -247,30 +211,8 @@ pub fn create_coinbase(dest: &str, block_fees: &BlockFees) -> Result Result { - let mut core = reactor::Core::new().context(ErrorKind::GenericError( - "Could not create reactor".to_owned(), + let res = api::client::post(url, block_fees).context(ErrorKind::GenericError( + "Posting create coinbase".to_string(), ))?; - let client = hyper::Client::new(&core.handle()); - - let mut req = Request::new( - Method::Post, - url.parse::().context(ErrorKind::Uri)?, - ); - req.headers_mut().set(ContentType::json()); - let json = serde_json::to_string(&block_fees).context(ErrorKind::Format)?; - trace!(LOGGER, "Sending coinbase request: {:?}", json); - req.set_body(json); - - let work = client.request(req).and_then(|res| { - res.body().concat2().and_then(move |body| { - trace!(LOGGER, "Returned Body: {:?}", body); - let coinbase: CbData = - serde_json::from_slice(&body).map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; - Ok(coinbase) - }) - }); - - let res = core.run(work) - .context(ErrorKind::GenericError("Could not run core".to_owned()))?; Ok(res) } diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index febd87687..d0735caf5 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -27,7 +27,7 @@ extern crate serde_json; extern crate slog; extern crate chrono; extern crate term; -extern crate urlencoded; +extern crate url; extern crate uuid; extern crate bodyparser; @@ -36,9 +36,7 @@ extern crate failure; extern crate failure_derive; extern crate futures; extern crate hyper; -extern crate iron; -#[macro_use] -extern crate router; +extern crate tokio; extern crate tokio_core; extern crate tokio_retry; diff --git a/wallet/src/libwallet/controller.rs b/wallet/src/libwallet/controller.rs index 11d5abd77..3d77e82ec 100644 --- a/wallet/src/libwallet/controller.rs +++ b/wallet/src/libwallet/controller.rs @@ -15,18 +15,18 @@ //! Controller for wallet.. instantiates and handles listeners (or single-run //! invocations) as needed. //! Still experimental -use api::ApiServer; +use api::{ApiServer, Handler, ResponseFuture, Router}; +use std::cell::RefCell; +use std::collections::HashMap; use std::marker::PhantomData; +use std::net::SocketAddr; use std::sync::{Arc, Mutex}; -use bodyparser; -use iron::prelude::{IronError, IronResult, Plugin, Request, Response}; -use iron::{status, Handler, Headers}; -use serde::Serialize; +use futures::future::{err, ok}; +use futures::{Future, Stream}; +use hyper::{Body, Request, Response, StatusCode}; +use serde::{Deserialize, Serialize}; use serde_json; -use urlencoded::UrlEncodedQuery; - -use failure::Fail; use keychain::Keychain; use libtx::slate::Slate; @@ -35,6 +35,7 @@ use libwallet::types::{ BlockFees, CbData, OutputData, SendTXArgs, TxLogEntry, WalletBackend, WalletClient, WalletInfo, }; use libwallet::{Error, ErrorKind}; +use url::form_urlencoded; use util::LOGGER; @@ -64,72 +65,102 @@ where Ok(()) } +thread_local!(static OWNER_ROUTER: RefCell> = RefCell::new(None)); + /// Listener version, providing same API but listening for requests on a /// port and wrapping the calls pub fn owner_listener(wallet: Box, addr: &str) -> Result<(), Error> where - T: WalletBackend, - OwnerAPIGetHandler: Handler, - OwnerAPIPostHandler: Handler, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + OwnerAPIHandler: Handler, + C: WalletClient + 'static, + K: Keychain + 'static, { let wallet_arc = Arc::new(Mutex::new(wallet)); - let api_get_handler = OwnerAPIGetHandler::new(wallet_arc.clone()); - let api_post_handler = OwnerAPIPostHandler::new(wallet_arc); - let api_options_handler = OwnerAPIOptionsHandler {}; + let api_handler = OwnerAPIHandler::new(wallet_arc); - let router = router!( - owner_options: options "/wallet/owner/*" => api_options_handler, - owner_get: get "/wallet/owner/*" => api_get_handler, - owner_post: post "/wallet/owner/*" => api_post_handler, - ); + let mut orouter = Router::new(); + orouter + .add_route("/v1/wallet/owner/**", Box::new(api_handler)) + .map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?; - let mut apis = ApiServer::new("/v1".to_string()); - apis.register_handler(router); - match apis.start(addr) { - Err(e) => error!( - LOGGER, - "Failed to start Grin wallet owner API listener: {}.", e - ), - Ok(_) => info!(LOGGER, "Grin wallet owner API listener started at {}", addr), - }; + OWNER_ROUTER.with(move |router| { + *router.borrow_mut() = Some(orouter); + let mut apis = ApiServer::new(); + info!(LOGGER, "Starting HTTP Owner API server at {}.", addr); + let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address"); + apis.start(socket_addr, &handle_owner).unwrap_or_else(|e| { + error!(LOGGER, "Failed to start API HTTP server: {}.", e); + }) + }); Ok(()) } +fn handle_owner(req: Request) -> ResponseFuture { + OWNER_ROUTER.with(|router| match *router.borrow() { + Some(ref h) => h.handle(req), + None => { + error!(LOGGER, "No HTTP API router configured"); + Box::new(ok(response( + StatusCode::INTERNAL_SERVER_ERROR, + "No router configured", + ))) + } + }) +} + +thread_local!(static FOREIGN_ROUTER: RefCell> = RefCell::new(None)); + /// Listener version, providing same API but listening for requests on a /// port and wrapping the calls pub fn foreign_listener(wallet: Box, addr: &str) -> Result<(), Error> where - T: WalletBackend, - ForeignAPIHandler: Handler, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + C: WalletClient + 'static, + K: Keychain + 'static, { let api_handler = ForeignAPIHandler::new(Arc::new(Mutex::new(wallet))); - let router = router!( - receive_tx: post "/wallet/foreign/*" => api_handler, - ); + let mut router = Router::new(); + router + .add_route("/v1/wallet/foreign/**", Box::new(api_handler)) + .map_err(|_| ErrorKind::GenericError("Router failed to add route".to_string()))?; + + FOREIGN_ROUTER.with(move |frouter| { + *frouter.borrow_mut() = Some(router); + let mut apis = ApiServer::new(); + info!(LOGGER, "Starting HTTP Foreign API server at {}.", addr); + let socket_addr: SocketAddr = addr.parse().expect("unable to parse socket address"); + apis.start(socket_addr, &handle_foreign) + .unwrap_or_else(|e| { + error!(LOGGER, "Failed to start API HTTP server: {}.", e); + }); + }); - let mut apis = ApiServer::new("/v1".to_string()); - apis.register_handler(router); - match apis.start(addr) { - Err(e) => error!( - LOGGER, - "Failed to start Grin wallet foreign listener: {}.", e - ), - Ok(_) => info!(LOGGER, "Grin wallet foreign listener started at {}", addr), - }; Ok(()) } -/// API Handler/Wrapper for owner functions -pub struct OwnerAPIGetHandler +fn handle_foreign(req: Request) -> ResponseFuture { + FOREIGN_ROUTER.with(|router| match *router.borrow() { + Some(ref h) => h.handle(req), + None => { + error!(LOGGER, "No HTTP API router configured"); + Box::new(ok(response( + StatusCode::INTERNAL_SERVER_ERROR, + "No router configured", + ))) + } + }) +} + +type WalletResponseFuture = Box, Error = Error> + Send>; + +/// API Handler/Wrapper for owner functions +pub struct OwnerAPIHandler where - T: WalletBackend, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + C: WalletClient + 'static, + K: Keychain + 'static, { /// Wallet instance pub wallet: Arc>>, @@ -137,15 +168,15 @@ where phantom_c: PhantomData, } -impl OwnerAPIGetHandler +impl OwnerAPIHandler where - T: WalletBackend, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + C: WalletClient + 'static, + K: Keychain + 'static, { /// Create a new owner API handler for GET methods - pub fn new(wallet: Arc>>) -> OwnerAPIGetHandler { - OwnerAPIGetHandler { + pub fn new(wallet: Arc>>) -> OwnerAPIHandler { + OwnerAPIHandler { wallet, phantom: PhantomData, phantom_c: PhantomData, @@ -154,23 +185,23 @@ where fn retrieve_outputs( &self, - req: &mut Request, - api: &mut APIOwner, + req: &Request, + api: APIOwner, ) -> Result<(bool, Vec), Error> { let mut update_from_node = false; let mut id = None; let mut show_spent = false; - if let Ok(params) = req.get_ref::() { - if let Some(_) = params.get("refresh") { - update_from_node = true; - } - if let Some(_) = params.get("show_spent") { - show_spent = true; - } - if let Some(ids) = params.get("tx_id") { - for i in ids { - id = Some(i.parse().unwrap()); - } + let params = parse_params(req); + + if let Some(_) = params.get("refresh") { + update_from_node = true; + } + if let Some(_) = params.get("show_spent") { + show_spent = true; + } + if let Some(ids) = params.get("tx_id") { + for i in ids { + id = Some(i.parse().unwrap()); } } api.retrieve_outputs(show_spent, update_from_node, id) @@ -178,19 +209,20 @@ where fn retrieve_txs( &self, - req: &mut Request, - api: &mut APIOwner, + req: &Request, + api: APIOwner, ) -> Result<(bool, Vec), Error> { let mut id = None; let mut update_from_node = false; - if let Ok(params) = req.get_ref::() { - if let Some(_) = params.get("refresh") { - update_from_node = true; - } - if let Some(ids) = params.get("id") { - for i in ids { - id = Some(i.parse().unwrap()); - } + + let params = parse_params(req); + + if let Some(_) = params.get("refresh") { + update_from_node = true; + } + if let Some(ids) = params.get("id") { + for i in ids { + id = Some(i.parse().unwrap()); } } api.retrieve_txs(update_from_node, id) @@ -198,212 +230,129 @@ where fn retrieve_summary_info( &self, - req: &mut Request, - api: &mut APIOwner, + req: &Request, + mut api: APIOwner, ) -> Result<(bool, WalletInfo), Error> { - let mut update_from_node = false; - if let Ok(params) = req.get_ref::() { - if let Some(_) = params.get("refresh") { - update_from_node = true; - } - } + let update_from_node = param_exists(req, "refresh"); api.retrieve_summary_info(update_from_node) } fn node_height( &self, - _req: &mut Request, - api: &mut APIOwner, + _req: &Request, + mut api: APIOwner, ) -> Result<(u64, bool), Error> { api.node_height() } - fn handle_request( - &self, - req: &mut Request, - api: &mut APIOwner, - ) -> IronResult { - let url = req.url.clone(); - let path_elems = url.path(); - match *path_elems.last().unwrap() { - "retrieve_outputs" => json_response(&self.retrieve_outputs(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - "retrieve_txs" => json_response(&self.retrieve_txs(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - "retrieve_summary_info" => json_response(&self.retrieve_summary_info(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - "node_height" => json_response(&self.node_height(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - _ => Err(IronError::new( - Fail::compat(ErrorKind::Hyper), - status::BadRequest, - )), - } - } -} - -impl Handler for OwnerAPIGetHandler -where - T: WalletBackend + Send + Sync + 'static, - C: WalletClient + 'static, - K: Keychain + 'static, -{ - fn handle(&self, req: &mut Request) -> IronResult { - let mut api = APIOwner::new(self.wallet.clone()); - let mut resp_json = self.handle_request(req, &mut api); - if !resp_json.is_err() { - resp_json - .as_mut() - .unwrap() - .headers - .set_raw("access-control-allow-origin", vec![b"*".to_vec()]); - } - resp_json - } -} - -/// Handles all owner API POST requests -pub struct OwnerAPIPostHandler -where - T: WalletBackend, - C: WalletClient, - K: Keychain, -{ - /// Wallet instance - pub wallet: Arc>>, - phantom: PhantomData, - phantom_c: PhantomData, -} - -impl OwnerAPIPostHandler -where - T: WalletBackend, - C: WalletClient, - K: Keychain, -{ - /// New POST handler - pub fn new(wallet: Arc>>) -> OwnerAPIPostHandler { - OwnerAPIPostHandler { - wallet, - phantom: PhantomData, - phantom_c: PhantomData, - } + fn handle_get_request(&self, req: &Request) -> Result, Error> { + let api = APIOwner::new(self.wallet.clone()); + Ok(match req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + { + "retrieve_outputs" => json_response(&self.retrieve_outputs(req, api)?), + "retrieve_summary_info" => json_response(&self.retrieve_summary_info(req, api)?), + "node_height" => json_response(&self.node_height(req, api)?), + "retrieve_txs" => json_response(&self.retrieve_txs(req, api)?), + _ => response(StatusCode::BAD_REQUEST, ""), + }) } fn issue_send_tx( &self, - req: &mut Request, - api: &mut APIOwner, - ) -> Result { - let struct_body = req.get::>(); - match struct_body { - Ok(Some(args)) => api.issue_send_tx( + req: Request, + mut api: APIOwner, + ) -> Box + Send> { + Box::new(parse_body(req).and_then(move |args: SendTXArgs| { + api.issue_send_tx( args.amount, args.minimum_confirmations, &args.dest, args.max_outputs, args.selection_strategy_is_use_all, - ), - Ok(None) => { - error!(LOGGER, "Missing request body: issue_send_tx"); - Err(ErrorKind::GenericError( - "Invalid request body: issue_send_tx".to_owned(), - ))? - } - Err(e) => { - error!(LOGGER, "Invalid request body: issue_send_tx {:?}", e); - Err(ErrorKind::GenericError( - "Invalid request body: issue_send_tx".to_owned(), - ))? - } - } + ) + })) } - fn issue_burn_tx(&self, _req: &mut Request, api: &mut APIOwner) -> Result<(), Error> { - // TODO: Args - api.issue_burn_tx(60, 10, 1000) - } - - fn handle_request( + fn issue_burn_tx( &self, - req: &mut Request, - api: &mut APIOwner, - ) -> Result { - let url = req.url.clone(); - let path_elems = url.path(); - match *path_elems.last().unwrap() { - "issue_send_tx" => json_response_pretty(&self.issue_send_tx(req, api)?), - "issue_burn_tx" => json_response_pretty(&self.issue_burn_tx(req, api)?), - _ => Err(ErrorKind::GenericError( + _req: Request, + mut api: APIOwner, + ) -> Box + Send> { + // TODO: Args + Box::new(match api.issue_burn_tx(60, 10, 1000) { + Ok(_) => ok(()), + Err(e) => err(e), + }) + } + + fn handle_post_request(&self, req: Request) -> WalletResponseFuture { + let api = APIOwner::new(self.wallet.clone()); + match req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + { + "issue_send_tx" => Box::new( + self.issue_send_tx(req, api) + .and_then(|slate| ok(json_response_pretty(&slate))), + ), + "issue_burn_tx" => Box::new( + self.issue_burn_tx(req, api) + .and_then(|_| ok(response(StatusCode::OK, ""))), + ), + _ => Box::new(err(ErrorKind::GenericError( "Unknown error handling post request".to_owned(), - ))?, + ).into())), } } - - fn create_error_response(&self, e: Error) -> IronResult { - let mut headers = Headers::new(); - headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]); - headers.set_raw( - "access-control-allow-headers", - vec![b"Content-Type".to_vec()], - ); - let message = format!("{}", e.kind()); - let mut r = Response::with((status::InternalServerError, message)); - r.headers = headers; - Ok(r) - } - - fn create_ok_response(&self, json: &str) -> IronResult { - let mut headers = Headers::new(); - headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]); - let mut r = Response::with((status::Ok, json)); - r.headers = headers; - Ok(r) - } } -impl Handler for OwnerAPIPostHandler +impl Handler for OwnerAPIHandler where T: WalletBackend + Send + Sync + 'static, C: WalletClient + 'static, K: Keychain + 'static, { - fn handle(&self, req: &mut Request) -> IronResult { - let mut api = APIOwner::new(self.wallet.clone()); - let resp = match self.handle_request(req, &mut api) { - Ok(r) => self.create_ok_response(&r), + fn get(&self, req: Request) -> ResponseFuture { + match self.handle_get_request(&req) { + Ok(r) => Box::new(ok(r)), Err(e) => { error!(LOGGER, "Request Error: {:?}", e); - self.create_error_response(e) + Box::new(ok(create_error_response(e))) } - }; - resp + } + } + + fn post(&self, req: Request) -> ResponseFuture { + Box::new( + self.handle_post_request(req) + .and_then(|r| ok(r)) + .or_else(|e| { + error!(LOGGER, "Request Error: {:?}", e); + ok(create_error_response(e)) + }), + ) + } + + fn options(&self, _req: Request) -> ResponseFuture { + Box::new(ok(create_ok_response("{}"))) } } -/// Options handler -pub struct OwnerAPIOptionsHandler {} - -impl Handler for OwnerAPIOptionsHandler where { - fn handle(&self, _req: &mut Request) -> IronResult { - let mut resp_json = Ok(Response::with((status::Ok, "{}"))); - let mut headers = Headers::new(); - headers.set_raw("access-control-allow-origin", vec![b"*".to_vec()]); - headers.set_raw( - "access-control-allow-headers", - vec![b"Content-Type".to_vec()], - ); - resp_json.as_mut().unwrap().headers = headers; - resp_json - } -} /// API Handler/Wrapper for foreign functions pub struct ForeignAPIHandler where - T: WalletBackend, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + C: WalletClient + 'static, + K: Keychain + 'static, { /// Wallet instance pub wallet: Arc>>, @@ -413,9 +362,9 @@ where impl ForeignAPIHandler where - T: WalletBackend, - C: WalletClient, - K: Keychain, + T: WalletBackend + Send + Sync + 'static, + C: WalletClient + 'static, + K: Keychain + 'static, { /// create a new api handler pub fn new(wallet: Arc>>) -> ForeignAPIHandler { @@ -428,55 +377,43 @@ where fn build_coinbase( &self, - req: &mut Request, - api: &mut APIForeign, - ) -> Result { - let struct_body = req.get::>(); - match struct_body { - Ok(Some(block_fees)) => api.build_coinbase(&block_fees), - Ok(None) => { - error!(LOGGER, "Missing request body: build_coinbase"); - Err(ErrorKind::GenericError( - "Invalid request body: build_coinbase".to_owned(), - ))? - } - Err(e) => { - error!(LOGGER, "Invalid request body: build_coinbase: {:?}", e); - Err(ErrorKind::GenericError( - "Invalid request body: build_coinbase".to_owned(), - ))? - } - } + req: Request, + mut api: APIForeign, + ) -> Box + Send> { + Box::new(parse_body(req).and_then(move |block_fees| api.build_coinbase(&block_fees))) } - fn receive_tx(&self, req: &mut Request, api: &mut APIForeign) -> Result { - let struct_body = req.get::>(); - if let Ok(Some(mut slate)) = struct_body { - api.receive_tx(&mut slate)?; - Ok(slate.clone()) - } else { - Err(ErrorKind::GenericError( - "Invalid request body: receive_tx".to_owned(), - ))? - } - } - - fn handle_request( + fn receive_tx( &self, - req: &mut Request, - api: &mut APIForeign, - ) -> IronResult { - let url = req.url.clone(); - let path_elems = url.path(); - match *path_elems.last().unwrap() { - "build_coinbase" => json_response(&self.build_coinbase(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - "receive_tx" => json_response(&self.receive_tx(req, api) - .map_err(|e| IronError::new(Fail::compat(e), status::BadRequest))?), - _ => Err(IronError::new( - Fail::compat(ErrorKind::Hyper), - status::BadRequest, - )), + req: Request, + mut api: APIForeign, + ) -> Box + Send> { + Box::new( + parse_body(req).and_then(move |mut slate| match api.receive_tx(&mut slate) { + Ok(_) => ok(slate.clone()), + Err(e) => err(e), + }), + ) + } + + fn handle_request(&self, req: Request) -> WalletResponseFuture { + let api = *APIForeign::new(self.wallet.clone()); + match req.uri() + .path() + .trim_right_matches("/") + .rsplit("/") + .next() + .unwrap() + { + "build_coinbase" => Box::new( + self.build_coinbase(req, api) + .and_then(|res| ok(json_response(&res))), + ), + "receive_tx" => Box::new( + self.receive_tx(req, api) + .and_then(|res| ok(json_response(&res))), + ), + _ => Box::new(ok(response(StatusCode::BAD_REQUEST, "unknown action"))), } } } @@ -486,32 +423,92 @@ where C: WalletClient + Send + Sync + 'static, K: Keychain + 'static, { - fn handle(&self, req: &mut Request) -> IronResult { - let mut api = APIForeign::new(self.wallet.clone()); - let resp_json = self.handle_request(req, &mut *api); - resp_json + fn post(&self, req: Request) -> ResponseFuture { + Box::new(self.handle_request(req).and_then(|r| ok(r)).or_else(|e| { + error!(LOGGER, "Request Error: {:?}", e); + ok(create_error_response(e)) + })) } } -// Utility to serialize a struct into JSON and produce a sensible IronResult +// Utility to serialize a struct into JSON and produce a sensible Response // out of it. -fn json_response(s: &T) -> IronResult +fn json_response(s: &T) -> Response where T: Serialize, { match serde_json::to_string(s) { - Ok(json) => Ok(Response::with((status::Ok, json))), - Err(_) => Ok(Response::with((status::InternalServerError, ""))), + Ok(json) => response(StatusCode::OK, json), + Err(_) => response(StatusCode::INTERNAL_SERVER_ERROR, ""), } } // pretty-printed version of above -fn json_response_pretty(s: &T) -> Result +fn json_response_pretty(s: &T) -> Response where T: Serialize, { match serde_json::to_string_pretty(s) { - Ok(json) => Ok(json), - Err(_) => Err(ErrorKind::Format)?, + Ok(json) => response(StatusCode::OK, json), + Err(_) => response(StatusCode::INTERNAL_SERVER_ERROR, ""), } } + +fn create_error_response(e: Error) -> Response { + Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .header("access-control-allow-origin", "*") + .header("access-control-allow-headers", "Content-Type") + .body(format!("{}", e.kind()).into()) + .unwrap() +} + +fn create_ok_response(json: &str) -> Response { + Response::builder() + .status(StatusCode::OK) + .header("access-control-allow-origin", "*") + .body(json.to_string().into()) + .unwrap() +} + +fn response>(status: StatusCode, text: T) -> Response { + Response::builder() + .status(status) + .header("access-control-allow-origin", "*") + .body(text.into()) + .unwrap() + //let mut resp = Response::new(text.into()); + //*resp.status_mut() = status; + //resp +} + +fn parse_params(req: &Request) -> HashMap> { + match req.uri().query() { + Some(query_string) => form_urlencoded::parse(query_string.as_bytes()) + .into_owned() + .fold(HashMap::new(), |mut hm, (k, v)| { + hm.entry(k).or_insert(vec![]).push(v); + hm + }), + None => HashMap::new(), + } +} + +fn param_exists(req: &Request, param: &str) -> bool { + parse_params(req).get(param).is_some() +} + +fn parse_body(req: Request) -> Box + Send> +where + for<'de> T: Deserialize<'de> + Send + 'static, +{ + Box::new( + req.into_body() + .concat2() + .map_err(|_| ErrorKind::GenericError("Failed to read request".to_owned()).into()) + .and_then(|body| match serde_json::from_reader(&body.to_vec()[..]) { + Ok(obj) => ok(obj), + Err(_) => err(ErrorKind::GenericError("Invalid request body".to_owned()).into()), + }), + ) +}