Skip to content

Commit

Permalink
feat: publish https outcalls adapter with http enabled for dfx
Browse files Browse the repository at this point in the history
  • Loading branch information
tthebst committed Jul 5, 2024
1 parent 52b5c41 commit 5480073
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 15 deletions.
2 changes: 1 addition & 1 deletion ic-os/guestos/defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def image_deps(mode, malicious = False):
"//publish/binaries:guestos_tool": "/opt/ic/bin/guestos_tool:0755",
"//publish/binaries:ic-btc-adapter": "/opt/ic/bin/ic-btc-adapter:0755",
"//publish/binaries:ic-consensus-pool-util": "/opt/ic/bin/ic-consensus-pool-util:0755",
"//publish/binaries:ic-https-outcalls-adapter": "/opt/ic/bin/ic-https-outcalls-adapter:0755",
"//rs/https_outcalls/adapter:ic-https-outcalls-adapter": "/opt/ic/bin/ic-https-outcalls-adapter:0755", # `//publish/binaries:ic-https-outcalls-adapter` is for testing and must NOT be used here
"//publish/binaries:ic-crypto-csp": "/opt/ic/bin/ic-crypto-csp:0755",
"//publish/binaries:ic-regedit": "/opt/ic/bin/ic-regedit:0755",
"//publish/binaries:ic-recovery": "/opt/ic/bin/ic-recovery:0755",
Expand Down
3 changes: 2 additions & 1 deletion publish/binaries/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ BINARIES = {
"ic-boundary": "//rs/boundary_node/ic_boundary:ic-boundary",
"ic-boundary-tls": "//rs/boundary_node/ic_boundary:ic-boundary-tls",
"ic-starter": "//rs/starter:ic-starter",
"ic-https-outcalls-adapter": "//rs/https_outcalls/adapter:ic-https-outcalls-adapter",
"ic-https-outcalls-adapter": "//rs/https_outcalls/adapter:ic-outcalls-adapter-with-http",
"ic-consensus-pool-util": "//rs/artifact_pool:ic-consensus-pool-util",
"ic-crypto-csp": "//rs/crypto:ic-crypto-csp",
"ic-nns-init": "//rs/nns/init:ic-nns-init",
Expand Down Expand Up @@ -82,6 +82,7 @@ TESTONLY_BINARIES = [
"ic-backup",
"ic-boundary",
"ic-boundary-tls",
"ic-https-outcalls-adapter",
"ic-nns-init",
"ic-prep",
"ic-recovery",
Expand Down
37 changes: 36 additions & 1 deletion rs/https_outcalls/adapter/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,40 @@ rust_library(
deps = DEPENDENCIES,
)

# Same target as above but allows the adapter to make HTTP calls.
rust_library(
name = "adapter_with_http",
testonly = True,
srcs = glob(["src/**"]),
aliases = ALIASES,
crate_features = ["http"],
crate_name = "ic_https_outcalls_adapter",
proc_macro_deps = MACRO_DEPENDENCIES,
version = "0.1.0",
deps = DEPENDENCIES,
)

rust_binary(
name = "ic-https-outcalls-adapter",
srcs = ["src/main.rs"],
aliases = ALIASES,
proc_macro_deps = MACRO_DEPENDENCIES,
visibility = ["//publish:__subpackages__"],
visibility = ["//ic-os/guestos:__subpackages__"],
deps = DEPENDENCIES + [":adapter"],
)

# Same target as above but allows the adapter to make HTTP calls.
# This target is used for local testing (e.g. DFX)
rust_binary(
name = "ic-outcalls-adapter-with-http",
testonly = True,
srcs = ["src/main.rs"],
aliases = ALIASES,
proc_macro_deps = MACRO_DEPENDENCIES,
visibility = ["//publish:__subpackages__"],
deps = DEPENDENCIES + [":adapter_with_http"],
)

rust_test(
name = "adapter_test",
aliases = ALIASES,
Expand All @@ -73,3 +98,13 @@ rust_test_suite(
tags = ["requires-network"],
deps = [":adapter"] + DEPENDENCIES + DEV_DEPENDENCIES,
)

rust_test_suite(
name = "adapter_integration_with_http",
srcs = glob(["tests/**/*.rs"]),
aliases = ALIASES,
crate_features = ["http"],
proc_macro_deps = MACRO_DEPENDENCIES + MACRO_DEV_DEPENDENCIES,
tags = ["requires-network"],
deps = [":adapter_with_http"] + DEPENDENCIES + DEV_DEPENDENCIES,
)
12 changes: 7 additions & 5 deletions rs/https_outcalls/adapter/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,18 @@ impl AdapterServer {
}
};

let https_client = Client::builder()
let builder = Client::builder()
.use_rustls_tls()
.https_only(true)
.http1_only()
.redirect(Policy::none())
.referer(false)
.default_headers(HeaderMap::new())
.connect_timeout(timeout)
.build()
.expect("Failed to create HTTPS client");
.connect_timeout(timeout);

#[cfg(not(feature = "http"))]
let builder = builder.https_only(true);

let https_client = builder.build().expect("Failed to create HTTPS client");

let canister_http = CanisterHttp::new(https_client, socks_client, logger, metrics);

Expand Down
1 change: 1 addition & 0 deletions rs/https_outcalls/adapter/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use prometheus::{IntCounter, IntCounterVec};
pub(crate) const LABEL_BODY_RECEIVE_SIZE: &str = "body_receive_size";
pub(crate) const LABEL_BODY_RECEIVE_TIMEOUT: &str = "body_receive_timeout";
pub(crate) const LABEL_HEADER_RECEIVE_SIZE: &str = "header_receive_size";
#[cfg(not(feature = "http"))]
pub(crate) const LABEL_HTTP_SCHEME: &str = "http_scheme";
pub(crate) const LABEL_HTTP_METHOD: &str = "http_method";
pub(crate) const LABEL_RESPONSE_HEADERS: &str = "response_headers";
Expand Down
6 changes: 4 additions & 2 deletions rs/https_outcalls/adapter/src/rpc_server.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::metrics::{
AdapterMetrics, LABEL_BODY_RECEIVE_SIZE, LABEL_BODY_RECEIVE_TIMEOUT, LABEL_CONNECT,
LABEL_DOWNLOAD, LABEL_HEADER_RECEIVE_SIZE, LABEL_HTTP_METHOD, LABEL_HTTP_SCHEME,
LABEL_REQUEST_HEADERS, LABEL_RESPONSE_HEADERS, LABEL_UPLOAD, LABEL_URL_PARSE,
LABEL_DOWNLOAD, LABEL_HEADER_RECEIVE_SIZE, LABEL_HTTP_METHOD, LABEL_REQUEST_HEADERS,
LABEL_RESPONSE_HEADERS, LABEL_UPLOAD, LABEL_URL_PARSE,
};
use core::convert::TryFrom;
use futures::StreamExt;
Expand Down Expand Up @@ -86,7 +86,9 @@ impl CanisterHttpService for CanisterHttp {
)
})?;

#[cfg(not(feature = "http"))]
if url.scheme() != "https" {
use crate::metrics::LABEL_HTTP_SCHEME;
debug!(
self.logger,
"Got request with no or http scheme specified. {}", url
Expand Down
49 changes: 44 additions & 5 deletions rs/https_outcalls/adapter/tests/server_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ mod test {
use unix::UnixListenerDrop;
use uuid::Uuid;
use warp::{
filters::BoxedFilter,
http::{header::HeaderValue, Response, StatusCode},
Filter,
};

#[cfg(feature = "http")]
use std::net::IpAddr;

// Selfsigned localhost cert
const CERT: &str = "
-----BEGIN CERTIFICATE-----
Expand Down Expand Up @@ -74,7 +78,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE
dir
}

fn start_server(cert_dir: &TempDir) -> String {
fn warp_server() -> BoxedFilter<(impl warp::Reply,)> {
let basic_post = warp::post()
.and(warp::path("post"))
.and(warp::body::json())
Expand All @@ -83,7 +87,6 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE
let basic_get = warp::get()
.and(warp::path("get"))
.map(|| warp::reply::json(&"Hello"));

let invalid_header = warp::get().and(warp::path("invalid")).map(|| unsafe {
Response::builder()
.header(
Expand All @@ -108,14 +111,17 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE

let basic_head = warp::head().and(warp::path("head")).map(warp::reply::reply);

let routes = basic_post
basic_post
.or(basic_get)
.or(basic_head)
.or(get_response_size)
.or(get_delay)
.or(invalid_header);
.or(invalid_header)
.boxed()
}

let (addr, fut) = warp::serve(routes)
fn start_server(cert_dir: &TempDir) -> String {
let (addr, fut) = warp::serve(warp_server())
.tls()
.cert_path(cert_dir.path().join("cert.crt"))
.key_path(cert_dir.path().join("key.pem"))
Expand All @@ -125,6 +131,14 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE
format!("localhost:{}", addr.port())
}

#[cfg(feature = "http")]
fn start_http_server(ip: IpAddr) -> String {
let (addr, fut) = warp::serve(warp_server()).bind_ephemeral((ip, 0));

tokio::spawn(fut);
format!("{}:{}", ip, addr.port())
}

#[tokio::test]
async fn test_canister_http_server() {
let server_config = Config {
Expand All @@ -146,6 +160,7 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE
assert_eq!(http_response.status, StatusCode::OK.as_u16() as u32);
}

#[cfg(not(feature = "http"))]
#[tokio::test]
async fn test_canister_http_http_protocol() {
// Check that error is returned if a `http` url is specified.
Expand Down Expand Up @@ -175,6 +190,30 @@ MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgob29X4H4m2XOkSZE
.contains(&"Url need to specify https scheme".to_string()));
}

#[cfg(feature = "http")]
#[tokio::test]
async fn test_canister_http_http_protocol_allowed() {
// Check that error is returned if a `http` url is specified.
let server_config = Config {
..Default::default()
};

let url = start_http_server("127.0.0.1".parse().unwrap());
let mut client = spawn_grpc_server(server_config);

let request = tonic::Request::new(CanisterHttpSendRequest {
url: format!("http://{}/get", &url),
headers: Vec::new(),
method: HttpMethod::Get as i32,
body: "hello".to_string().as_bytes().to_vec(),
max_response_size_bytes: 512,
socks_proxy_allowed: false,
});
let response = client.canister_http_send(request).await;
let http_response = response.unwrap().into_inner();
assert_eq!(http_response.status, StatusCode::OK.as_u16() as u32);
}

#[tokio::test]
async fn test_canister_http_server_post() {
let server_config = Config {
Expand Down

0 comments on commit 5480073

Please sign in to comment.