|  | 
| 1 |  | -pub use wasi::http::types::{ | 
| 2 |  | -    Fields, IncomingRequest, OutgoingBody, OutgoingResponse, ResponseOutparam, | 
| 3 |  | -}; | 
| 4 |  | - | 
| 5 |  | -struct Component; | 
| 6 |  | -wasi::http::proxy::export!(Component); | 
| 7 |  | - | 
| 8 |  | -impl wasi::exports::http::incoming_handler::Guest for Component { | 
| 9 |  | -    fn handle(req: IncomingRequest, outparam: ResponseOutparam) { | 
| 10 |  | -        match req.path_with_query().unwrap().as_str() { | 
| 11 |  | -            "/wait" => http_wait(req, outparam), | 
| 12 |  | -            // "/echo" => {} // TODO | 
| 13 |  | -            // "/host" => {} // TODO | 
| 14 |  | -            "/" | _ => http_home(req, outparam), | 
| 15 |  | -        } | 
|  | 1 | +use wstd::http::body::{BodyForthcoming, IncomingBody}; | 
|  | 2 | +use wstd::http::server::{Finished, Responder}; | 
|  | 3 | +use wstd::http::{IntoBody, Request, Response, StatusCode}; | 
|  | 4 | +use wstd::io::{copy, empty, AsyncWrite}; | 
|  | 5 | +use wstd::time::{Duration, Instant}; | 
|  | 6 | + | 
|  | 7 | +#[wstd::http_server] | 
|  | 8 | +async fn main(req: Request<IncomingBody>, res: Responder) -> Finished { | 
|  | 9 | +    match req.uri().path_and_query().unwrap().as_str() { | 
|  | 10 | +        "/wait" => wait(req, res).await, | 
|  | 11 | +        "/echo" => echo(req, res).await, | 
|  | 12 | +        "/echo-headers" => echo_headers(req, res).await, | 
|  | 13 | +        "/echo-trailers" => echo_trailers(req, res).await, | 
|  | 14 | +        "/" => home(req, res).await, | 
|  | 15 | +        _ => not_found(req, res).await, | 
| 16 | 16 |     } | 
| 17 | 17 | } | 
| 18 | 18 | 
 | 
| 19 |  | -fn http_home(_req: IncomingRequest, outparam: ResponseOutparam) { | 
| 20 |  | -    let headers = Fields::new(); | 
| 21 |  | -    let res = OutgoingResponse::new(headers); | 
| 22 |  | -    let body = res.body().expect("outgoing response"); | 
| 23 |  | - | 
| 24 |  | -    ResponseOutparam::set(outparam, Ok(res)); | 
| 25 |  | - | 
| 26 |  | -    let out = body.write().expect("outgoing stream"); | 
| 27 |  | -    out.blocking_write_and_flush(b"Hello, wasi:http/proxy world!\n") | 
| 28 |  | -        .expect("writing response"); | 
| 29 |  | - | 
| 30 |  | -    drop(out); | 
| 31 |  | -    OutgoingBody::finish(body, None).unwrap(); | 
|  | 19 | +async fn home(_req: Request<IncomingBody>, res: Responder) -> Finished { | 
|  | 20 | +    // To send a single string as the response body, use `res::respond`. | 
|  | 21 | +    res.respond(Response::new("Hello, wasi:http/proxy world!\n".into_body())) | 
|  | 22 | +        .await | 
| 32 | 23 | } | 
| 33 | 24 | 
 | 
| 34 |  | -fn http_wait(_req: IncomingRequest, outparam: ResponseOutparam) { | 
|  | 25 | +async fn wait(_req: Request<IncomingBody>, res: Responder) -> Finished { | 
| 35 | 26 |     // Get the time now | 
| 36 |  | -    let now = wasi::clocks::monotonic_clock::now(); | 
|  | 27 | +    let now = Instant::now(); | 
| 37 | 28 | 
 | 
| 38 |  | -    // Sleep for 1 second | 
| 39 |  | -    let nanos = 1_000_000_000; | 
| 40 |  | -    let pollable = wasi::clocks::monotonic_clock::subscribe_duration(nanos); | 
| 41 |  | -    pollable.block(); | 
|  | 29 | +    // Sleep for one second. | 
|  | 30 | +    wstd::task::sleep(Duration::from_secs(1)).await; | 
| 42 | 31 | 
 | 
| 43 | 32 |     // Compute how long we slept for. | 
| 44 |  | -    let elapsed = wasi::clocks::monotonic_clock::now() - now; | 
| 45 |  | -    let elapsed = elapsed / 1_000_000; // change to millis | 
|  | 33 | +    let elapsed = Instant::now().duration_since(now).as_millis(); | 
| 46 | 34 | 
 | 
| 47 |  | -    let headers = Fields::new(); | 
| 48 |  | -    let res = OutgoingResponse::new(headers); | 
| 49 |  | -    let body = res.body().expect("outgoing response"); | 
|  | 35 | +    // To stream data to the response body, use `res::start_response`. | 
|  | 36 | +    let mut body = res.start_response(Response::new(BodyForthcoming)); | 
|  | 37 | +    let result = body | 
|  | 38 | +        .write_all(format!("slept for {elapsed} millis\n").as_bytes()) | 
|  | 39 | +        .await; | 
|  | 40 | +    Finished::finish(body, result, None) | 
|  | 41 | +} | 
| 50 | 42 | 
 | 
| 51 |  | -    ResponseOutparam::set(outparam, Ok(res)); | 
|  | 43 | +async fn echo(mut req: Request<IncomingBody>, res: Responder) -> Finished { | 
|  | 44 | +    // Stream data from the req body to the response body. | 
|  | 45 | +    let mut body = res.start_response(Response::new(BodyForthcoming)); | 
|  | 46 | +    let result = copy(req.body_mut(), &mut body).await; | 
|  | 47 | +    Finished::finish(body, result, None) | 
|  | 48 | +} | 
|  | 49 | + | 
|  | 50 | +async fn echo_headers(req: Request<IncomingBody>, responder: Responder) -> Finished { | 
|  | 51 | +    let mut res = Response::builder(); | 
|  | 52 | +    *res.headers_mut().unwrap() = req.into_parts().0.headers; | 
|  | 53 | +    let res = res.body(empty()).unwrap(); | 
|  | 54 | +    responder.respond(res).await | 
|  | 55 | +} | 
| 52 | 56 | 
 | 
| 53 |  | -    let out = body.write().expect("outgoing stream"); | 
| 54 |  | -    let msg = format!("slept for {elapsed} millis\n"); | 
| 55 |  | -    out.blocking_write_and_flush(msg.as_bytes()) | 
| 56 |  | -        .expect("writing response"); | 
|  | 57 | +async fn echo_trailers(req: Request<IncomingBody>, res: Responder) -> Finished { | 
|  | 58 | +    let body = res.start_response(Response::new(BodyForthcoming)); | 
|  | 59 | +    let (trailers, result) = match req.into_body().finish().await { | 
|  | 60 | +        Ok(trailers) => (trailers, Ok(())), | 
|  | 61 | +        Err(err) => (Default::default(), Err(std::io::Error::other(err))), | 
|  | 62 | +    }; | 
|  | 63 | +    Finished::finish(body, result, trailers) | 
|  | 64 | +} | 
| 57 | 65 | 
 | 
| 58 |  | -    drop(out); | 
| 59 |  | -    OutgoingBody::finish(body, None).unwrap(); | 
|  | 66 | +async fn not_found(_req: Request<IncomingBody>, responder: Responder) -> Finished { | 
|  | 67 | +    let res = Response::builder() | 
|  | 68 | +        .status(StatusCode::NOT_FOUND) | 
|  | 69 | +        .body(empty()) | 
|  | 70 | +        .unwrap(); | 
|  | 71 | +    responder.respond(res).await | 
| 60 | 72 | } | 
0 commit comments