|
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