tonic/service/
recover_error.rs1use std::{
28 fmt,
29 future::Future,
30 pin::Pin,
31 task::{Context, Poll, ready},
32};
33
34use http::Response;
35use pin_project::pin_project;
36use tower_layer::Layer;
37use tower_service::Service;
38
39use crate::Status;
40
41#[derive(Debug, Default, Clone)]
43pub struct RecoverErrorLayer {
44 _priv: (),
45}
46
47impl RecoverErrorLayer {
48 pub fn new() -> Self {
50 Self { _priv: () }
51 }
52}
53
54impl<S> Layer<S> for RecoverErrorLayer {
55 type Service = RecoverError<S>;
56
57 fn layer(&self, inner: S) -> Self::Service {
58 RecoverError::new(inner)
59 }
60}
61
62#[derive(Debug, Clone)]
65pub struct RecoverError<S> {
66 inner: S,
67}
68
69impl<S> RecoverError<S> {
70 pub fn new(inner: S) -> Self {
72 Self { inner }
73 }
74}
75
76impl<S, Req, ResBody> Service<Req> for RecoverError<S>
77where
78 S: Service<Req, Response = Response<ResBody>>,
79 S::Error: Into<crate::BoxError>,
80{
81 type Response = Response<ResponseBody<ResBody>>;
82 type Error = crate::BoxError;
83 type Future = ResponseFuture<S::Future>;
84
85 fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
86 self.inner.poll_ready(cx).map_err(Into::into)
87 }
88
89 fn call(&mut self, req: Req) -> Self::Future {
90 ResponseFuture {
91 inner: self.inner.call(req),
92 }
93 }
94}
95
96#[pin_project]
98pub struct ResponseFuture<F> {
99 #[pin]
100 inner: F,
101}
102
103impl<F> fmt::Debug for ResponseFuture<F> {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 f.debug_struct("ResponseFuture").finish()
106 }
107}
108
109impl<F, E, ResBody> Future for ResponseFuture<F>
110where
111 F: Future<Output = Result<Response<ResBody>, E>>,
112 E: Into<crate::BoxError>,
113{
114 type Output = Result<Response<ResponseBody<ResBody>>, crate::BoxError>;
115
116 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
117 match ready!(self.project().inner.poll(cx)) {
118 Ok(response) => {
119 let response = response.map(ResponseBody::full);
120 Poll::Ready(Ok(response))
121 }
122 Err(err) => match Status::try_from_error(err.into()) {
123 Ok(status) => {
124 let (parts, ()) = status.into_http::<()>().into_parts();
125 let res = Response::from_parts(parts, ResponseBody::empty());
126 Poll::Ready(Ok(res))
127 }
128 Err(err) => Poll::Ready(Err(err)),
129 },
130 }
131 }
132}
133
134#[pin_project]
136pub struct ResponseBody<B> {
137 #[pin]
138 inner: Option<B>,
139}
140
141impl<B> fmt::Debug for ResponseBody<B> {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 f.debug_struct("ResponseBody").finish()
144 }
145}
146
147impl<B> ResponseBody<B> {
148 fn full(inner: B) -> Self {
149 Self { inner: Some(inner) }
150 }
151
152 const fn empty() -> Self {
153 Self { inner: None }
154 }
155}
156
157impl<B> http_body::Body for ResponseBody<B>
158where
159 B: http_body::Body,
160{
161 type Data = B::Data;
162 type Error = B::Error;
163
164 fn poll_frame(
165 self: Pin<&mut Self>,
166 cx: &mut Context<'_>,
167 ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
168 match self.project().inner.as_pin_mut() {
169 Some(b) => b.poll_frame(cx),
170 None => Poll::Ready(None),
171 }
172 }
173
174 fn is_end_stream(&self) -> bool {
175 match &self.inner {
176 Some(b) => b.is_end_stream(),
177 None => true,
178 }
179 }
180
181 fn size_hint(&self) -> http_body::SizeHint {
182 match &self.inner {
183 Some(body) => body.size_hint(),
184 None => http_body::SizeHint::with_exact(0),
185 }
186 }
187}