diff --git a/packages/pocket-ic/BUILD.bazel b/packages/pocket-ic/BUILD.bazel index 45590531dc2..3cbe06bfe13 100644 --- a/packages/pocket-ic/BUILD.bazel +++ b/packages/pocket-ic/BUILD.bazel @@ -94,6 +94,9 @@ rust_test_suite( proc_macro_deps = MACRO_DEPENDENCIES, tags = [ "cpu:16", + # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. + # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) + "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, @@ -114,6 +117,9 @@ rust_test_suite( flaky = False, proc_macro_deps = MACRO_DEPENDENCIES, tags = [ + # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. + # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) + "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, @@ -137,6 +143,9 @@ rust_test_suite( proc_macro_deps = MACRO_DEPENDENCIES, tags = [ "cpu:16", + # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. + # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) + "requires-network", "test_macos", ], deps = [":pocket-ic"] + DEPENDENCIES + TEST_DEPENDENCIES, diff --git a/packages/pocket-ic/HOWTO.md b/packages/pocket-ic/HOWTO.md index 8023c654045..e3e6b8dc6ff 100644 --- a/packages/pocket-ic/HOWTO.md +++ b/packages/pocket-ic/HOWTO.md @@ -525,7 +525,7 @@ Now we create a PocketIC instance configured with the Bitcoin subnet and the `bi .with_ii_subnet() // to have tECDSA keys available .with_application_subnet() // to deploy the test dapp .with_bitcoind_addr(SocketAddr::new( - IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 18444, )) .build(); @@ -576,7 +576,7 @@ To mine blocks with rewards credited to a given `bitcoin_address: String`, you c ```rust use bitcoincore_rpc::{bitcoin::Address, Auth, Client, RpcApi}; let btc_rpc = Client::new( - "http://[::1]:18443", + "http://127.0.0.1:18443", Auth::UserPass( "ic-btc-integration".to_string(), "QPQiNaph19FqUsCrBRN0FII7lyM26B51fAMeBQzCb-E=".to_string(), diff --git a/packages/pocket-ic/src/lib.rs b/packages/pocket-ic/src/lib.rs index 5088281ec74..947e057e3aa 100644 --- a/packages/pocket-ic/src/lib.rs +++ b/packages/pocket-ic/src/lib.rs @@ -99,7 +99,7 @@ const EXPECTED_SERVER_VERSION: &str = "pocket-ic-server 7.0.0"; // the default timeout of a PocketIC operation const DEFAULT_MAX_REQUEST_TIME_MS: u64 = 300_000; -const LOCALHOST: &str = "[::1]"; +const LOCALHOST: &str = "127.0.0.1"; pub struct PocketIcBuilder { config: Option, diff --git a/rs/pocket_ic_server/BUILD.bazel b/rs/pocket_ic_server/BUILD.bazel index 0d6a79efe24..112ffb34b72 100644 --- a/rs/pocket_ic_server/BUILD.bazel +++ b/rs/pocket_ic_server/BUILD.bazel @@ -192,6 +192,17 @@ rust_test( }, tags = [ "cpu:8", + # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. + # ---- test_http_gateway stdout ---- + # thread 'test_http_gateway' panicked at rs/pocket_ic_server/tests/test.rs:383:48: + # called `Result::unwrap()` on an `Err` value: reqwest::Error { + # kind: Request, url: "http://7tjcv-pp777-77776-qaaaa-cai.raw.localhost:49380/", + # source: hyper_util::client::legacy::Error( + # Connect, + # ConnectError("tcp connect error", Os { code: 1, kind: PermissionDenied, message: "Operation not permitted" }) + # ) + # } + "requires-network", "test_macos", ], deps = TEST_DEPENDENCIES, @@ -244,6 +255,9 @@ rust_test( "SSL_CERT_FILE": "$(rootpath @mozilla_root_ca_store//file)", }, tags = [ + # TODO: remove 'requires-network' tag when the root cause for sporadic error below on Apple Silicon is identified and fixed. + # Failed to crate http gateway: Failed to bind to address 127.0.0.1:0: Operation not permitted (os error 1) + "requires-network", "test_macos", ], deps = TEST_DEPENDENCIES, diff --git a/rs/pocket_ic_server/CHANGELOG.md b/rs/pocket_ic_server/CHANGELOG.md index 3b8cd8c1c9d..fa0390e3828 100644 --- a/rs/pocket_ic_server/CHANGELOG.md +++ b/rs/pocket_ic_server/CHANGELOG.md @@ -15,9 +15,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - New endpoint `/instances//read/ingress_status` to fetch the status of an update call submitted through an ingress message. If an optional caller is provided, the status of the update call is known, but the update call was submitted by a different caller, then an error is returned. -### Changed -- The default IP address to which the PocketIC server and HTTP gateway bind is [::1] instead of 127.0.0.1. - ### Fixed - Canisters created via `provisional_create_canister_with_cycles` with the management canister ID as the effective canister ID are created on an arbitrary subnet. diff --git a/rs/pocket_ic_server/src/main.rs b/rs/pocket_ic_server/src/main.rs index ce3b504a140..adbc07586c3 100644 --- a/rs/pocket_ic_server/src/main.rs +++ b/rs/pocket_ic_server/src/main.rs @@ -56,7 +56,7 @@ const LOG_DIR_LEVELS_ENV_NAME: &str = "POCKET_IC_LOG_DIR_LEVELS"; #[derive(Parser)] #[clap(version = "7.0.0")] struct Args { - /// The IP address to which the PocketIC server should bind (defaults to [::1]) + /// The IP address to which the PocketIC server should bind (defaults to 127.0.0.1) #[clap(long, short)] ip_addr: Option, /// Log levels for PocketIC server logs (defaults to `pocket_ic_server=info,tower_http=info,axum::rejection=trace`). @@ -131,7 +131,7 @@ async fn start(runtime: Arc) { None }; - let ip_addr = args.ip_addr.unwrap_or("[::1]".to_string()); + let ip_addr = args.ip_addr.unwrap_or("127.0.0.1".to_string()); let addr = format!("{}:{}", ip_addr, args.port); let listener = std::net::TcpListener::bind(addr.clone()) .unwrap_or_else(|_| panic!("Failed to bind PocketIC server to address {}", addr)); diff --git a/rs/pocket_ic_server/src/state_api/canister_id.rs b/rs/pocket_ic_server/src/state_api/canister_id.rs index 9356cae6ff1..433781f0756 100644 --- a/rs/pocket_ic_server/src/state_api/canister_id.rs +++ b/rs/pocket_ic_server/src/state_api/canister_id.rs @@ -2,14 +2,13 @@ use crate::state_api::state::HandlerState; use async_trait::async_trait; use axum::extract::FromRequestParts; use candid::Principal; -use fqdn::{Fqdn, FQDN}; +use fqdn::{fqdn, Fqdn, FQDN}; use hyper::{ header::{HOST, REFERER}, http::request::Parts, Uri, }; use std::collections::BTreeMap; -use std::str::FromStr; use std::sync::Arc; // ADAPTED from ic-gateway @@ -190,10 +189,8 @@ impl FromRequestParts for HostHeader { .rsplit_once(':') .map(|(host, _port)| host) .unwrap_or(host); - let fqdn = - FQDN::from_str(host).map_err(|_| "Could not parse domain name from Host header")?; resolver - .resolve_domain(&fqdn) + .resolve_domain(&fqdn!(host)) .map(|d| d.canister_id) .ok_or(BAD_HOST)? .ok_or(BAD_HOST) @@ -231,10 +228,8 @@ impl FromRequestParts for RefererHeaderHost { let referer = referer.to_str().map_err(|_| BAD_REFERER)?; let referer: Uri = referer.parse().map_err(|_| BAD_REFERER)?; let referer = referer.authority().ok_or(BAD_REFERER)?; - let fqdn = FQDN::from_str(referer.host()) - .map_err(|_| "Could not parse domain name from Referer header")?; resolver - .resolve_domain(&fqdn) + .resolve_domain(&fqdn!(referer.host())) .map(|d| d.canister_id) .ok_or(BAD_REFERER)? .ok_or(BAD_REFERER) diff --git a/rs/pocket_ic_server/src/state_api/state.rs b/rs/pocket_ic_server/src/state_api/state.rs index e33de3f9c4d..e13ed094bf0 100644 --- a/rs/pocket_ic_server/src/state_api/state.rs +++ b/rs/pocket_ic_server/src/state_api/state.rs @@ -18,7 +18,7 @@ use axum::{ use axum_server::tls_rustls::RustlsConfig; use axum_server::Handle; use base64; -use fqdn::FQDN; +use fqdn::{fqdn, FQDN}; use futures::future::Shared; use http::{ header::{ @@ -795,7 +795,7 @@ impl ApiState { let ip_addr = http_gateway_config .ip_addr .clone() - .unwrap_or("[::1]".to_string()); + .unwrap_or("127.0.0.1".to_string()); let port = http_gateway_config.port.unwrap_or_default(); let addr = format!("{}:{}", ip_addr, port); let listener = std::net::TcpListener::bind(&addr) @@ -829,9 +829,8 @@ impl ApiState { .clone() .unwrap_or(vec!["localhost".to_string()]) .iter() - .map(|d| FQDN::from_str(d)) - .collect::, _>>() - .map_err(|e| e.to_string())?; + .map(|d| fqdn!(d)) + .collect(); spawn(async move { let http_gateway_client = ic_http_gateway::HttpGatewayClientBuilder::new() .with_agent(agent) diff --git a/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs b/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs index 29a010ea8d2..7b29841928c 100644 --- a/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs +++ b/rs/pocket_ic_server/tests/bitcoin_integration_tests.rs @@ -6,7 +6,7 @@ use ic_nns_constants::ROOT_CANISTER_ID; use pocket_ic::{update_candid, PocketIc, PocketIcBuilder}; use std::fs::{create_dir, File}; use std::io::Write; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::process::Command; use std::str::FromStr; use std::time::SystemTime; @@ -105,7 +105,7 @@ rpcauth=ic-btc-integration:cdf2741387f3a12438f69092f0fdad8e$62081498c98bee09a0dc .with_ii_subnet() .with_application_subnet() .with_bitcoind_addr(SocketAddr::new( - IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 18444, )) .build(); @@ -130,7 +130,7 @@ rpcauth=ic-btc-integration:cdf2741387f3a12438f69092f0fdad8e$62081498c98bee09a0dc .0; let btc_rpc = Client::new( - "http://[::1]:18443", + "http://127.0.0.1:18443", Auth::UserPass( "ic-btc-integration".to_string(), "QPQiNaph19FqUsCrBRN0FII7lyM26B51fAMeBQzCb-E=".to_string(), diff --git a/rs/pocket_ic_server/tests/test.rs b/rs/pocket_ic_server/tests/test.rs index 8c92919059a..68d9ad3eb06 100644 --- a/rs/pocket_ic_server/tests/test.rs +++ b/rs/pocket_ic_server/tests/test.rs @@ -25,13 +25,13 @@ use reqwest::{StatusCode, Url}; use slog::Level; use std::io::Read; use std::io::Write; -use std::net::{IpAddr, Ipv6Addr, SocketAddr}; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::path::PathBuf; use std::process::{Child, Command}; use std::time::Duration; use tempfile::{NamedTempFile, TempDir}; -pub const LOCALHOST: &str = "[::1]"; +pub const LOCALHOST: &str = "127.0.0.1"; fn start_server_helper( test_driver_pid: Option, @@ -290,7 +290,7 @@ async fn test_gateway(server_url: Url, https: bool) { assert_eq!(http_gateway_details.domains, domains); assert_eq!(http_gateway_details.https_config, https_config); - // create a non-blocking reqwest client resolving localhost/example.com and .(raw.)localhost/example.com to [::1] + // create a non-blocking reqwest client resolving localhost/example.com and .(raw.)localhost/example.com to 127.0.0.1 let mut builder = NonblockingClient::builder(); for domain in [ localhost, @@ -302,7 +302,7 @@ async fn test_gateway(server_url: Url, https: bool) { ] { builder = builder.resolve( domain, - SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), port), + SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), port), ); } // add a custom root certificate @@ -341,13 +341,13 @@ async fn test_gateway(server_url: Url, https: bool) { .await .unwrap(); - // perform frontend asset request for the title page at http://[::1]:/?canisterId= + // perform frontend asset request for the title page at http://127.0.0.1:/?canisterId= let mut test_urls = vec![]; if !https { assert_eq!(proto, "http"); let canister_url = format!( "{}://{}:{}/?canisterId={}", - "http", LOCALHOST, port, canister_id + "http", "127.0.0.1", port, canister_id ); test_urls.push(canister_url); } @@ -1112,7 +1112,7 @@ fn test_gateway_ip_addr_host() { let mut endpoint = pic.make_live(None); endpoint - .set_ip_host(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))) + .set_ip_host(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))) .unwrap(); let rt = tokio::runtime::Builder::new_current_thread() @@ -1474,7 +1474,7 @@ fn test_gateway_address_in_use() { ) .unwrap_err(); assert!(err.contains(&format!( - "Failed to bind to address [::1]:{}: Address already in use", + "Failed to bind to address 127.0.0.1:{}: Address already in use", port ))); }