Skip to content

Commit

Permalink
Infer 80/443 ports for http/https rpc-url (#576)
Browse files Browse the repository at this point in the history
Co-authored-by: Paul Bellamy <paul@stellar.org>
  • Loading branch information
leighmcculloch and Paul Bellamy authored Apr 11, 2023
1 parent 015106c commit c53cdb0
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 8 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions cmd/soroban-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ csv = "1.1.6"
ed25519-dalek = "1.0.1"
jsonrpsee-http-client = "0.15.1"
jsonrpsee-core = "0.15.1"
http = "0.2.9"
regex = "1.6.0"
wasm-opt = "0.112.0"
chrono = "0.4.23"
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/contract/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ impl Cmd {
None => rand::thread_rng().gen::<[u8; 32]>(),
};

let client = Client::new(&network.rpc_url);
let client = Client::new(&network.rpc_url)?;
let key = self.config.key_pair()?;

// Get the account sequence number
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/contract/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl Cmd {

async fn run_against_rpc_server(&self, contract: Vec<u8>) -> Result<Hash, Error> {
let network = self.config.get_network()?;
let client = Client::new(&network.rpc_url);
let client = Client::new(&network.rpc_url)?;
let key = self.config.key_pair()?;

// Get the account sequence number
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/contract/invoke.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ impl Cmd {
pub async fn run_against_rpc_server(&self) -> Result<String, Error> {
let contract_id = self.contract_id()?;
let network = &self.config.get_network()?;
let client = Client::new(&network.rpc_url);
let client = Client::new(&network.rpc_url)?;
let key = self.config.key_pair()?;

// Get the account sequence number
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ impl Cmd {
})?;
}

let client = rpc::Client::new(&rpc_url);
let client = rpc::Client::new(&rpc_url)?;
client
.get_events(
start,
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-cli/src/commands/lab/token/wrap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ impl Cmd {

async fn run_against_rpc_server(&self, asset: Asset) -> Result<String, Error> {
let network = self.config.get_network()?;
let client = Client::new(&network.rpc_url);
let client = Client::new(&network.rpc_url)?;
let key = self.config.key_pair()?;

// Get the account sequence number
Expand Down
64 changes: 61 additions & 3 deletions cmd/soroban-cli/src/rpc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use http::{uri::Authority, Uri};
use itertools::Itertools;
use jsonrpsee_core::{self, client::ClientT, rpc_params};
use jsonrpsee_http_client::{types, HeaderMap, HttpClient, HttpClientBuilder};
Expand All @@ -10,6 +11,7 @@ use soroban_env_host::xdr::{
use std::{
collections,
fmt::Display,
str::FromStr,
time::{Duration, Instant},
};
use termcolor::{Color, ColorChoice, StandardStream, WriteColor};
Expand All @@ -26,6 +28,10 @@ pub enum Error {
InvalidResponse,
#[error("xdr processing error: {0}")]
Xdr(#[from] XdrError),
#[error("invalid rpc url: {0}")]
InvalidRpcUrl(http::uri::InvalidUri),
#[error("invalid rpc url: {0}")]
InvalidRpcUrlFromUriParts(http::uri::InvalidUriParts),
#[error("jsonrpc error: {0}")]
JsonRpc(#[from] jsonrpsee_core::Error),
#[error("json decoding error: {0}")]
Expand Down Expand Up @@ -300,10 +306,33 @@ pub struct Client {
}

impl Client {
pub fn new(base_url: &str) -> Self {
Self {
base_url: base_url.to_string(),
pub fn new(base_url: &str) -> Result<Self, Error> {
// Add the port to the base URL if there is no port explicitly included
// in the URL and the scheme allows us to infer a default port.
// Jsonrpsee requires a port to always be present even if one can be
// inferred. This may change: https://github.com/paritytech/jsonrpsee/issues/1048.
let uri = base_url.parse::<Uri>().map_err(Error::InvalidRpcUrl)?;
let mut parts = uri.into_parts();
if let (Some(scheme), Some(authority)) = (&parts.scheme, &parts.authority) {
if authority.port().is_none() {
let port = match scheme.as_str() {
"http" => Some(80),
"https" => Some(443),
_ => None,
};
if let Some(port) = port {
let host = authority.host();
parts.authority = Some(
Authority::from_str(&format!("{host}:{port}"))
.map_err(Error::InvalidRpcUrl)?,
);
}
}
}
let uri = Uri::from_parts(parts).map_err(Error::InvalidRpcUrlFromUriParts)?;
Ok(Self {
base_url: uri.to_string(),
})
}

fn client(&self) -> Result<HttpClient, Error> {
Expand Down Expand Up @@ -493,6 +522,35 @@ pub fn parse_cursor(c: &str) -> Result<(u64, i32), Error> {
mod tests {
use super::*;

#[test]
fn test_rpc_url_default_ports() {
// Default ports are added.
let client = Client::new("http://example.com").unwrap();
assert_eq!(client.base_url, "http://example.com:80/");
let client = Client::new("https://example.com").unwrap();
assert_eq!(client.base_url, "https://example.com:443/");

// Ports are not added when already present.
let client = Client::new("http://example.com:8080").unwrap();
assert_eq!(client.base_url, "http://example.com:8080/");
let client = Client::new("https://example.com:8080").unwrap();
assert_eq!(client.base_url, "https://example.com:8080/");

// Paths are not modified.
let client = Client::new("http://example.com/a/b/c").unwrap();
assert_eq!(client.base_url, "http://example.com:80/a/b/c");
let client = Client::new("https://example.com/a/b/c").unwrap();
assert_eq!(client.base_url, "https://example.com:443/a/b/c");
let client = Client::new("http://example.com/a/b/c/").unwrap();
assert_eq!(client.base_url, "http://example.com:80/a/b/c/");
let client = Client::new("https://example.com/a/b/c/").unwrap();
assert_eq!(client.base_url, "https://example.com:443/a/b/c/");
let client = Client::new("http://example.com/a/b:80/c/").unwrap();
assert_eq!(client.base_url, "http://example.com:80/a/b:80/c/");
let client = Client::new("https://example.com/a/b:80/c/").unwrap();
assert_eq!(client.base_url, "https://example.com:443/a/b:80/c/");
}

#[test]
// Taken from [RPC server
// tests](https://github.com/stellar/soroban-tools/blob/main/cmd/soroban-rpc/internal/methods/get_events_test.go#L21).
Expand Down

0 comments on commit c53cdb0

Please sign in to comment.