compression: handle compression flag but no header (#763)
Co-authored-by: Quentin Perez <[email protected]> Co-authored-by: Lucio Franco <[email protected]>
This commit is contained in:
co-authored by
Quentin Perez
Lucio Franco
parent
4054d61e14
commit
88008191fc
@@ -87,3 +87,44 @@ async fn client_enabled_server_disabled() {
|
|||||||
"identity"
|
"identity"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn client_mark_compressed_without_header_server_enabled() {
|
||||||
|
let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10);
|
||||||
|
|
||||||
|
let svc = test_server::TestServer::new(Svc::default()).accept_gzip();
|
||||||
|
|
||||||
|
tokio::spawn({
|
||||||
|
async move {
|
||||||
|
Server::builder()
|
||||||
|
.add_service(svc)
|
||||||
|
.serve_with_incoming(futures::stream::iter(vec![Ok::<_, std::io::Error>(
|
||||||
|
MockStream(server),
|
||||||
|
)]))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut client = test_client::TestClient::with_interceptor(
|
||||||
|
mock_io_channel(client).await,
|
||||||
|
move |mut req: Request<()>| {
|
||||||
|
req.metadata_mut().remove("grpc-encoding");
|
||||||
|
Ok(req)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.send_gzip();
|
||||||
|
|
||||||
|
let status = client
|
||||||
|
.compress_input_unary(SomeData {
|
||||||
|
data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(),
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap_err();
|
||||||
|
|
||||||
|
assert_eq!(status.code(), tonic::Code::Internal);
|
||||||
|
assert_eq!(
|
||||||
|
status.message(),
|
||||||
|
"protocol error: received message with compressed-flag but no grpc-encoding was specified"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -205,9 +205,20 @@ impl<T> Streaming<T> {
|
|||||||
let is_compressed = match self.buf.get_u8() {
|
let is_compressed = match self.buf.get_u8() {
|
||||||
0 => false,
|
0 => false,
|
||||||
1 => {
|
1 => {
|
||||||
if cfg!(feature = "compression") {
|
#[cfg(feature = "compression")]
|
||||||
true
|
{
|
||||||
} else {
|
if self.encoding.is_some() {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
// https://grpc.github.io/grpc/core/md_doc_compression.html
|
||||||
|
// An ill-constructed message with its Compressed-Flag bit set but lacking a grpc-encoding
|
||||||
|
// entry different from identity in its metadata MUST fail with INTERNAL status,
|
||||||
|
// its associated description indicating the invalid Compressed-Flag condition.
|
||||||
|
return Err(Status::new(Code::Internal, "protocol error: received message with compressed-flag but no grpc-encoding was specified"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "compression"))]
|
||||||
|
{
|
||||||
return Err(Status::new(
|
return Err(Status::new(
|
||||||
Code::Unimplemented,
|
Code::Unimplemented,
|
||||||
"Message compressed, compression support not enabled.".to_string(),
|
"Message compressed, compression support not enabled.".to_string(),
|
||||||
@@ -250,6 +261,7 @@ impl<T> Streaming<T> {
|
|||||||
|
|
||||||
if let Err(err) = decompress(
|
if let Err(err) = decompress(
|
||||||
self.encoding.unwrap_or_else(|| {
|
self.encoding.unwrap_or_else(|| {
|
||||||
|
// SAFETY: The check while in State::ReadHeader would already have returned Code::Internal
|
||||||
unreachable!("message was compressed but `Streaming.encoding` was `None`. This is a bug in Tonic. Please file an issue")
|
unreachable!("message was compressed but `Streaming.encoding` was `None`. This is a bug in Tonic. Please file an issue")
|
||||||
}),
|
}),
|
||||||
&mut self.buf,
|
&mut self.buf,
|
||||||
|
|||||||
Reference in New Issue
Block a user