|
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