16f6a514bSRoman Volosatovs use {
26f6a514bSRoman Volosatovs     flate2::{
36f6a514bSRoman Volosatovs         Compression,
46f6a514bSRoman Volosatovs         write::{DeflateDecoder, DeflateEncoder},
56f6a514bSRoman Volosatovs     },
66f6a514bSRoman Volosatovs     std::{io::Write, mem},
76f6a514bSRoman Volosatovs     test_programs::p3::{
86f6a514bSRoman Volosatovs         wasi::http::{
96f6a514bSRoman Volosatovs             handler,
106f6a514bSRoman Volosatovs             types::{ErrorCode, Headers, Request, Response},
116f6a514bSRoman Volosatovs         },
126f6a514bSRoman Volosatovs         wit_future, wit_stream,
136f6a514bSRoman Volosatovs     },
141047b511SAlex Crichton     wit_bindgen::StreamResult,
156f6a514bSRoman Volosatovs };
166f6a514bSRoman Volosatovs 
171cc0bcffSBailey Hayes wit_bindgen::generate!({
181cc0bcffSBailey Hayes     path: "../wasi-http/src/p3/wit",
191cc0bcffSBailey Hayes     world: "wasi:http/middleware",
201cc0bcffSBailey Hayes     with: {
21*5d3627b7SBailey Hayes         "wasi:http/handler@0.3.0-rc-2026-03-15": test_programs::p3::wasi::http::handler,
22*5d3627b7SBailey Hayes         "wasi:http/types@0.3.0-rc-2026-03-15": test_programs::p3::wasi::http::types,
23*5d3627b7SBailey Hayes         "wasi:http/client@0.3.0-rc-2026-03-15": test_programs::p3::wasi::http::client,
24*5d3627b7SBailey Hayes         "wasi:random/random@0.3.0-rc-2026-03-15": test_programs::p3::wasi::random::random,
25*5d3627b7SBailey Hayes         "wasi:random/insecure@0.3.0-rc-2026-03-15": test_programs::p3::wasi::random::insecure,
26*5d3627b7SBailey Hayes         "wasi:random/insecure-seed@0.3.0-rc-2026-03-15": test_programs::p3::wasi::random::insecure_seed,
27*5d3627b7SBailey Hayes         "wasi:cli/stdout@0.3.0-rc-2026-03-15": test_programs::p3::wasi::cli::stdout,
28*5d3627b7SBailey Hayes         "wasi:cli/stderr@0.3.0-rc-2026-03-15": test_programs::p3::wasi::cli::stderr,
29*5d3627b7SBailey Hayes         "wasi:cli/stdin@0.3.0-rc-2026-03-15": test_programs::p3::wasi::cli::stdin,
30*5d3627b7SBailey Hayes         "wasi:cli/types@0.3.0-rc-2026-03-15": test_programs::p3::wasi::cli::types,
31*5d3627b7SBailey Hayes         "wasi:clocks/monotonic-clock@0.3.0-rc-2026-03-15": test_programs::p3::wasi::clocks::monotonic_clock,
32*5d3627b7SBailey Hayes         "wasi:clocks/system-clock@0.3.0-rc-2026-03-15": test_programs::p3::wasi::clocks::system_clock,
33*5d3627b7SBailey Hayes         "wasi:clocks/types@0.3.0-rc-2026-03-15": test_programs::p3::wasi::clocks::types,
341cc0bcffSBailey Hayes     },
351cc0bcffSBailey Hayes });
361cc0bcffSBailey Hayes 
376f6a514bSRoman Volosatovs struct Component;
386f6a514bSRoman Volosatovs 
391cc0bcffSBailey Hayes export!(Component);
406f6a514bSRoman Volosatovs 
411cc0bcffSBailey Hayes impl exports::wasi::http::handler::Guest for Component {
426f6a514bSRoman Volosatovs     /// Forward the specified request to the imported `wasi:http/handler`, transparently decoding the request body
436f6a514bSRoman Volosatovs     /// if it is `deflate`d and then encoding the response body if the client has provided an `accept-encoding:
446f6a514bSRoman Volosatovs     /// deflate` header.
handle(request: Request) -> Result<Response, ErrorCode>456f6a514bSRoman Volosatovs     async fn handle(request: Request) -> Result<Response, ErrorCode> {
466f6a514bSRoman Volosatovs         // First, extract the parts of the request and check for (and remove) headers pertaining to body encodings.
476f6a514bSRoman Volosatovs         let method = request.get_method();
486f6a514bSRoman Volosatovs         let scheme = request.get_scheme();
496f6a514bSRoman Volosatovs         let path_with_query = request.get_path_with_query();
506f6a514bSRoman Volosatovs         let authority = request.get_authority();
516f6a514bSRoman Volosatovs         let mut accept_deflated = false;
526f6a514bSRoman Volosatovs         let mut content_deflated = false;
536f6a514bSRoman Volosatovs         let headers = request.get_headers();
546f6a514bSRoman Volosatovs         let mut headers = headers.copy_all();
556f6a514bSRoman Volosatovs         headers.retain(|(k, v)| match (k.as_str(), v.as_slice()) {
566f6a514bSRoman Volosatovs             ("accept-encoding", value)
576f6a514bSRoman Volosatovs                 if std::str::from_utf8(value)
586f6a514bSRoman Volosatovs                     .map(|v| v.contains("deflate"))
596f6a514bSRoman Volosatovs                     .unwrap_or(false) =>
606f6a514bSRoman Volosatovs             {
616f6a514bSRoman Volosatovs                 accept_deflated = true;
626f6a514bSRoman Volosatovs                 false
636f6a514bSRoman Volosatovs             }
646f6a514bSRoman Volosatovs             ("content-encoding", b"deflate") => {
656f6a514bSRoman Volosatovs                 content_deflated = true;
666f6a514bSRoman Volosatovs                 false
676f6a514bSRoman Volosatovs             }
686f6a514bSRoman Volosatovs             _ => true,
696f6a514bSRoman Volosatovs         });
7053059995SRoman Volosatovs         let (_, result_rx) = wit_future::new(|| Ok(()));
7153059995SRoman Volosatovs         let (mut body, trailers) = Request::consume_body(request, result_rx);
726f6a514bSRoman Volosatovs 
736f6a514bSRoman Volosatovs         let (body, trailers) = if content_deflated {
746f6a514bSRoman Volosatovs             // Next, spawn a task to pipe and decode the original request body and trailers into a new request
756f6a514bSRoman Volosatovs             // we'll create below.  This will run concurrently with any code in the imported `wasi:http/handler`.
766f6a514bSRoman Volosatovs             let (trailers_tx, trailers_rx) = wit_future::new(|| todo!());
776f6a514bSRoman Volosatovs             let (mut pipe_tx, pipe_rx) = wit_stream::new();
786f6a514bSRoman Volosatovs 
791047b511SAlex Crichton             wit_bindgen::spawn(async move {
806f6a514bSRoman Volosatovs                 {
816f6a514bSRoman Volosatovs                     let mut decoder = DeflateDecoder::new(Vec::new());
82da633618SJoel Dice                     let mut status = StreamResult::Complete(0);
83da633618SJoel Dice                     let mut chunk = Vec::with_capacity(64 * 1024);
846f6a514bSRoman Volosatovs 
856f6a514bSRoman Volosatovs                     while let StreamResult::Complete(_) = status {
86da633618SJoel Dice                         (status, chunk) = body.read(chunk).await;
876f6a514bSRoman Volosatovs                         decoder.write_all(&chunk).unwrap();
886f6a514bSRoman Volosatovs                         let remaining = pipe_tx.write_all(mem::take(decoder.get_mut())).await;
896f6a514bSRoman Volosatovs                         assert!(remaining.is_empty());
906f6a514bSRoman Volosatovs                         *decoder.get_mut() = remaining;
916f6a514bSRoman Volosatovs                         chunk.clear();
926f6a514bSRoman Volosatovs                     }
936f6a514bSRoman Volosatovs 
946f6a514bSRoman Volosatovs                     let remaining = pipe_tx.write_all(decoder.finish().unwrap()).await;
956f6a514bSRoman Volosatovs                     assert!(remaining.is_empty());
966f6a514bSRoman Volosatovs 
976f6a514bSRoman Volosatovs                     drop(pipe_tx);
986f6a514bSRoman Volosatovs                 }
996f6a514bSRoman Volosatovs 
1006f6a514bSRoman Volosatovs                 trailers_tx.write(trailers.await).await.unwrap();
1016f6a514bSRoman Volosatovs             });
1026f6a514bSRoman Volosatovs 
1036f6a514bSRoman Volosatovs             (pipe_rx, trailers_rx)
1046f6a514bSRoman Volosatovs         } else {
1056f6a514bSRoman Volosatovs             (body, trailers)
1066f6a514bSRoman Volosatovs         };
1076f6a514bSRoman Volosatovs 
1086f6a514bSRoman Volosatovs         // While the above task (if any) is running, synthesize a request from the parts collected above and pass
1096f6a514bSRoman Volosatovs         // it to the imported `wasi:http/handler`.
1106f6a514bSRoman Volosatovs         let (my_request, _request_complete) = Request::new(
1116f6a514bSRoman Volosatovs             Headers::from_list(&headers).unwrap(),
1126f6a514bSRoman Volosatovs             Some(body),
1136f6a514bSRoman Volosatovs             trailers,
1146f6a514bSRoman Volosatovs             None,
1156f6a514bSRoman Volosatovs         );
1166f6a514bSRoman Volosatovs         my_request.set_method(&method).unwrap();
1176f6a514bSRoman Volosatovs         my_request.set_scheme(scheme.as_ref()).unwrap();
1186f6a514bSRoman Volosatovs         my_request
1196f6a514bSRoman Volosatovs             .set_path_with_query(path_with_query.as_deref())
1206f6a514bSRoman Volosatovs             .unwrap();
1216f6a514bSRoman Volosatovs         my_request.set_authority(authority.as_deref()).unwrap();
1226f6a514bSRoman Volosatovs 
1236f6a514bSRoman Volosatovs         let response = handler::handle(my_request).await?;
1246f6a514bSRoman Volosatovs 
1256f6a514bSRoman Volosatovs         // Now that we have the response, extract the parts, adding an extra header if we'll be encoding the body.
1266f6a514bSRoman Volosatovs         let status_code = response.get_status_code();
1276f6a514bSRoman Volosatovs         let mut headers = response.get_headers().copy_all();
1286f6a514bSRoman Volosatovs         if accept_deflated {
1296f6a514bSRoman Volosatovs             headers.push(("content-encoding".into(), b"deflate".into()));
1306f6a514bSRoman Volosatovs         }
1316f6a514bSRoman Volosatovs 
13253059995SRoman Volosatovs         let (_, result_rx) = wit_future::new(|| Ok(()));
13353059995SRoman Volosatovs         let (mut body, trailers) = Response::consume_body(response, result_rx);
1346f6a514bSRoman Volosatovs         let (body, trailers) = if accept_deflated {
1356f6a514bSRoman Volosatovs             headers.retain(|(name, _value)| name != "content-length");
1366f6a514bSRoman Volosatovs 
1376f6a514bSRoman Volosatovs             // Spawn another task; this one is to pipe and encode the original response body and trailers into a
1386f6a514bSRoman Volosatovs             // new response we'll create below.  This will run concurrently with the caller's code (i.e. it won't
1396f6a514bSRoman Volosatovs             // necessarily complete before we return a value).
1406f6a514bSRoman Volosatovs             let (trailers_tx, trailers_rx) = wit_future::new(|| todo!());
1416f6a514bSRoman Volosatovs             let (mut pipe_tx, pipe_rx) = wit_stream::new();
1426f6a514bSRoman Volosatovs 
1431047b511SAlex Crichton             wit_bindgen::spawn(async move {
1446f6a514bSRoman Volosatovs                 {
1456f6a514bSRoman Volosatovs                     let mut encoder = DeflateEncoder::new(Vec::new(), Compression::fast());
146da633618SJoel Dice                     let mut status = StreamResult::Complete(0);
147da633618SJoel Dice                     let mut chunk = Vec::with_capacity(64 * 1024);
1486f6a514bSRoman Volosatovs 
1496f6a514bSRoman Volosatovs                     while let StreamResult::Complete(_) = status {
150da633618SJoel Dice                         (status, chunk) = body.read(chunk).await;
1516f6a514bSRoman Volosatovs                         encoder.write_all(&chunk).unwrap();
1526f6a514bSRoman Volosatovs                         let remaining = pipe_tx.write_all(mem::take(encoder.get_mut())).await;
1536f6a514bSRoman Volosatovs                         assert!(remaining.is_empty());
1546f6a514bSRoman Volosatovs                         *encoder.get_mut() = remaining;
1556f6a514bSRoman Volosatovs                         chunk.clear();
1566f6a514bSRoman Volosatovs                     }
1576f6a514bSRoman Volosatovs 
1586f6a514bSRoman Volosatovs                     let remaining = pipe_tx.write_all(encoder.finish().unwrap()).await;
1596f6a514bSRoman Volosatovs                     assert!(remaining.is_empty());
1606f6a514bSRoman Volosatovs 
1616f6a514bSRoman Volosatovs                     drop(pipe_tx);
1626f6a514bSRoman Volosatovs                 }
1636f6a514bSRoman Volosatovs 
1646f6a514bSRoman Volosatovs                 trailers_tx.write(trailers.await).await.unwrap();
1656f6a514bSRoman Volosatovs             });
1666f6a514bSRoman Volosatovs 
1676f6a514bSRoman Volosatovs             (pipe_rx, trailers_rx)
1686f6a514bSRoman Volosatovs         } else {
1696f6a514bSRoman Volosatovs             (body, trailers)
1706f6a514bSRoman Volosatovs         };
1716f6a514bSRoman Volosatovs 
1726f6a514bSRoman Volosatovs         // While the above tasks (if any) are running, synthesize a response from the parts collected above and
1736f6a514bSRoman Volosatovs         // return it.
1746f6a514bSRoman Volosatovs         let (my_response, _response_complete) =
1756f6a514bSRoman Volosatovs             Response::new(Headers::from_list(&headers).unwrap(), Some(body), trailers);
1766f6a514bSRoman Volosatovs         my_response.set_status_code(status_code).unwrap();
1776f6a514bSRoman Volosatovs 
1786f6a514bSRoman Volosatovs         Ok(my_response)
1796f6a514bSRoman Volosatovs     }
1806f6a514bSRoman Volosatovs }
1816f6a514bSRoman Volosatovs 
1826f6a514bSRoman Volosatovs // Unused function; required since this file is built as a `bin`:
main()1836f6a514bSRoman Volosatovs fn main() {}
184