22// cargo build --example http_server_proxy --target=wasm32-wasip2
33// wasmtime serve -Scli -Shttp --env TARGET_URL=https://example.com/ target/wasm32-wasip2/debug/examples/http_server_proxy.wasm
44// Test with `curl --no-buffer -v 127.0.0.1:8080/proxy/`
5- use futures_concurrency:: prelude:: * ;
6- use wstd:: http:: body:: { BodyForthcoming , IncomingBody } ;
7- use wstd:: http:: server:: { Finished , Responder } ;
8- use wstd:: http:: { Client , Request , Response , StatusCode , Uri } ;
9- use wstd:: io:: { copy, empty} ;
5+
6+ use wstd:: http:: body:: { Body , Bytes } ;
7+ use wstd:: http:: { Client , Error , Request , Response , StatusCode , Uri } ;
108
119const PROXY_PREFIX : & str = "/proxy/" ;
1210
1311#[ wstd:: http_server]
14- async fn main ( mut server_req : Request < IncomingBody > , responder : Responder ) -> Finished {
12+ async fn main ( server_req : Request < Body > ) -> Result < Response < Body > , Error > {
1513 match server_req. uri ( ) . path_and_query ( ) . unwrap ( ) . as_str ( ) {
1614 api_prefixed_path if api_prefixed_path. starts_with ( PROXY_PREFIX ) => {
1715 // Remove PROXY_PREFIX
@@ -26,73 +24,44 @@ async fn main(mut server_req: Request<IncomingBody>, responder: Responder) -> Fi
2624 . parse ( )
2725 . expect ( "final target url should be parseable" ) ;
2826 println ! ( "Proxying to {target_url}" ) ;
27+ proxy ( server_req, target_url) . await
28+ }
29+ _ => Ok ( http_not_found ( server_req) ) ,
30+ }
31+ }
2932
30- let client = Client :: new ( ) ;
31- let mut client_req = Request :: builder ( ) ;
32- client_req = client_req. uri ( target_url) . method ( server_req. method ( ) ) ;
33-
34- // Copy headers from server request to the client request.
35- for ( key, value) in server_req. headers ( ) {
36- client_req = client_req. header ( key, value) ;
37- }
38-
39- // Send the request.
40- let client_req = client_req
41- . body ( BodyForthcoming )
42- . expect ( "client_req.body failed" ) ;
43- let ( mut client_request_body, client_resp) = client
44- . start_request ( client_req)
45- . await
46- . expect ( "client.start_request failed" ) ;
47-
48- // Copy the server request body to client's request body.
49- let server_req_to_client_req = async {
50- let res = copy ( server_req. body_mut ( ) , & mut client_request_body) . await ;
51- Client :: finish ( client_request_body, None )
52- . map_err ( |_http_err| {
53- std:: io:: Error :: new (
54- std:: io:: ErrorKind :: InvalidData ,
55- "Failed write the HTTP request body" ,
56- )
57- } )
58- . and ( res)
59- } ;
60-
61- // Copy the client response headers to server response.
62- let client_resp_to_server_resp = async {
63- let client_resp = client_resp. await . unwrap ( ) ;
64- let mut server_resp = Response :: builder ( ) ;
65- for ( key, value) in client_resp. headers ( ) {
66- server_resp
67- . headers_mut ( )
68- . unwrap ( )
69- . append ( key, value. clone ( ) ) ;
70- }
71- // Start sending the server response.
72- let server_resp = server_resp. body ( BodyForthcoming ) . unwrap ( ) ;
73- let mut server_resp = responder. start_response ( server_resp) ;
33+ async fn proxy ( server_req : Request < Body > , target_url : Uri ) -> Result < Response < Body > , Error > {
34+ let client = Client :: new ( ) ;
35+ let mut client_req = Request :: builder ( ) ;
36+ client_req = client_req. uri ( target_url) . method ( server_req. method ( ) ) ;
7437
75- (
76- copy ( client_resp. into_body ( ) , & mut server_resp) . await ,
77- server_resp,
78- )
79- } ;
38+ // Copy headers from `server_req` to the `client_req`.
39+ for ( key, value) in server_req. headers ( ) {
40+ client_req = client_req. header ( key, value) ;
41+ }
8042
81- let ( server_req_to_client_req, ( client_resp_to_server_resp, server_resp) ) =
82- ( server_req_to_client_req, client_resp_to_server_resp)
83- . join ( )
84- . await ;
85- let is_success = server_req_to_client_req. and ( client_resp_to_server_resp) ;
86- Finished :: finish ( server_resp, is_success, None )
87- }
88- _ => http_not_found ( server_req, responder) . await ,
43+ // Stream the request body.
44+ let client_body = Body :: from_http_body ( server_req. into_body ( ) . into_boxed_body ( ) ) ;
45+ let client_req = client_req. body ( client_body) ?;
46+ // Send the request.
47+ let client_resp = client. send ( client_req) . await ?;
48+ // Copy headers from `client_resp` to `server_resp`.
49+ let mut server_resp = Response :: builder ( ) ;
50+ for ( key, value) in client_resp. headers ( ) {
51+ server_resp
52+ . headers_mut ( )
53+ . expect ( "no errors could be in ResponseBuilder" )
54+ . append ( key, value. clone ( ) ) ;
8955 }
56+ // FIXME: Convert UnsyncBoxBody<Bytes, Error> to Response<Body>
57+ server_resp
58+ . body ( client_resp. into_body ( ) . into_boxed_body ( ) )
59+ . map_err ( Error :: from)
9060}
9161
92- async fn http_not_found ( _request : Request < IncomingBody > , responder : Responder ) -> Finished {
93- let response = Response :: builder ( )
62+ fn http_not_found ( _request : Request < Body > ) -> Response < Body > {
63+ Response :: builder ( )
9464 . status ( StatusCode :: NOT_FOUND )
95- . body ( empty ( ) )
96- . unwrap ( ) ;
97- responder. respond ( response) . await
65+ . body ( Body :: empty ( ) )
66+ . unwrap ( )
9867}
0 commit comments