Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 60 additions & 18 deletions client/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ impl QueryRequest {
fn assemble(self) -> DefaultRequestBuilder {
let builder = DefaultRequestBuilder::new(
HttpMethod::POST,
self.torii_url.join(torii_uri::QUERY).expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::QUERY),
)
.headers(self.headers);

Expand Down Expand Up @@ -689,9 +689,7 @@ impl Client {
(
B::new(
HttpMethod::POST,
self.torii_url
.join(torii_uri::TRANSACTION)
.expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::TRANSACTION),
)
.headers(self.headers.clone())
.body(transaction_bytes),
Expand Down Expand Up @@ -958,9 +956,7 @@ impl Client {
events_api::flow::Init::new(
event_filters.into_iter().map(Into::into).collect(),
self.headers.clone(),
self.torii_url
.join(torii_uri::SUBSCRIPTION)
.expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::SUBSCRIPTION),
)
}

Expand Down Expand Up @@ -994,9 +990,7 @@ impl Client {
blocks_api::flow::Init::new(
height,
self.headers.clone(),
self.torii_url
.join(torii_uri::BLOCKS_STREAM)
.expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::BLOCKS_STREAM),
)
}

Expand All @@ -1007,9 +1001,7 @@ impl Client {
pub fn get_config(&self) -> Result<ConfigDTO> {
let resp = DefaultRequestBuilder::new(
HttpMethod::GET,
self.torii_url
.join(torii_uri::CONFIGURATION)
.expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::CONFIGURATION),
)
.headers(&self.headers)
.header(http::header::CONTENT_TYPE, APPLICATION_JSON)
Expand All @@ -1032,10 +1024,7 @@ impl Client {
/// If sending request or decoding fails
pub fn set_config(&self, dto: &ConfigDTO) -> Result<()> {
let body = serde_json::to_vec(&dto).wrap_err(format!("Failed to serialize {dto:?}"))?;
let url = self
.torii_url
.join(torii_uri::CONFIGURATION)
.expect("Valid URI");
let url = join_torii_url(&self.torii_url, torii_uri::CONFIGURATION);
let resp = DefaultRequestBuilder::new(HttpMethod::POST, url)
.headers(&self.headers)
.header(http::header::CONTENT_TYPE, APPLICATION_JSON)
Expand Down Expand Up @@ -1076,12 +1065,26 @@ impl Client {
pub fn prepare_status_request<B: RequestBuilder>(&self) -> B {
B::new(
HttpMethod::GET,
self.torii_url.join(torii_uri::STATUS).expect("Valid URI"),
join_torii_url(&self.torii_url, torii_uri::STATUS),
)
.headers(self.headers.clone())
}
}

fn join_torii_url(url: &Url, path: &str) -> Url {
// This is needed to prevent "https://iroha-peer.jp/peer1/".join("/query") == "https://iroha-peer.jp/query"
let path = path.strip_prefix('/').unwrap_or(path);

// This is needed to prevent "https://iroha-peer.jp/peer1".join("query") == "https://iroha-peer.jp/query"
// Note: trailing slash is added to url at config user layer if needed
assert!(
url.path().ends_with('/'),
"Torii url must end with trailing slash"
);

url.join(path).expect("Valid URI")
}

/// Logic for `sync` and `async` Iroha websocket streams
pub mod stream_api {
use futures_util::{SinkExt, Stream, StreamExt};
Expand Down Expand Up @@ -1702,4 +1705,43 @@ mod tests {
}
}
}

#[cfg(test)]
mod join_torii_url {
use url::Url;

use super::*;

fn do_test(url: &str, path: &str, expected: &str) {
let url = Url::parse(url).unwrap();
let actual = join_torii_url(&url, path);
assert_eq!(actual.as_str(), expected);
}

#[test]
fn path_with_slash() {
do_test("https://iroha.jp/", "/query", "https://iroha.jp/query");
do_test(
"https://iroha.jp/peer-1/",
"/query",
"https://iroha.jp/peer-1/query",
);
}

#[test]
fn path_without_slash() {
do_test("https://iroha.jp/", "query", "https://iroha.jp/query");
do_test(
"https://iroha.jp/peer-1/",
"query",
"https://iroha.jp/peer-1/query",
);
}

#[test]
#[should_panic(expected = "Torii url must end with trailing slash")]
fn panic_if_url_without_trailing_slash() {
do_test("https://iroha.jp/peer-1", "query", "should panic");
}
}
}
13 changes: 13 additions & 0 deletions client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,19 @@ mod tests {
let _ = with_scheme("ws").expect_err("not supported");
}

#[test]
fn torii_url_ensure_trailing_slash() {
let config = ConfigReader::new()
.with_toml_source(TomlSource::inline(config_sample()))
.with_env(MockEnv::from([("TORII_URL", "http://127.0.0.1/peer-1")]))
.read_and_complete::<user::Root>()
.unwrap()
.parse()
.unwrap();

assert_eq!(config.torii_api_url.as_str(), "http://127.0.0.1/peer-1/");
}

#[test]
fn invalid_toml_file_is_handled_properly() {
use std::io::Write;
Expand Down
12 changes: 11 additions & 1 deletion client/src/config/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ impl Root {
.attach_printable("Note: only `http` and `https` protocols are supported"),
),
}
let torii_api_url = {
let mut url = torii_url.into_value();
let path = url.path();
// Ensure torii url ends with a trailing slash
if !path.ends_with('/') {
let path = path.to_owned() + "/";
url.set_path(&path)
}
url
};

let (public_key, public_key_origin) = public_key.into_tuple();
let (private_key, private_key_origin) = private_key.into_tuple();
Expand All @@ -103,7 +113,7 @@ impl Root {
chain: chain_id,
account: account_id,
key_pair: key_pair.unwrap(),
torii_api_url: torii_url.into_value(),
torii_api_url,
basic_auth,
transaction_ttl: tx_ttl.into_value().get(),
transaction_status_timeout: tx_timeout.into_value().get(),
Expand Down
Binary file modified defaults/executor.wasm
Binary file not shown.