Skip to content

Commit 2142719

Browse files
committed
Add a http server proxy example
1 parent 2218692 commit 2142719

File tree

2 files changed

+92
-0
lines changed

2 files changed

+92
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ serde_json = { workspace = true, optional = true }
3131
[dev-dependencies]
3232
anyhow.workspace = true
3333
clap.workspace = true
34+
futures-concurrency.workspace = true
3435
futures-lite.workspace = true
3536
humantime.workspace = true
3637
serde = { workspace = true, features = ["derive"] }
@@ -61,6 +62,7 @@ authors = [
6162
anyhow = "1"
6263
cargo_metadata = "0.18.1"
6364
clap = { version = "4.5.26", features = ["derive"] }
65+
futures-concurrency = "7.6.3"
6466
futures-core = "0.3.19"
6567
futures-lite = "1.12.0"
6668
humantime = "2.1.0"

examples/http_server_proxy.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// Run the example with:
2+
// wasmtime serve -Scli -Shttp --env TARGET_URL=https://example.com http_server_proxy.wasm
3+
use futures_concurrency::prelude::*;
4+
use wstd::http::body::{BodyForthcoming, IncomingBody};
5+
use wstd::http::server::{Finished, Responder};
6+
use wstd::http::{Client, Request, Response, StatusCode, Uri};
7+
use wstd::io::{copy, empty};
8+
9+
const PROXY_PREFIX: &str = "/proxy";
10+
11+
#[wstd::http_server]
12+
async fn main(mut server_req: Request<IncomingBody>, responder: Responder) -> Finished {
13+
match server_req.uri().path_and_query().unwrap().as_str() {
14+
api_prefixed_path if api_prefixed_path.starts_with(PROXY_PREFIX) => {
15+
// Remove PROXY_PREFIX
16+
let target_url =
17+
std::env::var("TARGET_URL").expect("missing environment variable TARGET_URL");
18+
let target_url: Uri = format!(
19+
"{target_url}{}",
20+
api_prefixed_path
21+
.strip_prefix(PROXY_PREFIX)
22+
.expect("checked above")
23+
)
24+
.parse()
25+
.expect("final target url should be parseable");
26+
27+
let client = Client::new();
28+
let mut client_req = Request::builder();
29+
client_req = client_req.uri(target_url).method(server_req.method());
30+
31+
// Copy headers from server request to the client request.
32+
for (key, value) in server_req.headers() {
33+
client_req = client_req.header(key, value);
34+
}
35+
36+
// Send the request.
37+
let client_req = client_req
38+
.body(BodyForthcoming)
39+
.expect("client_req.body failed");
40+
let (mut client_request_body, client_resp) = client
41+
.start_request(client_req)
42+
.await
43+
.expect("client.start_request failed");
44+
45+
// Copy the server request body to client's request body.
46+
let server_req_to_client_req = async {
47+
let res = copy(server_req.body_mut(), &mut client_request_body).await;
48+
// TODO: Convert to io error if necessary
49+
let _ = Client::finish(client_request_body, None);
50+
res
51+
};
52+
53+
// Copy the client response headers to server response.
54+
let client_resp_to_server_resp = async {
55+
let client_resp = client_resp.await.unwrap();
56+
let mut server_resp = Response::builder();
57+
for (key, value) in client_resp.headers() {
58+
server_resp
59+
.headers_mut()
60+
.unwrap()
61+
.append(key, value.clone());
62+
}
63+
// Start sending the server response.
64+
let server_resp = server_resp.body(BodyForthcoming).unwrap();
65+
let mut server_resp = responder.start_response(server_resp);
66+
67+
(
68+
copy(client_resp.into_body(), &mut server_resp).await,
69+
server_resp,
70+
)
71+
};
72+
73+
let (server_req_to_client_req, (client_resp_to_server_resp, server_resp)) =
74+
(server_req_to_client_req, client_resp_to_server_resp)
75+
.join()
76+
.await;
77+
let is_success = server_req_to_client_req.and(client_resp_to_server_resp);
78+
Finished::finish(server_resp, is_success, None)
79+
}
80+
_ => http_not_found(server_req, responder).await,
81+
}
82+
}
83+
84+
async fn http_not_found(_request: Request<IncomingBody>, responder: Responder) -> Finished {
85+
let response = Response::builder()
86+
.status(StatusCode::NOT_FOUND)
87+
.body(empty())
88+
.unwrap();
89+
responder.respond(response).await
90+
}

0 commit comments

Comments
 (0)