From a14004b68b26157d7a67895b2ba18191acfc6ed9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 6 Oct 2023 15:26:47 -0500 Subject: [PATCH] fix(wasmtime-cli): wrong linker in wasi http (#7167) (#7175) * chore: convert wasi http cli test to component * fix(wasmtime-cli): wrong linker in wasi http * fix(wasmtime-cli): fix multiple functions added to linker We will allow shadowing in linker when using WASI HTTP in order to prevent the following error: > import of `wasi:clocks/wall-clock` defined twice * chore: update to latest io streams wit definition * chore: rename main function of core module prtest:full * fix(wasmtime-cli): add only http functions to linker * chore: add test building http request and response * chore: disable temporarily wasi http test Co-authored-by: Eduardo de Moura Rodrigues <16357187+eduardomourar@users.noreply.github.com> --- .../tests/wasi-http-components-sync.rs | 6 ++ .../tests/wasi-http-components.rs | 6 ++ .../bin/outbound_request_response_build.rs | 40 ++++++++ crates/wasi-http/src/proxy.rs | 11 +++ src/commands/run.rs | 2 +- tests/all/cli_tests.rs | 20 ++-- tests/all/cli_tests/wasi-http.wat | 93 ------------------- 7 files changed, 75 insertions(+), 103 deletions(-) create mode 100644 crates/test-programs/wasi-http-tests/src/bin/outbound_request_response_build.rs delete mode 100644 tests/all/cli_tests/wasi-http.wat diff --git a/crates/test-programs/tests/wasi-http-components-sync.rs b/crates/test-programs/tests/wasi-http-components-sync.rs index 1f5a196c361c..af0bcaeca218 100644 --- a/crates/test-programs/tests/wasi-http-components-sync.rs +++ b/crates/test-programs/tests/wasi-http-components-sync.rs @@ -163,3 +163,9 @@ fn outbound_request_invalid_dnsname() -> Result<()> { let server = Server::http1()?; run("outbound_request_invalid_dnsname", &server) } + +#[test_log::test] +fn outbound_request_response_build() -> Result<()> { + let server = Server::http1()?; + run("outbound_request_response_build", &server) +} diff --git a/crates/test-programs/tests/wasi-http-components.rs b/crates/test-programs/tests/wasi-http-components.rs index 7d70cb365036..6bec2ab717f7 100644 --- a/crates/test-programs/tests/wasi-http-components.rs +++ b/crates/test-programs/tests/wasi-http-components.rs @@ -161,3 +161,9 @@ async fn outbound_request_invalid_dnsname() -> Result<()> { let server = Server::http1()?; run("outbound_request_invalid_dnsname", &server).await } + +#[test_log::test(tokio::test(flavor = "multi_thread"))] +async fn outbound_request_response_build() -> Result<()> { + let server = Server::http1()?; + run("outbound_request_response_build", &server).await +} diff --git a/crates/test-programs/wasi-http-tests/src/bin/outbound_request_response_build.rs b/crates/test-programs/wasi-http-tests/src/bin/outbound_request_response_build.rs new file mode 100644 index 000000000000..322992380d49 --- /dev/null +++ b/crates/test-programs/wasi-http-tests/src/bin/outbound_request_response_build.rs @@ -0,0 +1,40 @@ +use wasi_http_tests::bindings::wasi::{cli::stdout::get_stdout, http::types as http_types}; + +fn print(msg: &[u8]) { + let _ = get_stdout().blocking_write_and_flush(&msg); +} + +fn main() { + print("Called _start\n".as_bytes()); + { + let headers = http_types::Headers::new(&[( + "Content-Type".to_string(), + "application/json".to_string().into_bytes(), + )]); + let request = http_types::OutgoingRequest::new( + &http_types::Method::Get, + None, + Some(&http_types::Scheme::Https), + Some("www.example.com"), + &headers, + ); + let outgoing_body = request.write().unwrap(); + let request_body = outgoing_body.write().unwrap(); + request_body + .blocking_write_and_flush("request-body".as_bytes()) + .unwrap(); + } + { + let headers = http_types::Headers::new(&[( + "Content-Type".to_string(), + "application/text".to_string().into_bytes(), + )]); + let response = http_types::OutgoingResponse::new(200, &headers); + let outgoing_body = response.write().unwrap(); + let response_body = outgoing_body.write().unwrap(); + response_body + .blocking_write_and_flush("response-body".as_bytes()) + .unwrap(); + } + print("Done\n".as_bytes()); +} diff --git a/crates/wasi-http/src/proxy.rs b/crates/wasi-http/src/proxy.rs index 1a7bca511c29..155a55fd11fd 100644 --- a/crates/wasi-http/src/proxy.rs +++ b/crates/wasi-http/src/proxy.rs @@ -67,6 +67,17 @@ pub mod sync { // dependencies. preview2::command::sync::add_to_linker(l)?; + add_only_http_to_linker(l)?; + + Ok(()) + } + + #[doc(hidden)] + // TODO: This is temporary solution until the preview2 command functions can be removed + pub fn add_only_http_to_linker(l: &mut wasmtime::component::Linker) -> anyhow::Result<()> + where + T: WasiHttpView + preview2::WasiView + bindings::http::types::Host, + { bindings::http::outgoing_handler::add_to_linker(l, |t| t)?; bindings::http::types::add_to_linker(l, |t| t)?; diff --git a/src/commands/run.rs b/src/commands/run.rs index b45f48a5ae6b..4bf6da4c4974 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -643,7 +643,7 @@ impl RunCommand { bail!("Cannot enable wasi-http for core wasm modules"); } CliLinker::Component(linker) => { - wasmtime_wasi_http::proxy::add_to_linker(linker)?; + wasmtime_wasi_http::proxy::sync::add_only_http_to_linker(linker)?; } } diff --git a/tests/all/cli_tests.rs b/tests/all/cli_tests.rs index da2e7adedc97..f1b39c078b77 100644 --- a/tests/all/cli_tests.rs +++ b/tests/all/cli_tests.rs @@ -790,23 +790,25 @@ fn run_basic_component() -> Result<()> { Ok(()) } -#[cfg(feature = "wasi-http")] -#[ignore = "needs to be ported to components"] #[test] -fn run_wasi_http_module() -> Result<()> { +// #[cfg_attr(not(feature = "wasi-http"), ignore)] +#[ignore = "re-enable when we can reference tests from test-programs"] +fn run_wasi_http_component() -> Result<()> { let output = run_wasmtime_for_output( &[ - "-Shttp,preview2", "-Ccache=no", - "tests/all/cli_tests/wasi-http.wat", + "-Wcomponent-model", + "-Scommon,http,preview2", + "tests/all/cli_tests/wasi-http-component.wat", ], None, )?; println!("{}", String::from_utf8_lossy(&output.stderr)); - assert!(String::from_utf8(output.stdout) - .unwrap() - .starts_with("Called _start\n")); - assert!(!output.status.success()); + let stdout = String::from_utf8_lossy(&output.stdout); + println!("{}", stdout); + assert!(stdout.starts_with("Called _start\n")); + assert!(stdout.ends_with("Done\n")); + assert!(output.status.success()); Ok(()) } diff --git a/tests/all/cli_tests/wasi-http.wat b/tests/all/cli_tests/wasi-http.wat deleted file mode 100644 index 8893c3ca4584..000000000000 --- a/tests/all/cli_tests/wasi-http.wat +++ /dev/null @@ -1,93 +0,0 @@ -(module - (import "wasi_snapshot_preview1" "proc_exit" - (func $__wasi_proc_exit (param i32))) - (import "wasi:io/streams" "write" - (func $__wasi_io_streams_write (param i32 i32 i32 i32))) - (import "wasi:io/streams" "blocking-write-and-flush" - (func $__wasi_io_streams_blocking_write_and_flush (param i32 i32 i32 i32))) - (import "wasi:io/streams" "subscribe-to-output-stream" - (func $__wasi_io_streams_subscribe_to_output_stream (param i32) (result i32))) - (import "wasi:http/types" "new-fields" - (func $__wasi_http_types_new_fields (param i32 i32) (result i32))) - (import "wasi:http/types" "drop-fields" - (func $__wasi_http_types_drop_fields (param i32))) - (import "wasi:http/types" "new-outgoing-request" - (func $__wasi_http_types_new_outgoing_request (param i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32 i32) (result i32))) - (import "wasi:http/types" "outgoing-request-write" - (func $__wasi_http_types_outgoing_request_write (param i32 i32))) - (import "wasi:http/types" "drop-outgoing-request" - (func $__wasi_http_types_drop_outgoing_request (param i32))) - (func $_start - (local i32) - (local $headers_id i32) - (local $request_id i32) - (local $body_stream_id i32) - - ;; Print "Called _start". - (call $print (i32.const 32) (i32.const 14)) - - (local.set $headers_id (call $__wasi_http_types_new_fields - i32.const 0 ;; base pointer - i32.const 0 ;; length - )) - (local.set $request_id (call $__wasi_http_types_new_outgoing_request - i32.const 0 ;; method = Method::Get - i32.const 0 ;; method pointer - i32.const 0 ;; method length - i32.const 0 ;; path is some = None - i32.const 0 ;; path pointer - i32.const 0 ;; path length - i32.const 1 ;; scheme is some = Some - i32.const 1 ;; scheme = Scheme::Https - i32.const 0 ;; scheme pointer - i32.const 0 ;; scheme length - i32.const 1 ;; authority is some = Some - i32.const 96 ;; authority pointer = Constant value - i32.const 15 ;; authority length - local.get $headers_id ;; headers id - )) - (call $__wasi_http_types_outgoing_request_write (local.get $request_id) (local.get 0)) - local.get 0 - i32.const 4 - i32.add - i32.load - local.set $body_stream_id - (call $__wasi_io_streams_write - (local.get $body_stream_id) ;; body stream id (usually 8) - (i32.const 128) ;; body stream pointer - (i32.const 4) ;; body stream length - (i32.const 0) - ) - (drop (call $__wasi_io_streams_subscribe_to_output_stream (local.get $body_stream_id))) - (call $__wasi_http_types_drop_fields (local.get $headers_id)) - (call $__wasi_http_types_drop_outgoing_request (local.get $request_id)) - - (call $print (i32.const 64) (i32.const 5)) - (drop (call $__wasi_io_streams_subscribe_to_output_stream (i32.const 4))) - - (call $__wasi_proc_exit (i32.const 1)) - ) - - ;; A helper function for printing ptr-len strings. - (func $print (param $ptr i32) (param $len i32) - (call $__wasi_io_streams_blocking_write_and_flush - i32.const 4 ;; Value for stdout - local.get $ptr - local.get $len - i32.const 0 - ) - ) - - (func $cabi_realloc (param i32 i32 i32 i32) (result i32) - i32.const 0 - ) - - (memory 1) - (export "memory" (memory 0)) - (export "_start" (func $_start)) - (export "cabi_realloc" (func $cabi_realloc)) - (data (i32.const 32) "Called _start\0a") - (data (i32.const 64) "Done\0a") - (data (i32.const 96) "www.example.com") - (data (i32.const 128) "body") -)