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