Skip to content

Commit

Permalink
refactor(server): move host filtering to tower middleware (#1179)
Browse files Browse the repository at this point in the history
* refactor: move host filtering to tower middleware

* fix tests

* commit missing file

* fix match on authority

* add some tests for authority

* grumbles: Arc<WhitelistedHosts>

* grumbles: split host filter code

* add example for host filter middleware

* Update examples/examples/host_filter_middleware.rs

* url.rs -> middleware/authority.rs
  • Loading branch information
niklasad1 committed Aug 11, 2023
1 parent 55010af commit 119d3ae
Show file tree
Hide file tree
Showing 18 changed files with 443 additions and 240 deletions.
2 changes: 1 addition & 1 deletion client/http-client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ where
let mut failed_calls = 0;

for _ in 0..json_rps.len() {
responses.push(Err(ErrorObject::borrowed(0, &"", None)));
responses.push(Err(ErrorObject::borrowed(0, "", None)));
}

for rp in json_rps {
Expand Down
5 changes: 1 addition & 4 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,20 @@ parking_lot = { version = "0.12", optional = true }
tokio = { version = "1.16", optional = true }
wasm-bindgen-futures = { version = "0.4.19", optional = true }
futures-timer = { version = "3", optional = true }
route-recognizer = { version = "0.3.1", optional = true }
http = { version = "0.2.9", optional = true }


[features]
default = []
http-helpers = ["hyper", "futures-util"]
server = [
"futures-util/alloc",
"route-recognizer",
"rustc-hash/std",
"parking_lot",
"rand",
"tokio/rt",
"tokio/sync",
"tokio/macros",
"tokio/time",
"http",
]
client = ["futures-util/sink", "tokio/sync"]
async-client = [
Expand Down
2 changes: 1 addition & 1 deletion core/src/client/async_client/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub(crate) fn process_batch_response(
};

for _ in range {
let err_obj = ErrorObject::borrowed(0, &"", None);
let err_obj = ErrorObject::borrowed(0, "", None);
responses.push(Err(err_obj));
}

Expand Down
2 changes: 1 addition & 1 deletion core/src/server/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl MethodResponse {

let err = ResponsePayload::error_borrowed(ErrorObject::borrowed(
err_code,
&OVERSIZED_RESPONSE_MSG,
OVERSIZED_RESPONSE_MSG,
data.as_deref(),
));
let result =
Expand Down
3 changes: 0 additions & 3 deletions core/src/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,13 @@
mod error;
/// Helpers.
pub mod helpers;
/// Host filtering.
mod host_filtering;
/// JSON-RPC "modules" group sets of methods that belong together and handles method/subscription registration.
mod rpc_module;
/// Subscription related types.
mod subscription;

pub use error::*;
pub use helpers::{BatchResponseBuilder, BoundedWriter, MethodResponse, MethodSink};
pub use host_filtering::*;
pub use rpc_module::*;
pub use subscription::*;

Expand Down
6 changes: 1 addition & 5 deletions examples/examples/cors_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,11 +85,7 @@ async fn run_server() -> anyhow::Result<SocketAddr> {
// modifying requests / responses. These features are independent of one another
// and can also be used separately.
// In this example, we use both features.
let server = Server::builder()
.disable_host_filtering()
.set_middleware(middleware)
.build("127.0.0.1:0".parse::<SocketAddr>()?)
.await?;
let server = Server::builder().set_middleware(middleware).build("127.0.0.1:0".parse::<SocketAddr>()?).await?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| {
Expand Down
82 changes: 82 additions & 0 deletions examples/examples/host_filter_middleware.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright 2019-2022 Parity Technologies (UK) Ltd.
//
// Permission is hereby granted, free of charge, to any
// person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the
// Software without restriction, including without
// limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software
// is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice
// shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

//! This example shows how to configure `host filtering` by tower middleware on the jsonrpsee server.
//!
//! The server whitelist's only `example.com` and any call from localhost will be
//! rejected both by HTTP and WebSocket transports.

use std::net::SocketAddr;

use jsonrpsee::core::client::ClientT;
use jsonrpsee::http_client::HttpClientBuilder;
use jsonrpsee::rpc_params;
use jsonrpsee::server::middleware::HostFilterLayer;
use jsonrpsee::server::{RpcModule, Server};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::FmtSubscriber::builder()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.try_init()
.expect("setting default subscriber failed");

let addr = run_server().await?;
let url = format!("http://{}", addr);

// Use RPC client to get the response of `say_hello` method.
let client = HttpClientBuilder::default().build(&url)?;
// This call will be denied because only `example.com` URIs/hosts are allowed by the host filter.
let response = client.request::<String, _>("say_hello", rpc_params![]).await.unwrap_err();
println!("[main]: response: {}", response);

Ok(())
}

async fn run_server() -> anyhow::Result<SocketAddr> {
// Custom tower service to handle the RPC requests
let service_builder = tower::ServiceBuilder::new()
// For this example we only want to permit requests from `example.com`
// all other request are denied.
//
// `HostFilerLayer::new` only fails on invalid URIs..
.layer(HostFilterLayer::new(["example.com"]).unwrap());

let server = Server::builder().set_middleware(service_builder).build("127.0.0.1:0".parse::<SocketAddr>()?).await?;

let addr = server.local_addr()?;

let mut module = RpcModule::new(());
module.register_method("say_hello", |_, _| "lo").unwrap();

let handle = server.start(module);

// In this example we don't care about doing shutdown so let's it run forever.
// You may use the `ServerHandle` to shut it down or manage it yourself.
tokio::spawn(handle.stopped());

Ok(addr)
}
2 changes: 1 addition & 1 deletion examples/examples/http_proxy_middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ use std::time::Duration;
use jsonrpsee::core::client::ClientT;
use jsonrpsee::http_client::HttpClientBuilder;
use jsonrpsee::rpc_params;
use jsonrpsee::server::middleware::proxy_get_request::ProxyGetRequestLayer;
use jsonrpsee::server::middleware::ProxyGetRequestLayer;
use jsonrpsee::server::{RpcModule, Server};

#[tokio::main]
Expand Down
3 changes: 3 additions & 0 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ tokio-util = { version = "0.7", features = ["compat"] }
tokio-stream = "0.1.7"
hyper = { version = "0.14", features = ["server", "http1", "http2"] }
tower = "0.4.13"
route-recognizer = "0.3.1"
http = "0.2.9"
thiserror = "1.0.44"

[dev-dependencies]
anyhow = "1"
Expand Down

0 comments on commit 119d3ae

Please sign in to comment.