Skip to content

Commit 4054d61

Browse files
authored
fix(tonic): Status code to set correct source on unkown error (#799)
1 parent c1fe31c commit 4054d61

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

tests/integration_tests/tests/status.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
use bytes::Bytes;
22
use futures_util::FutureExt;
3+
use http::Uri;
34
use integration_tests::pb::{
45
test_client, test_server, test_stream_client, test_stream_server, Input, InputStream, Output,
56
OutputStream,
67
};
8+
use std::convert::TryFrom;
9+
use std::error::Error;
710
use std::time::Duration;
811
use tokio::sync::oneshot;
912
use tonic::metadata::{MetadataMap, MetadataValue};
13+
use tonic::transport::Endpoint;
1014
use tonic::{transport::Server, Code, Request, Response, Status};
1115

1216
#[tokio::test]
@@ -173,8 +177,78 @@ async fn status_from_server_stream() {
173177
assert_eq!(stream.message().await.unwrap(), None);
174178
}
175179

180+
#[tokio::test]
181+
async fn status_from_server_stream_with_source() {
182+
trace_init();
183+
184+
let channel = Endpoint::try_from("http://[::]:50051")
185+
.unwrap()
186+
.connect_with_connector_lazy(tower::service_fn(move |_: Uri| async move {
187+
Err::<mock::MockStream, _>(std::io::Error::new(std::io::ErrorKind::Other, "WTF"))
188+
}))
189+
.unwrap();
190+
191+
let mut client = test_stream_client::TestStreamClient::new(channel);
192+
193+
let error = client.stream_call(InputStream {}).await.unwrap_err();
194+
195+
let source = error.source().unwrap();
196+
source.downcast_ref::<tonic::transport::Error>().unwrap();
197+
}
198+
176199
fn trace_init() {
177200
let _ = tracing_subscriber::FmtSubscriber::builder()
178201
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
179202
.try_init();
180203
}
204+
205+
mod mock {
206+
use std::{
207+
pin::Pin,
208+
task::{Context, Poll},
209+
};
210+
211+
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
212+
use tonic::transport::server::Connected;
213+
214+
#[derive(Debug)]
215+
pub struct MockStream(pub tokio::io::DuplexStream);
216+
217+
impl Connected for MockStream {
218+
type ConnectInfo = ();
219+
220+
/// Create type holding information about the connection.
221+
fn connect_info(&self) -> Self::ConnectInfo {}
222+
}
223+
224+
impl AsyncRead for MockStream {
225+
fn poll_read(
226+
mut self: Pin<&mut Self>,
227+
cx: &mut Context<'_>,
228+
buf: &mut ReadBuf<'_>,
229+
) -> Poll<std::io::Result<()>> {
230+
Pin::new(&mut self.0).poll_read(cx, buf)
231+
}
232+
}
233+
234+
impl AsyncWrite for MockStream {
235+
fn poll_write(
236+
mut self: Pin<&mut Self>,
237+
cx: &mut Context<'_>,
238+
buf: &[u8],
239+
) -> Poll<std::io::Result<usize>> {
240+
Pin::new(&mut self.0).poll_write(cx, buf)
241+
}
242+
243+
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
244+
Pin::new(&mut self.0).poll_flush(cx)
245+
}
246+
247+
fn poll_shutdown(
248+
mut self: Pin<&mut Self>,
249+
cx: &mut Context<'_>,
250+
) -> Poll<std::io::Result<()>> {
251+
Pin::new(&mut self.0).poll_shutdown(cx)
252+
}
253+
}
254+
}

tonic/src/status.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,11 @@ impl Status {
305305

306306
#[cfg_attr(not(feature = "transport"), allow(dead_code))]
307307
pub(crate) fn from_error(err: Box<dyn Error + Send + Sync + 'static>) -> Status {
308-
Status::try_from_error(err)
309-
.unwrap_or_else(|err| Status::new(Code::Unknown, err.to_string()))
308+
Status::try_from_error(err).unwrap_or_else(|err| {
309+
let mut status = Status::new(Code::Unknown, err.to_string());
310+
status.source = Some(err);
311+
status
312+
})
310313
}
311314

312315
pub(crate) fn try_from_error(

0 commit comments

Comments
 (0)