Browse Source

Ensure that scheme and authority are populated in the incoming handler (#7545)

pull/7548/head
Trevor Elliott 12 months ago
committed by GitHub
parent
commit
bba4ee78a9
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Cargo.lock
  2. 3
      Cargo.toml
  3. 4
      crates/test-programs/src/bin/api_proxy.rs
  4. 2
      crates/test-programs/src/bin/api_proxy_streaming.rs
  5. 19
      crates/wasi-http/tests/all/main.rs
  6. 39
      src/commands/serve.rs

1
Cargo.lock

@ -3322,6 +3322,7 @@ dependencies = [
"criterion",
"env_logger 0.10.0",
"filecheck",
"http",
"http-body-util",
"humantime 2.1.0",
"hyper",

3
Cargo.toml

@ -54,6 +54,7 @@ async-trait = { workspace = true }
bytes = { workspace = true }
tokio = { workspace = true, optional = true, features = [ "signal", "macros" ] }
hyper = { workspace = true, optional = true }
http = { workspace = true, optional = true }
http-body-util = { workspace = true, optional = true }
[target.'cfg(unix)'.dependencies]
@ -359,7 +360,7 @@ old-cli = []
# CLI subcommands for the `wasmtime` executable. See `wasmtime $cmd --help`
# for more information on each subcommand.
serve = ["wasi-http", "component-model", "dep:http-body-util"]
serve = ["wasi-http", "component-model", "dep:http-body-util", "dep:http"]
explore = ["dep:wasmtime-explorer"]
wast = ["dep:wasmtime-wast"]
config = ["cache"]

4
crates/test-programs/src/bin/api_proxy.rs

@ -16,6 +16,10 @@ struct T;
impl bindings::exports::wasi::http::incoming_handler::Guest for T {
fn handle(request: IncomingRequest, outparam: ResponseOutparam) {
assert!(request.scheme().is_some());
assert!(request.authority().is_some());
assert!(request.path_with_query().is_some());
let header = String::from("custom-forbidden-header");
let req_hdrs = request.headers();

2
crates/test-programs/src/bin/api_proxy_streaming.rs

@ -33,6 +33,8 @@ impl bindings::exports::wasi::http::incoming_handler::Guest for Handler {
async fn handle_request(request: IncomingRequest, response_out: ResponseOutparam) {
let headers = request.headers().entries();
assert!(request.authority().is_some());
match (request.method(), request.path_with_query().as_deref()) {
(Method::Get, Some("/hash-all")) => {
// Send outgoing GET requests to the specified URLs and stream the hashes of the response bodies as

19
crates/wasi-http/tests/all/main.rs

@ -199,11 +199,10 @@ async fn run_wasi_http(
#[test_log::test(tokio::test)]
async fn wasi_http_proxy_tests() -> anyhow::Result<()> {
let mut req = hyper::Request::builder().method(http::Method::GET);
req.headers_mut()
.unwrap()
.append("custom-forbidden-header", "yes".parse().unwrap());
let req = hyper::Request::builder()
.header("custom-forbidden-header", "yes")
.uri("http://example.com:8080/test-path")
.method(http::Method::GET);
let resp = run_wasi_http(
test_programs_artifacts::API_PROXY_COMPONENT,
@ -326,7 +325,9 @@ async fn do_wasi_http_hash_all(override_send_request: bool) -> Result<()> {
None
};
let mut request = hyper::Request::get("/hash-all");
let mut request = hyper::Request::builder()
.method(http::Method::GET)
.uri("http://example.com:8080/hash-all");
for path in bodies.keys() {
request = request.header("url", format!("{prefix}{path}"));
}
@ -448,8 +449,10 @@ async fn do_wasi_http_echo(uri: &str, url_header: Option<&str>) -> Result<()> {
.collect::<Vec<_>>()
};
let mut request =
hyper::Request::post(&format!("/{uri}")).header("content-type", "application/octet-stream");
let mut request = hyper::Request::builder()
.method(http::Method::POST)
.uri(format!("http://example.com:8080/{uri}"))
.header("content-type", "application/octet-stream");
if let Some(url_header) = url_header {
request = request.header("url", url_header);

39
src/commands/serve.rs

@ -15,7 +15,8 @@ use wasmtime_wasi::preview2::{
self, StreamError, StreamResult, Table, WasiCtx, WasiCtxBuilder, WasiView,
};
use wasmtime_wasi_http::{
body::HyperOutgoingBody, hyper_response_error, WasiHttpCtx, WasiHttpView,
bindings::http::types as http_types, body::HyperOutgoingBody, hyper_response_error,
WasiHttpCtx, WasiHttpView,
};
#[cfg(feature = "wasi-nn")]
@ -356,6 +357,37 @@ impl hyper::service::Service<Request> for ProxyHandler {
// TODO: need to track the join handle, but don't want to block the response on it
tokio::task::spawn(async move {
let req_id = inner.next_req_id();
let (mut parts, body) = req.into_parts();
parts.uri = {
let uri_parts = parts.uri.into_parts();
let scheme = uri_parts.scheme.unwrap_or(http::uri::Scheme::HTTP);
let host = if let Some(val) = parts.headers.get(hyper::header::HOST) {
std::str::from_utf8(val.as_bytes())
.map_err(|_| http_types::ErrorCode::HttpRequestUriInvalid)?
} else {
uri_parts
.authority
.as_ref()
.ok_or(http_types::ErrorCode::HttpRequestUriInvalid)?
.host()
};
let path_with_query = uri_parts
.path_and_query
.ok_or(http_types::ErrorCode::HttpRequestUriInvalid)?;
hyper::Uri::builder()
.scheme(scheme)
.authority(host)
.path_and_query(path_with_query)
.build()
.map_err(|_| http_types::ErrorCode::HttpRequestUriInvalid)?
};
let req = hyper::Request::from_parts(parts, body.map_err(hyper_response_error).boxed());
log::info!(
"Request {req_id} handling {} to {}",
@ -365,10 +397,7 @@ impl hyper::service::Service<Request> for ProxyHandler {
let mut store = inner.cmd.new_store(&inner.engine, req_id)?;
let req = store
.data_mut()
.new_incoming_request(req.map(|body| body.map_err(hyper_response_error).boxed()))?;
let req = store.data_mut().new_incoming_request(req)?;
let out = store.data_mut().new_response_outparam(sender)?;
let (proxy, _inst) =

Loading…
Cancel
Save