Skip to content

Commit

Permalink
feat(ethexe/rpc): support cors (#4370)
Browse files Browse the repository at this point in the history
  • Loading branch information
breathx authored Dec 3, 2024
1 parent 427e6d3 commit 9ce8b88
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 26 deletions.
16 changes: 1 addition & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -525,11 +525,14 @@ page_size = { version = "0.6", default-features = false } # pallets/gear
pathdiff = { version = "0.2.1", default-features = false } # utils/wasm-builder
rand_pcg = "0.3.1" # pallets/gear
rustc_version = "0.4.0" # utils/wasm-builder
schnorrkel = "0.11.4" # gcli
schnorrkel = "0.11.4" # gcli
scopeguard = { version = "1.2.0", default-features = false } # pallets/gear
hyper = "1.4.1" # ethexe/rpc
tabled = "0.10.0" # utils/regression-analysis
thousands = "0.2.0" # utils/regression-analysis
toml = "0.8.14" # utils/wasm-builder
tower = "0.4.13" # ethexe/rpc
tower-http = "0.5.2" # ethexe/rpc
tracing = "0.1.40" # utils/node-loader
tracing-appender = "0.2" # utils/node-loader
tracing-subscriber = "0.3.18" # utils/node-loader
Expand Down
2 changes: 1 addition & 1 deletion ethexe/cli/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ pub struct Args {

#[allow(missing_docs)]
#[clap(flatten)]
pub rpc_params: RpcParams,
pub rpc_params: Option<RpcParams>,

#[command(subcommand)]
pub extra_command: Option<ExtraCommands>,
Expand Down
2 changes: 1 addition & 1 deletion ethexe/cli/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl TryFrom<Args> for Config {
prometheus_config: args.prometheus_params.and_then(|params| {
params.prometheus_config(DEFAULT_PROMETHEUS_PORT, "ethexe-dev".to_string())
}),
rpc_config: args.rpc_params.as_config(),
rpc_config: args.rpc_params.and_then(|v| v.as_config()),
})
}
}
73 changes: 71 additions & 2 deletions ethexe/cli/src/params/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@
use clap::Args;
use ethexe_rpc::RpcConfig;
use serde::Deserialize;
use std::net::{Ipv4Addr, SocketAddr};
use std::{
net::{Ipv4Addr, SocketAddr},
str::FromStr,
};

/// Parameters used to config prometheus.
#[derive(Debug, Clone, Args, Deserialize)]
Expand All @@ -35,6 +38,14 @@ pub struct RpcParams {
/// Do not start rpc endpoint.
#[arg(long, default_value = "false")]
pub no_rpc: bool,

/// Specify browser *origins* allowed to access the HTTP & WS RPC servers.
///
/// A comma-separated list of origins (protocol://domain or special `null`
/// value). Value of `all` will disable origin validation. Default is to
/// allow localhost origin.
#[arg(long)]
pub rpc_cors: Option<Cors>,
}

impl RpcParams {
Expand All @@ -53,6 +64,64 @@ impl RpcParams {

let listen_addr = SocketAddr::new(ip, self.rpc_port);

Some(RpcConfig { listen_addr })
let cors = self
.rpc_cors
.clone()
.unwrap_or_else(|| {
Cors::List(vec![
"http://localhost:*".into(),
"http://127.0.0.1:*".into(),
"https://localhost:*".into(),
"https://127.0.0.1:*".into(),
])
})
.into();

Some(RpcConfig { listen_addr, cors })
}
}

/// CORS setting
///
/// The type is introduced to overcome `Option<Option<T>>` handling of `clap`.
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Cors {
/// All hosts allowed.
All,
/// Only hosts on the list are allowed.
List(Vec<String>),
}

impl From<Cors> for Option<Vec<String>> {
fn from(cors: Cors) -> Self {
match cors {
Cors::All => None,
Cors::List(list) => Some(list),
}
}
}

impl FromStr for Cors {
type Err = anyhow::Error;

fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut is_all = false;
let mut origins = Vec::new();
for part in s.split(',') {
match part {
"all" | "*" => {
is_all = true;
break;
}
other => origins.push(other.to_owned()),
}
}

if is_all {
Ok(Cors::All)
} else {
Ok(Cors::List(origins))
}
}
}
1 change: 1 addition & 0 deletions ethexe/cli/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,7 @@ mod tests {
)),
rpc_config: Some(RpcConfig {
listen_addr: SocketAddr::new(Ipv4Addr::LOCALHOST.into(), 9944),
cors: None,
}),
})
.await
Expand Down
7 changes: 4 additions & 3 deletions ethexe/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ futures.workspace = true
gprimitives = { workspace = true, features = ["serde"] }
ethexe-db.workspace = true
ethexe-processor.workspace = true
jsonrpsee = { version = "0.24", features = ["server", "macros"] }
tower = { version = "0.4.13", features = ["full"] }
hyper = { version = "1.4.1", features = ["server"] }
tower = { workspace = true, features = ["util"] }
tower-http = { workspace = true, features = ["cors"] }
jsonrpsee = { workspace = true, features = ["server", "macros"] }
hyper = { workspace = true, features = ["server"] }
log.workspace = true
parity-scale-codec.workspace = true
hex.workspace = true
Expand Down
17 changes: 14 additions & 3 deletions ethexe/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use anyhow::anyhow;
use anyhow::{anyhow, Result};
use apis::{BlockApi, BlockServer, ProgramApi, ProgramServer};
use ethexe_db::Database;
use futures::FutureExt;
Expand All @@ -35,6 +35,8 @@ mod apis;
mod common;
mod errors;

pub(crate) mod util;

#[derive(Clone)]
struct PerConnection<RpcMiddleware, HttpMiddleware> {
methods: Methods,
Expand All @@ -47,6 +49,8 @@ struct PerConnection<RpcMiddleware, HttpMiddleware> {
pub struct RpcConfig {
/// Listen address.
pub listen_addr: SocketAddr,
/// CORS.
pub cors: Option<Vec<String>>,
}

pub struct RpcService {
Expand All @@ -63,10 +67,17 @@ impl RpcService {
self.config.listen_addr.port()
}

pub async fn run_server(self) -> anyhow::Result<ServerHandle> {
pub async fn run_server(self) -> Result<ServerHandle> {
let listener = TcpListener::bind(self.config.listen_addr).await?;

let service_builder = Server::builder().to_service_builder();
let cors = util::try_into_cors(self.config.cors)?;

let http_middleware = tower::ServiceBuilder::new().layer(cors);

let service_builder = Server::builder()
.set_http_middleware(http_middleware)
.to_service_builder();

let mut module = JsonrpcModule::new(());
module.merge(ProgramServer::into_rpc(ProgramApi::new(self.db.clone())))?;
module.merge(BlockServer::into_rpc(BlockApi::new(self.db.clone())))?;
Expand Down
36 changes: 36 additions & 0 deletions ethexe/rpc/src/util.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// This file is part of Gear.
//
// Copyright (C) 2024 Gear Technologies Inc.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use anyhow::Result;
use hyper::header::HeaderValue;
use tower_http::cors::{AllowOrigin, CorsLayer};

pub(crate) fn try_into_cors(maybe_cors: Option<Vec<String>>) -> Result<CorsLayer> {
if let Some(cors) = maybe_cors {
let mut list = Vec::new();

for origin in cors {
list.push(HeaderValue::from_str(&origin)?)
}

Ok(CorsLayer::new().allow_origin(AllowOrigin::list(list)))
} else {
// allow all cors
Ok(CorsLayer::permissive())
}
}

0 comments on commit 9ce8b88

Please sign in to comment.