1use std::collections::HashMap;
2
3use async_trait::async_trait;
4
5use wasi::io::streams;
6
7use super::{
8 Headers, IncomingRequest, IncomingResponse, Method, OutgoingRequest, OutgoingResponse,
9 RequestBuilder,
10};
11#[cfg(feature = "json")]
12use super::{Json, JsonBodyError};
13
14use super::{responses, NonUtf8BodyError, Request, Response};
15
16impl TryFrom<Response> for OutgoingResponse {
17 type Error = anyhow::Error;
18
19 fn try_from(response: Response) -> anyhow::Result<Self> {
20 let headers = response
21 .headers
22 .into_iter()
23 .map(|(k, v)| (k, v.into_bytes()))
24 .collect::<Vec<_>>();
25 let res = OutgoingResponse::new(Headers::from_list(&headers)?);
26 res.set_status_code(response.status)
27 .map_err(|()| anyhow::anyhow!("error setting status code to {}", response.status))?;
28 Ok(res)
29 }
30}
31
32#[async_trait]
34pub trait TryFromIncomingRequest {
35 type Error;
37
38 async fn try_from_incoming_request(value: IncomingRequest) -> Result<Self, Self::Error>
40 where
41 Self: Sized;
42}
43
44#[async_trait]
45impl TryFromIncomingRequest for IncomingRequest {
46 type Error = std::convert::Infallible;
47 async fn try_from_incoming_request(request: IncomingRequest) -> Result<Self, Self::Error> {
48 Ok(request)
49 }
50}
51
52#[async_trait]
53impl<R> TryFromIncomingRequest for R
54where
55 R: TryNonRequestFromRequest,
56{
57 type Error = IncomingRequestError<R::Error>;
58
59 async fn try_from_incoming_request(request: IncomingRequest) -> Result<Self, Self::Error> {
60 let req = Request::try_from_incoming_request(request)
61 .await
62 .map_err(convert_error)?;
63 R::try_from_request(req).map_err(IncomingRequestError::ConversionError)
64 }
65}
66
67#[async_trait]
68impl TryFromIncomingRequest for Request {
69 type Error = IncomingRequestError;
70
71 async fn try_from_incoming_request(request: IncomingRequest) -> Result<Self, Self::Error> {
72 Ok(Request::builder()
73 .method(request.method())
74 .uri(request.uri())
75 .headers(request.headers())
76 .body(request.into_body().await.map_err(|e| {
77 IncomingRequestError::BodyConversionError(anyhow::anyhow!(
78 "{}",
79 e.to_debug_string()
80 ))
81 })?)
82 .build())
83 }
84}
85
86#[derive(Debug, thiserror::Error)]
87pub enum IncomingRequestError<E = std::convert::Infallible> {
89 #[error(transparent)]
91 BodyConversionError(anyhow::Error),
92 #[error(transparent)]
94 ConversionError(E),
95}
96
97fn convert_error<E>(
100 error: IncomingRequestError<std::convert::Infallible>,
101) -> IncomingRequestError<E> {
102 match error {
103 IncomingRequestError::BodyConversionError(e) => {
104 IncomingRequestError::BodyConversionError(e)
105 }
106 IncomingRequestError::ConversionError(_) => unreachable!(),
107 }
108}
109
110impl<E: IntoResponse> IntoResponse for IncomingRequestError<E> {
111 fn into_response(self) -> Response {
112 match self {
113 IncomingRequestError::BodyConversionError(e) => e.into_response(),
114 IncomingRequestError::ConversionError(e) => e.into_response(),
115 }
116 }
117}
118
119pub trait TryFromRequest {
121 type Error;
123 fn try_from_request(req: Request) -> Result<Self, Self::Error>
125 where
126 Self: Sized;
127}
128
129impl TryFromRequest for Request {
130 type Error = std::convert::Infallible;
131
132 fn try_from_request(req: Request) -> Result<Self, Self::Error>
133 where
134 Self: Sized,
135 {
136 Ok(req)
137 }
138}
139
140impl<R: TryNonRequestFromRequest> TryFromRequest for R {
141 type Error = R::Error;
142
143 fn try_from_request(req: Request) -> Result<Self, Self::Error>
144 where
145 Self: Sized,
146 {
147 TryNonRequestFromRequest::try_from_request(req)
148 }
149}
150
151pub trait TryNonRequestFromRequest {
158 type Error;
160 fn try_from_request(req: Request) -> Result<Self, Self::Error>
162 where
163 Self: Sized;
164}
165
166impl<B: TryFromBody> TryNonRequestFromRequest for hyperium::Request<B> {
167 type Error = B::Error;
168 fn try_from_request(req: Request) -> Result<Self, Self::Error> {
169 let mut builder = hyperium::Request::builder()
170 .uri(req.uri())
171 .method(req.method);
172 for (n, v) in req.headers {
173 builder = builder.header(n, v.into_bytes());
174 }
175 Ok(builder.body(B::try_from_body(req.body)?).unwrap())
176 }
177}
178
179impl From<super::Method> for hyperium::Method {
180 fn from(method: super::Method) -> Self {
181 match method {
182 super::Method::Get => hyperium::Method::GET,
183 super::Method::Post => hyperium::Method::POST,
184 super::Method::Put => hyperium::Method::PUT,
185 super::Method::Delete => hyperium::Method::DELETE,
186 super::Method::Patch => hyperium::Method::PATCH,
187 super::Method::Head => hyperium::Method::HEAD,
188 super::Method::Options => hyperium::Method::OPTIONS,
189 super::Method::Connect => hyperium::Method::CONNECT,
190 super::Method::Trace => hyperium::Method::TRACE,
191 super::Method::Other(o) => hyperium::Method::from_bytes(o.as_bytes()).expect("TODO"),
192 }
193 }
194}
195impl From<hyperium::Method> for super::Method {
196 fn from(method: hyperium::Method) -> Self {
197 match method {
198 hyperium::Method::GET => super::Method::Get,
199 hyperium::Method::POST => super::Method::Post,
200 hyperium::Method::PUT => super::Method::Put,
201 hyperium::Method::DELETE => super::Method::Delete,
202 hyperium::Method::PATCH => super::Method::Patch,
203 hyperium::Method::HEAD => super::Method::Head,
204 hyperium::Method::OPTIONS => super::Method::Options,
205 hyperium::Method::CONNECT => super::Method::Connect,
206 hyperium::Method::TRACE => super::Method::Trace,
207 m => super::Method::Other(m.as_str().into()),
208 }
209 }
210}
211
212pub trait IntoResponse {
214 fn into_response(self) -> Response;
216}
217
218impl IntoResponse for Response {
219 fn into_response(self) -> Response {
220 self
221 }
222}
223
224impl<B> IntoResponse for hyperium::Response<B>
225where
226 B: IntoBody,
227{
228 fn into_response(self) -> Response {
229 Response::builder()
230 .status(self.status().as_u16())
231 .headers(self.headers())
232 .body(self.into_body())
233 .build()
234 }
235}
236
237impl<R: IntoResponse, E: IntoResponse> IntoResponse for std::result::Result<R, E> {
238 fn into_response(self) -> Response {
239 match self {
240 Ok(r) => r.into_response(),
241 Err(e) => e.into_response(),
242 }
243 }
244}
245
246impl IntoResponse for anyhow::Error {
247 fn into_response(self) -> Response {
248 let body = self.to_string();
249 eprintln!("Handler returned an error: {}", body);
250 let mut source = self.source();
251 while let Some(s) = source {
252 eprintln!(" caused by: {}", s);
253 source = s.source();
254 }
255 Response {
256 status: 500,
257 headers: Default::default(),
258 body: body.as_bytes().to_vec(),
259 }
260 }
261}
262
263impl IntoResponse for Box<dyn std::error::Error> {
264 fn into_response(self) -> Response {
265 let body = self.to_string();
266 eprintln!("Handler returned an error: {}", body);
267 let mut source = self.source();
268 while let Some(s) = source {
269 eprintln!(" caused by: {}", s);
270 source = s.source();
271 }
272 Response {
273 status: 500,
274 headers: Default::default(),
275 body: body.as_bytes().to_vec(),
276 }
277 }
278}
279
280#[cfg(feature = "json")]
281impl IntoResponse for super::JsonBodyError {
282 fn into_response(self) -> Response {
283 responses::bad_request(Some(format!("invalid JSON body: {}", self.0)))
284 }
285}
286
287impl IntoResponse for NonUtf8BodyError {
288 fn into_response(self) -> Response {
289 responses::bad_request(Some(
290 "expected body to be a utf8 string but wasn't".to_owned(),
291 ))
292 }
293}
294
295impl IntoResponse for std::convert::Infallible {
296 fn into_response(self) -> Response {
297 unreachable!()
298 }
299}
300
301pub trait IntoStatusCode {
303 fn into_status_code(self) -> u16;
305}
306
307impl IntoStatusCode for u16 {
308 fn into_status_code(self) -> u16 {
309 self
310 }
311}
312
313impl IntoStatusCode for hyperium::StatusCode {
314 fn into_status_code(self) -> u16 {
315 self.as_u16()
316 }
317}
318
319pub trait IntoHeaders {
321 fn into_headers(self) -> Vec<(String, Vec<u8>)>;
323}
324
325impl IntoHeaders for Vec<(String, String)> {
326 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
327 self.into_iter().map(|(k, v)| (k, v.into_bytes())).collect()
328 }
329}
330
331impl IntoHeaders for Vec<(String, Vec<u8>)> {
332 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
333 self
334 }
335}
336
337impl IntoHeaders for HashMap<String, Vec<String>> {
338 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
339 self.into_iter()
340 .flat_map(|(k, values)| values.into_iter().map(move |v| (k.clone(), v.into_bytes())))
341 .collect()
342 }
343}
344
345impl IntoHeaders for HashMap<String, String> {
346 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
347 self.into_iter().map(|(k, v)| (k, v.into_bytes())).collect()
348 }
349}
350
351impl IntoHeaders for HashMap<String, Vec<u8>> {
352 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
353 self.into_iter().collect()
354 }
355}
356
357impl IntoHeaders for &hyperium::HeaderMap {
358 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
359 self.iter()
360 .map(|(k, v)| (k.as_str().to_owned(), v.as_bytes().to_owned()))
361 .collect()
362 }
363}
364
365impl IntoHeaders for Headers {
366 fn into_headers(self) -> Vec<(String, Vec<u8>)> {
367 self.entries().into_headers()
368 }
369}
370
371pub trait IntoBody {
373 fn into_body(self) -> Vec<u8>;
375}
376
377impl<T: IntoBody> IntoBody for Option<T> {
378 fn into_body(self) -> Vec<u8> {
379 self.map(|b| IntoBody::into_body(b)).unwrap_or_default()
380 }
381}
382
383impl IntoBody for Vec<u8> {
384 fn into_body(self) -> Vec<u8> {
385 self
386 }
387}
388
389impl IntoBody for bytes::Bytes {
390 fn into_body(self) -> Vec<u8> {
391 self.to_vec()
392 }
393}
394
395impl IntoBody for () {
396 fn into_body(self) -> Vec<u8> {
397 Default::default()
398 }
399}
400
401impl IntoBody for &str {
402 fn into_body(self) -> Vec<u8> {
403 self.to_owned().into_bytes()
404 }
405}
406
407impl IntoBody for String {
408 fn into_body(self) -> Vec<u8> {
409 self.to_owned().into_bytes()
410 }
411}
412
413pub trait TryFromBody {
415 type Error: IntoResponse;
417 fn try_from_body(body: Vec<u8>) -> Result<Self, Self::Error>
419 where
420 Self: Sized;
421}
422
423impl<T: TryFromBody> TryFromBody for Option<T> {
424 type Error = T::Error;
425
426 fn try_from_body(body: Vec<u8>) -> Result<Self, Self::Error>
427 where
428 Self: Sized,
429 {
430 Ok(Some(TryFromBody::try_from_body(body)?))
431 }
432}
433
434impl<T: FromBody> TryFromBody for T {
435 type Error = std::convert::Infallible;
436
437 fn try_from_body(body: Vec<u8>) -> Result<Self, Self::Error>
438 where
439 Self: Sized,
440 {
441 Ok(FromBody::from_body(body))
442 }
443}
444
445impl TryFromBody for String {
446 type Error = NonUtf8BodyError;
447
448 fn try_from_body(body: Vec<u8>) -> Result<Self, Self::Error>
449 where
450 Self: Sized,
451 {
452 String::from_utf8(body).map_err(|_| NonUtf8BodyError)
453 }
454}
455
456#[cfg(feature = "json")]
457impl<T: serde::de::DeserializeOwned> TryFromBody for Json<T> {
458 type Error = JsonBodyError;
459 fn try_from_body(body: Vec<u8>) -> Result<Self, Self::Error> {
460 Ok(Json(serde_json::from_slice(&body).map_err(JsonBodyError)?))
461 }
462}
463
464pub trait FromBody {
466 fn from_body(body: Vec<u8>) -> Self;
468}
469
470impl FromBody for Vec<u8> {
471 fn from_body(body: Vec<u8>) -> Self {
472 body
473 }
474}
475
476impl FromBody for () {
477 fn from_body(_body: Vec<u8>) -> Self {}
478}
479
480impl FromBody for bytes::Bytes {
481 fn from_body(body: Vec<u8>) -> Self {
482 Into::into(body)
483 }
484}
485
486pub trait TryIntoBody {
488 type Error;
490 fn try_into_body(self) -> Result<Vec<u8>, Self::Error>;
492}
493
494impl<B> TryIntoBody for B
495where
496 B: IntoBody,
497{
498 type Error = std::convert::Infallible;
499
500 fn try_into_body(self) -> Result<Vec<u8>, Self::Error> {
501 Ok(self.into_body())
502 }
503}
504
505#[cfg(feature = "json")]
506impl<T: serde::Serialize> TryIntoBody for Json<T> {
507 type Error = JsonBodyError;
508
509 fn try_into_body(self) -> Result<Vec<u8>, Self::Error> {
510 serde_json::to_vec(&self.0).map_err(JsonBodyError)
511 }
512}
513
514pub trait TryIntoOutgoingRequest {
516 type Error;
518
519 fn try_into_outgoing_request(self) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error>;
525}
526
527impl TryIntoOutgoingRequest for OutgoingRequest {
528 type Error = std::convert::Infallible;
529
530 fn try_into_outgoing_request(self) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error> {
531 Ok((self, None))
532 }
533}
534
535impl TryIntoOutgoingRequest for Request {
536 type Error = anyhow::Error;
537
538 fn try_into_outgoing_request(self) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error> {
539 let headers = self
540 .headers()
541 .map(|(k, v)| (k.to_owned(), v.as_bytes().to_owned()))
542 .collect::<Vec<_>>();
543 let request = OutgoingRequest::new(Headers::from_list(&headers)?);
544 request
545 .set_method(self.method())
546 .map_err(|()| anyhow::anyhow!("error setting method to {}", self.method()))?;
547 request
548 .set_path_with_query(self.path_and_query())
549 .map_err(|()| anyhow::anyhow!("error setting path to {:?}", self.path_and_query()))?;
550 request
551 .set_scheme(Some(if self.is_https() {
552 &super::Scheme::Https
553 } else {
554 &super::Scheme::Http
555 }))
556 .unwrap();
559 let authority = self
560 .authority()
561 .or_else(|| Some(if self.is_https() { ":443" } else { ":80" }));
563 request
564 .set_authority(authority)
565 .map_err(|()| anyhow::anyhow!("error setting authority to {authority:?}"))?;
566 Ok((request, Some(self.into_body())))
567 }
568}
569
570impl TryIntoOutgoingRequest for RequestBuilder {
571 type Error = anyhow::Error;
572
573 fn try_into_outgoing_request(
574 mut self,
575 ) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error> {
576 self.build().try_into_outgoing_request()
577 }
578}
579
580impl<B> TryIntoOutgoingRequest for hyperium::Request<B>
581where
582 B: TryIntoBody,
583 B::Error: std::error::Error + Send + Sync + 'static,
584{
585 type Error = anyhow::Error;
586 fn try_into_outgoing_request(self) -> Result<(OutgoingRequest, Option<Vec<u8>>), Self::Error> {
587 let headers = self
588 .headers()
589 .into_iter()
590 .map(|(n, v)| (n.as_str().to_owned(), v.as_bytes().to_owned()))
591 .collect::<Vec<_>>();
592 let request = OutgoingRequest::new(Headers::from_list(&headers)?);
593 request
594 .set_method(&self.method().clone().into())
595 .map_err(|()| {
596 anyhow::anyhow!(
597 "error setting method to {}",
598 Method::from(self.method().clone())
599 )
600 })?;
601 request
602 .set_path_with_query(self.uri().path_and_query().map(|p| p.as_str()))
603 .map_err(|()| {
604 anyhow::anyhow!("error setting path to {:?}", self.uri().path_and_query())
605 })?;
606 let scheme = self.uri().scheme().map(|s| match s.as_str() {
607 "http" => super::Scheme::Http,
608 "https" => super::Scheme::Https,
609 s => super::Scheme::Other(s.to_owned()),
610 });
611 request
612 .set_scheme(scheme.as_ref())
613 .map_err(|()| anyhow::anyhow!("error setting scheme to {scheme:?}"))?;
614 request
615 .set_authority(self.uri().authority().map(|a| a.as_str()))
616 .map_err(|()| {
617 anyhow::anyhow!("error setting authority to {:?}", self.uri().authority())
618 })?;
619 let buffer = TryIntoBody::try_into_body(self.into_body())?;
620 Ok((request, Some(buffer)))
621 }
622}
623
624#[async_trait]
626pub trait TryFromIncomingResponse {
627 type Error;
629 async fn try_from_incoming_response(resp: IncomingResponse) -> Result<Self, Self::Error>
631 where
632 Self: Sized;
633}
634
635#[async_trait]
636impl TryFromIncomingResponse for IncomingResponse {
637 type Error = std::convert::Infallible;
638 async fn try_from_incoming_response(resp: IncomingResponse) -> Result<Self, Self::Error> {
639 Ok(resp)
640 }
641}
642
643#[async_trait]
644impl TryFromIncomingResponse for Response {
645 type Error = streams::Error;
646 async fn try_from_incoming_response(resp: IncomingResponse) -> Result<Self, Self::Error> {
647 Ok(Response::builder()
648 .status(resp.status())
649 .headers(resp.headers())
650 .body(resp.into_body().await?)
651 .build())
652 }
653}
654
655#[async_trait]
656impl<B: TryFromBody> TryFromIncomingResponse for hyperium::Response<B> {
657 type Error = B::Error;
658 async fn try_from_incoming_response(resp: IncomingResponse) -> Result<Self, Self::Error> {
659 let mut builder = hyperium::Response::builder().status(resp.status());
660 for (n, v) in resp.headers().entries() {
661 builder = builder.header(n, v);
662 }
663 let body = resp.into_body().await.expect("TODO");
664 Ok(builder.body(B::try_from_body(body)?).unwrap())
665 }
666}
667
668pub trait TryIntoRequest {
670 type Error;
672
673 fn try_into_request(self) -> Result<Request, Self::Error>;
675}
676
677impl TryIntoRequest for Request {
678 type Error = std::convert::Infallible;
679
680 fn try_into_request(self) -> Result<Request, Self::Error> {
681 Ok(self)
682 }
683}
684
685impl<B: TryIntoBody> TryIntoRequest for hyperium::Request<B> {
686 type Error = B::Error;
687 fn try_into_request(self) -> Result<Request, Self::Error> {
688 Ok(Request::builder()
689 .method(self.method().clone().into())
690 .uri(self.uri().to_string())
691 .headers(self.headers())
692 .body(B::try_into_body(self.into_body())?)
693 .build())
694 }
695}