From f089e7a090c558fd22b02db362061988591e8a41 Mon Sep 17 00:00:00 2001 From: tottoto Date: Tue, 14 Nov 2023 00:11:41 +0900 Subject: [PATCH 01/14] chore: Refactor use of tokio-stream (#1560) --- examples/src/mock/mock.rs | 2 +- interop/src/client.rs | 6 +++--- interop/src/server.rs | 2 +- tests/compression/src/bidirectional_stream.rs | 2 +- tests/compression/src/client_stream.rs | 11 +++++------ tests/compression/src/compressing_request.rs | 6 +++--- tests/compression/src/compressing_response.rs | 17 ++++++++--------- tests/compression/src/server_stream.rs | 6 +++--- .../integration_tests/tests/max_message_size.rs | 4 ++-- tests/integration_tests/tests/routes_builder.rs | 2 +- tonic-reflection/tests/server.rs | 2 +- 11 files changed, 29 insertions(+), 31 deletions(-) diff --git a/examples/src/mock/mock.rs b/examples/src/mock/mock.rs index 87f5fc6ba..0d3754921 100644 --- a/examples/src/mock/mock.rs +++ b/examples/src/mock/mock.rs @@ -23,7 +23,7 @@ async fn main() -> Result<(), Box> { tokio::spawn(async move { Server::builder() .add_service(GreeterServer::new(greeter)) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await }); diff --git a/interop/src/client.rs b/interop/src/client.rs index aa5a9a93f..389264684 100644 --- a/interop/src/client.rs +++ b/interop/src/client.rs @@ -207,7 +207,7 @@ pub async fn ping_pong(client: &mut TestClient, assertions: &mut Vec) { - let stream = tokio_stream::iter(Vec::new()); + let stream = tokio_stream::empty(); let result = client.full_duplex_call(Request::new(stream)).await; assertions.push(test_assert!( @@ -270,7 +270,7 @@ pub async fn status_code_and_message(client: &mut TestClient, assertions: &mut V let result = client.unary_call(Request::new(simple_req)).await; validate_response(result, assertions); - let stream = tokio_stream::iter(vec![duplex_req]); + let stream = tokio_stream::once(duplex_req); let result = match client.full_duplex_call(Request::new(stream)).await { Ok(response) => { let stream = response.into_inner(); @@ -356,7 +356,7 @@ pub async fn custom_metadata(client: &mut TestClient, assertions: &mut Vec(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } diff --git a/tests/compression/src/client_stream.rs b/tests/compression/src/client_stream.rs index 99d72751b..9c210c574 100644 --- a/tests/compression/src/client_stream.rs +++ b/tests/compression/src/client_stream.rs @@ -29,7 +29,7 @@ async fn client_enabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -75,7 +75,7 @@ async fn client_disabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -102,7 +102,7 @@ async fn client_enabled_server_disabled() { tokio::spawn(async move { Server::builder() .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); }); @@ -147,7 +147,7 @@ async fn compressing_response_from_client_stream() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -156,8 +156,7 @@ async fn compressing_response_from_client_stream() { let mut client = test_client::TestClient::new(mock_io_channel(client).await) .accept_compressed(CompressionEncoding::Gzip); - let stream = tokio_stream::iter(vec![]); - let req = Request::new(Box::pin(stream)); + let req = Request::new(Box::pin(tokio_stream::empty())); let res = client.compress_output_client_stream(req).await.unwrap(); assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); diff --git a/tests/compression/src/compressing_request.rs b/tests/compression/src/compressing_request.rs index 7cdfd7cec..b1c9009b8 100644 --- a/tests/compression/src/compressing_request.rs +++ b/tests/compression/src/compressing_request.rs @@ -31,7 +31,7 @@ async fn client_enabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -61,7 +61,7 @@ async fn client_enabled_server_disabled() { tokio::spawn(async move { Server::builder() .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); }); @@ -99,7 +99,7 @@ async fn client_mark_compressed_without_header_server_enabled() { async move { Server::builder() .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } diff --git a/tests/compression/src/compressing_response.rs b/tests/compression/src/compressing_response.rs index cc5d4f4cd..a9b73e6d9 100644 --- a/tests/compression/src/compressing_response.rs +++ b/tests/compression/src/compressing_response.rs @@ -53,7 +53,7 @@ async fn client_enabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -94,7 +94,7 @@ async fn client_enabled_server_disabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -160,7 +160,7 @@ async fn client_disabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -198,7 +198,7 @@ async fn server_replying_with_unsupported_encoding() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); }); @@ -240,7 +240,7 @@ async fn disabling_compression_on_single_response() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -281,7 +281,7 @@ async fn disabling_compression_on_response_but_keeping_compression_on_stream() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -337,7 +337,7 @@ async fn disabling_compression_on_response_from_client_stream() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -346,8 +346,7 @@ async fn disabling_compression_on_response_from_client_stream() { let mut client = test_client::TestClient::new(mock_io_channel(client).await) .accept_compressed(CompressionEncoding::Gzip); - let stream = tokio_stream::iter(vec![]); - let req = Request::new(Box::pin(stream)); + let req = Request::new(Box::pin(tokio_stream::empty())); let res = client.compress_output_client_stream(req).await.unwrap(); assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); diff --git a/tests/compression/src/server_stream.rs b/tests/compression/src/server_stream.rs index 453c055c8..3a7fe7104 100644 --- a/tests/compression/src/server_stream.rs +++ b/tests/compression/src/server_stream.rs @@ -26,7 +26,7 @@ async fn client_enabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -80,7 +80,7 @@ async fn client_disabled_server_enabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } @@ -125,7 +125,7 @@ async fn client_enabled_server_disabled() { .into_inner(), ) .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); } diff --git a/tests/integration_tests/tests/max_message_size.rs b/tests/integration_tests/tests/max_message_size.rs index bda1e9d47..9ae524dbc 100644 --- a/tests/integration_tests/tests/max_message_size.rs +++ b/tests/integration_tests/tests/max_message_size.rs @@ -148,7 +148,7 @@ async fn response_stream_limit() { tokio::spawn(async move { Server::builder() .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); }); @@ -317,7 +317,7 @@ async fn max_message_run(case: &TestCase) -> Result<(), Status> { tokio::spawn(async move { Server::builder() .add_service(svc) - .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .serve_with_incoming(tokio_stream::once(Ok::<_, std::io::Error>(server))) .await .unwrap(); }); diff --git a/tests/integration_tests/tests/routes_builder.rs b/tests/integration_tests/tests/routes_builder.rs index f820be0d1..7bcbfad37 100644 --- a/tests/integration_tests/tests/routes_builder.rs +++ b/tests/integration_tests/tests/routes_builder.rs @@ -43,7 +43,7 @@ async fn multiple_service_using_routes_builder() { let output = Output1 { buf: request.into_inner().buf, }; - let stream = tokio_stream::iter(vec![Ok(output)]); + let stream = tokio_stream::once(Ok(output)); Ok(Response::new(Box::pin(stream))) } diff --git a/tonic-reflection/tests/server.rs b/tonic-reflection/tests/server.rs index 00c98fc8d..ab210d5db 100644 --- a/tonic-reflection/tests/server.rs +++ b/tonic-reflection/tests/server.rs @@ -123,7 +123,7 @@ async fn make_test_reflection_request(request: ServerReflectionRequest) -> Messa .unwrap(); let mut client = ServerReflectionClient::new(conn); - let request = Request::new(tokio_stream::iter(vec![request])); + let request = Request::new(tokio_stream::once(request)); let mut inbound = client .server_reflection_info(request) .await From 680214b5e1d48e831ae5ed9483f3e6b826f121f4 Mon Sep 17 00:00:00 2001 From: shuoer86 <129674997+shuoer86@users.noreply.github.com> Date: Mon, 13 Nov 2023 23:11:54 +0800 Subject: [PATCH 02/14] chore: fix typos (#1563) --- examples/src/richer-error/client.rs | 2 +- examples/src/richer-error/client_vec.rs | 2 +- tonic-build/src/prost.rs | 2 +- tonic-web/src/call.rs | 2 +- tonic/src/lib.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/src/richer-error/client.rs b/examples/src/richer-error/client.rs index 1fa9ef7e2..3ccf35428 100644 --- a/examples/src/richer-error/client.rs +++ b/examples/src/richer-error/client.rs @@ -46,7 +46,7 @@ async fn main() -> Result<(), Box> { } }; - println!(" Successfull response received.\n\n {:?}\n", response); + println!(" Successful response received.\n\n {:?}\n", response); Ok(()) } diff --git a/examples/src/richer-error/client_vec.rs b/examples/src/richer-error/client_vec.rs index f74aa9f31..c852c61a4 100644 --- a/examples/src/richer-error/client_vec.rs +++ b/examples/src/richer-error/client_vec.rs @@ -52,7 +52,7 @@ async fn main() -> Result<(), Box> { } }; - println!(" Successfull response received.\n\n {:?}\n", response); + println!(" Successful response received.\n\n {:?}\n", response); Ok(()) } diff --git a/tonic-build/src/prost.rs b/tonic-build/src/prost.rs index 1249055d9..3202e2730 100644 --- a/tonic-build/src/prost.rs +++ b/tonic-build/src/prost.rs @@ -506,7 +506,7 @@ impl Builder { /// should be enabled automatically when run from a build script. However, /// the method of detection is not completely reliable since the `CARGO` /// environment variable can have been set by anything else. If writing the - /// instructions to `stdout` is undesireable, you can disable this setting + /// instructions to `stdout` is undesirable, you can disable this setting /// explicitly. pub fn emit_rerun_if_changed(mut self, enable: bool) -> Self { self.emit_rerun_if_changed = enable; diff --git a/tonic-web/src/call.rs b/tonic-web/src/call.rs index b9fd628a5..dd79971c6 100644 --- a/tonic-web/src/call.rs +++ b/tonic-web/src/call.rs @@ -425,7 +425,7 @@ fn make_trailers_frame(trailers: HeaderMap) -> Vec { /// Search some buffer for grpc-web trailers headers and return /// its location in the original buf. If `None` is returned we did /// not find a trailers in this buffer either because its incomplete -/// or the buffer jsut contained grpc message frames. +/// or the buffer just contained grpc message frames. fn find_trailers(buf: &[u8]) -> Result { let mut len = 0; let mut temp_buf = &buf[..]; diff --git a/tonic/src/lib.rs b/tonic/src/lib.rs index 437402a62..8aa80a121 100644 --- a/tonic/src/lib.rs +++ b/tonic/src/lib.rs @@ -58,7 +58,7 @@ //! ## Max Message Size //! //! Currently, both servers and clients can be configured to set the max message encoding and -//! decoding size. This will ensure that an incoming gRPC message will not exahust the systems +//! decoding size. This will ensure that an incoming gRPC message will not exhaust the systems //! memory. By default, the decoding message limit is `4MB` and the encoding limit is `usize::MAX`. //! //! [gRPC]: https://grpc.io From e1fa95e1bba2ea2c762bf51313cef1458ad02ad9 Mon Sep 17 00:00:00 2001 From: tottoto Date: Tue, 14 Nov 2023 00:13:11 +0900 Subject: [PATCH 03/14] chore: Bump msrv to 1.65 (#1549) --- .github/workflows/CI.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index a3ab20a3f..f0ce998fe 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -88,7 +88,7 @@ jobs: - uses: actions/checkout@v3 - uses: hecrj/setup-rust-action@v1 with: - rust-version: "1.64" # msrv + rust-version: "1.65" # msrv - name: Install protoc uses: taiki-e/install-action@v2 with: diff --git a/README.md b/README.md index 0f1c1ba18..d32a1a3ee 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ For IntelliJ IDEA users, please refer to [this](https://github.com/intellij-rust ### Rust Version -`tonic`'s MSRV is `1.64`. +`tonic`'s MSRV is `1.65`. ```bash $ rustup update From ff71e89349190a15172f5c3902dde2be4fcc0648 Mon Sep 17 00:00:00 2001 From: Xiaoya Wei Date: Mon, 13 Nov 2023 23:14:27 +0800 Subject: [PATCH 04/14] support vectored IO (#1502) Co-authored-by: Lucio Franco --- tests/integration_tests/src/lib.rs | 13 ++++++++++++ tonic/src/transport/service/io.rs | 33 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/tests/integration_tests/src/lib.rs b/tests/integration_tests/src/lib.rs index 68bf837b6..2d3c3f3f8 100644 --- a/tests/integration_tests/src/lib.rs +++ b/tests/integration_tests/src/lib.rs @@ -5,6 +5,7 @@ pub mod pb { pub mod mock { use std::{ + io::IoSlice, pin::Pin, task::{Context, Poll}, }; @@ -51,6 +52,18 @@ pub mod mock { ) -> Poll> { Pin::new(&mut self.0).poll_shutdown(cx) } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + Pin::new(&mut self.0).poll_write_vectored(cx, bufs) + } + + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } } } diff --git a/tonic/src/transport/service/io.rs b/tonic/src/transport/service/io.rs index 2b465355f..2230b9b2e 100644 --- a/tonic/src/transport/service/io.rs +++ b/tonic/src/transport/service/io.rs @@ -1,6 +1,7 @@ use crate::transport::server::Connected; use hyper::client::connect::{Connected as HyperConnected, Connection}; use std::io; +use std::io::IoSlice; use std::pin::Pin; use std::task::{Context, Poll}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; @@ -65,6 +66,18 @@ impl AsyncWrite for BoxedIo { fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { Pin::new(&mut self.0).poll_shutdown(cx) } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + Pin::new(&mut self.0).poll_write_vectored(cx, bufs) + } + + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } } pub(crate) enum ServerIo { @@ -163,4 +176,24 @@ where Self::TlsIo(io) => Pin::new(io).poll_shutdown(cx), } } + + fn poll_write_vectored( + mut self: Pin<&mut Self>, + cx: &mut Context<'_>, + bufs: &[IoSlice<'_>], + ) -> Poll> { + match &mut *self { + Self::Io(io) => Pin::new(io).poll_write_vectored(cx, bufs), + #[cfg(feature = "tls")] + Self::TlsIo(io) => Pin::new(io).poll_write_vectored(cx, bufs), + } + } + + fn is_write_vectored(&self) -> bool { + match self { + Self::Io(io) => io.is_write_vectored(), + #[cfg(feature = "tls")] + Self::TlsIo(io) => io.is_write_vectored(), + } + } } From 522a8d74f8a948d48cb6b5ae0f591d02388e930d Mon Sep 17 00:00:00 2001 From: tottoto Date: Tue, 14 Nov 2023 00:14:49 +0900 Subject: [PATCH 05/14] chore: Fix clippy warning (#1500) Co-authored-by: Lucio Franco --- codegen/src/main.rs | 12 ++++++------ examples/src/dynamic/server.rs | 10 ++-------- tonic-build/src/server.rs | 2 ++ tonic-web/src/call.rs | 8 ++++---- tonic-web/tests/integration/tests/grpc.rs | 2 +- tonic-web/tests/integration/tests/grpc_web.rs | 4 ++-- tonic/src/codec/encode.rs | 4 ++-- tonic/src/codec/prost.rs | 1 - tonic/src/metadata/value.rs | 2 +- tonic/src/status.rs | 2 +- 10 files changed, 21 insertions(+), 26 deletions(-) diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 4b88039a1..7659ad93d 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; fn main() { // tonic-health @@ -45,11 +45,11 @@ fn main() { } fn codegen( - root_dir: &PathBuf, + root_dir: &Path, iface_files: &[&str], include_dirs: &[&str], - out_dir: &PathBuf, - file_descriptor_set_path: &PathBuf, + out_dir: &Path, + file_descriptor_set_path: &Path, build_client: bool, build_server: bool, ) { @@ -59,12 +59,12 @@ fn codegen( .unwrap(); let iface_files: Vec = iface_files - .into_iter() + .iter() .map(|&path| root_dir.join(path)) .collect(); let include_dirs: Vec = include_dirs - .into_iter() + .iter() .map(|&path| root_dir.join(path)) .collect(); let out_dir = root_dir.join(out_dir); diff --git a/examples/src/dynamic/server.rs b/examples/src/dynamic/server.rs index e25c7e8ae..300ec868c 100644 --- a/examples/src/dynamic/server.rs +++ b/examples/src/dynamic/server.rs @@ -32,10 +32,7 @@ impl Echo for MyEcho { } fn init_echo(args: &[String], builder: &mut RoutesBuilder) { - let enabled = args - .into_iter() - .find(|arg| arg.as_str() == "echo") - .is_some(); + let enabled = args.iter().any(|arg| arg.as_str() == "echo"); if enabled { println!("Adding Echo service..."); let svc = EchoServer::new(MyEcho::default()); @@ -62,10 +59,7 @@ impl Greeter for MyGreeter { } fn init_greeter(args: &[String], builder: &mut RoutesBuilder) { - let enabled = args - .into_iter() - .find(|arg| arg.as_str() == "greeter") - .is_some(); + let enabled = args.iter().any(|arg| arg.as_str() == "greeter"); if enabled { println!("Adding Greeter service..."); diff --git a/tonic-build/src/server.rs b/tonic-build/src/server.rs index 9e42789ef..d9ab1ad6b 100644 --- a/tonic-build/src/server.rs +++ b/tonic-build/src/server.rs @@ -9,6 +9,7 @@ use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{Ident, Lit, LitStr}; +#[allow(clippy::too_many_arguments)] pub(crate) fn generate_internal( service: &T, emit_package: bool, @@ -209,6 +210,7 @@ pub(crate) fn generate_internal( } } +#[allow(clippy::too_many_arguments)] fn generate_trait( service: &T, emit_package: bool, diff --git a/tonic-web/src/call.rs b/tonic-web/src/call.rs index dd79971c6..731b9f667 100644 --- a/tonic-web/src/call.rs +++ b/tonic-web/src/call.rs @@ -428,7 +428,7 @@ fn make_trailers_frame(trailers: HeaderMap) -> Vec { /// or the buffer just contained grpc message frames. fn find_trailers(buf: &[u8]) -> Result { let mut len = 0; - let mut temp_buf = &buf[..]; + let mut temp_buf = buf; loop { // To check each frame, there must be at least GRPC_HEADER_SIZE @@ -457,7 +457,7 @@ fn find_trailers(buf: &[u8]) -> Result { return Ok(FindTrailers::IncompleteBuf); } - temp_buf = &buf[len as usize..]; + temp_buf = &buf[len..]; } } @@ -514,7 +514,7 @@ mod tests { fn find_trailers_non_buffered() { // Byte version of this: // b"\x80\0\0\0\x0fgrpc-status:0\r\n" - let buf = vec![ + let buf = [ 128, 0, 0, 0, 15, 103, 114, 112, 99, 45, 115, 116, 97, 116, 117, 115, 58, 48, 13, 10, ]; @@ -527,7 +527,7 @@ mod tests { fn find_trailers_buffered() { // Byte version of this: // b"\0\0\0\0L\n$975738af-1a17-4aea-b887-ed0bbced6093\x1a$da609e9b-f470-4cc0-a691-3fd6a005a436\x80\0\0\0\x0fgrpc-status:0\r\n" - let buf = vec![ + let buf = [ 0, 0, 0, 0, 76, 10, 36, 57, 55, 53, 55, 51, 56, 97, 102, 45, 49, 97, 49, 55, 45, 52, 97, 101, 97, 45, 98, 56, 56, 55, 45, 101, 100, 48, 98, 98, 99, 101, 100, 54, 48, 57, 51, 26, 36, 100, 97, 54, 48, 57, 101, 57, 98, 45, 102, 52, 55, 48, 45, 52, 99, 99, 48, diff --git a/tonic-web/tests/integration/tests/grpc.rs b/tonic-web/tests/integration/tests/grpc.rs index 8e81ef68c..98eca1f92 100644 --- a/tonic-web/tests/integration/tests/grpc.rs +++ b/tonic-web/tests/integration/tests/grpc.rs @@ -129,7 +129,7 @@ async fn spawn() -> Result<(Client, Client, Client, Client), Error> { let ((s1, u1), (s2, u2), (s3, u3), (s4, u4)) = join!(grpc(true), grpc(false), grpc_web(true), grpc_web(false)); - let _ = tokio::spawn(async move { join!(s1, s2, s3, s4) }); + drop(tokio::spawn(async move { join!(s1, s2, s3, s4) })); tokio::time::sleep(Duration::from_millis(30)).await; diff --git a/tonic-web/tests/integration/tests/grpc_web.rs b/tonic-web/tests/integration/tests/grpc_web.rs index e062a8380..3343d754c 100644 --- a/tonic-web/tests/integration/tests/grpc_web.rs +++ b/tonic-web/tests/integration/tests/grpc_web.rs @@ -65,7 +65,7 @@ async fn spawn() -> String { let url = format!("http://{}", listener.local_addr().unwrap()); let listener_stream = TcpListenerStream::new(listener); - let _ = tokio::spawn(async move { + drop(tokio::spawn(async move { Server::builder() .accept_http1(true) .layer(GrpcWebLayer::new()) @@ -73,7 +73,7 @@ async fn spawn() -> String { .serve_with_incoming(listener_stream) .await .unwrap() - }); + })); url } diff --git a/tonic/src/codec/encode.rs b/tonic/src/codec/encode.rs index bd48ee47b..593634f93 100644 --- a/tonic/src/codec/encode.rs +++ b/tonic/src/codec/encode.rs @@ -106,14 +106,14 @@ where BytesMut::new() }; - return EncodedBytes { + Self { source: Fuse::new(source), encoder, compression_encoding, max_message_size, buf, uncompression_buf, - }; + } } } diff --git a/tonic/src/codec/prost.rs b/tonic/src/codec/prost.rs index 47e736a71..d2f1652f4 100644 --- a/tonic/src/codec/prost.rs +++ b/tonic/src/codec/prost.rs @@ -326,7 +326,6 @@ mod tests { } } - #[allow(clippy::drop_ref)] fn poll_trailers( self: Pin<&mut Self>, _cx: &mut Context<'_>, diff --git a/tonic/src/metadata/value.rs b/tonic/src/metadata/value.rs index b7600dd4f..9253a9254 100644 --- a/tonic/src/metadata/value.rs +++ b/tonic/src/metadata/value.rs @@ -646,7 +646,7 @@ impl Eq for MetadataValue {} impl PartialOrd for MetadataValue { #[inline] fn partial_cmp(&self, other: &MetadataValue) -> Option { - self.inner.partial_cmp(&other.inner) + Some(self.cmp(other)) } } diff --git a/tonic/src/status.rs b/tonic/src/status.rs index 0b3892c45..da8b792e5 100644 --- a/tonic/src/status.rs +++ b/tonic/src/status.rs @@ -461,7 +461,7 @@ impl Status { .expect("Invalid status header, expected base64 encoded value") }) .map(Bytes::from) - .unwrap_or_else(Bytes::new); + .unwrap_or_default(); let mut other_headers = header_map.clone(); other_headers.remove(GRPC_STATUS_HEADER_CODE); From dcaf23c6e6e64347bf356062b7478484889477e0 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:07:40 +0900 Subject: [PATCH 06/14] chore: Update to hecrj/setup-rust-action@v2 (#1536) --- .github/workflows/CI.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f0ce998fe..6b5bdb7db 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 with: components: rustfmt - run: cargo fmt --all --check @@ -32,7 +32,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 - name: Install protoc uses: taiki-e/install-action@v2 with: @@ -69,7 +69,7 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 - uses: taiki-e/install-action@cargo-hack - name: Install protoc uses: taiki-e/install-action@v2 @@ -86,7 +86,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 with: rust-version: "1.65" # msrv - name: Install protoc @@ -106,7 +106,7 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 - name: Install protoc uses: taiki-e/install-action@v2 with: @@ -124,7 +124,7 @@ jobs: os: [ubuntu-latest, macOS-latest, windows-latest] steps: - uses: actions/checkout@v3 - - uses: hecrj/setup-rust-action@v1 + - uses: hecrj/setup-rust-action@v2 - name: Install protoc uses: taiki-e/install-action@v2 with: From 7562600085deff364d58e155c1428f9713d42600 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:07:49 +0900 Subject: [PATCH 07/14] chore(web): Disable unused feature (#1535) --- tonic-web/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/tonic-web/Cargo.toml b/tonic-web/Cargo.toml index 3a3d40feb..16d8909b1 100644 --- a/tonic-web/Cargo.toml +++ b/tonic-web/Cargo.toml @@ -30,4 +30,3 @@ tracing = "0.1" [dev-dependencies] tokio = {version = "1", features = ["macros", "rt"]} -tonic = {path = "../tonic", default-features = false, features = ["transport", "tls"]} From 9123f68a8905ab97f02417caf039a1799c9de437 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:08:16 +0900 Subject: [PATCH 08/14] chore: Remove redundant helper constructor (#1534) * chore: Remove redundant helper constructor * chore: Refactor endpoint to construct connector --- tonic/src/transport/channel/endpoint.rs | 35 ++++++++++-------------- tonic/src/transport/service/connector.rs | 12 +------- tonic/src/transport/service/discover.rs | 7 +---- tonic/src/transport/service/mod.rs | 2 +- 4 files changed, 17 insertions(+), 39 deletions(-) diff --git a/tonic/src/transport/channel/endpoint.rs b/tonic/src/transport/channel/endpoint.rs index c599931e6..6aacb57a5 100644 --- a/tonic/src/transport/channel/endpoint.rs +++ b/tonic/src/transport/channel/endpoint.rs @@ -301,6 +301,16 @@ impl Endpoint { self } + pub(crate) fn connector(&self, c: C) -> service::Connector { + #[cfg(feature = "tls")] + let connector = service::Connector::new(c, self.tls.clone()); + + #[cfg(not(feature = "tls"))] + let connector = service::Connector::new(c); + + connector + } + /// Create a channel from this config. pub async fn connect(&self) -> Result { let mut http = hyper::client::connect::HttpConnector::new(); @@ -308,11 +318,7 @@ impl Endpoint { http.set_nodelay(self.tcp_nodelay); http.set_keepalive(self.tcp_keepalive); - #[cfg(feature = "tls")] - let connector = service::connector(http, self.tls.clone()); - - #[cfg(not(feature = "tls"))] - let connector = service::connector(http); + let connector = self.connector(http); if let Some(connect_timeout) = self.connect_timeout { let mut connector = hyper_timeout::TimeoutConnector::new(connector); @@ -333,11 +339,7 @@ impl Endpoint { http.set_nodelay(self.tcp_nodelay); http.set_keepalive(self.tcp_keepalive); - #[cfg(feature = "tls")] - let connector = service::connector(http, self.tls.clone()); - - #[cfg(not(feature = "tls"))] - let connector = service::connector(http); + let connector = self.connector(http); if let Some(connect_timeout) = self.connect_timeout { let mut connector = hyper_timeout::TimeoutConnector::new(connector); @@ -362,11 +364,7 @@ impl Endpoint { C::Future: Send + 'static, crate::Error: From + Send + 'static, { - #[cfg(feature = "tls")] - let connector = service::connector(connector, self.tls.clone()); - - #[cfg(not(feature = "tls"))] - let connector = service::connector(connector); + let connector = self.connector(connector); if let Some(connect_timeout) = self.connect_timeout { let mut connector = hyper_timeout::TimeoutConnector::new(connector); @@ -391,12 +389,7 @@ impl Endpoint { C::Future: Send + 'static, crate::Error: From + Send + 'static, { - #[cfg(feature = "tls")] - let connector = service::connector(connector, self.tls.clone()); - - #[cfg(not(feature = "tls"))] - let connector = service::connector(connector); - + let connector = self.connector(connector); Channel::new(connector, self.clone()) } diff --git a/tonic/src/transport/service/connector.rs b/tonic/src/transport/service/connector.rs index b672f3bf3..a5e0d9eb9 100644 --- a/tonic/src/transport/service/connector.rs +++ b/tonic/src/transport/service/connector.rs @@ -8,16 +8,6 @@ use std::task::{Context, Poll}; use tower::make::MakeConnection; use tower_service::Service; -#[cfg(not(feature = "tls"))] -pub(crate) fn connector(inner: C) -> Connector { - Connector::new(inner) -} - -#[cfg(feature = "tls")] -pub(crate) fn connector(inner: C, tls: Option) -> Connector { - Connector::new(inner, tls) -} - pub(crate) struct Connector { inner: C, #[cfg(feature = "tls")] @@ -34,7 +24,7 @@ impl Connector { } #[cfg(feature = "tls")] - fn new(inner: C, tls: Option) -> Self { + pub(crate) fn new(inner: C, tls: Option) -> Self { Self { inner, tls } } diff --git a/tonic/src/transport/service/discover.rs b/tonic/src/transport/service/discover.rs index 6ca4ab2c2..2d23ca74c 100644 --- a/tonic/src/transport/service/discover.rs +++ b/tonic/src/transport/service/discover.rs @@ -1,4 +1,3 @@ -use super::super::service; use super::connection::Connection; use crate::transport::Endpoint; @@ -38,12 +37,8 @@ impl Stream for DynamicServiceStream { http.set_keepalive(endpoint.tcp_keepalive); http.set_connect_timeout(endpoint.connect_timeout); http.enforce_http(false); - #[cfg(feature = "tls")] - let connector = service::connector(http, endpoint.tls.clone()); - #[cfg(not(feature = "tls"))] - let connector = service::connector(http); - let connection = Connection::lazy(connector, endpoint); + let connection = Connection::lazy(endpoint.connector(http), endpoint); let change = Ok(Change::Insert(k, connection)); Poll::Ready(Some(change)) } diff --git a/tonic/src/transport/service/mod.rs b/tonic/src/transport/service/mod.rs index 52addb322..69d850f10 100644 --- a/tonic/src/transport/service/mod.rs +++ b/tonic/src/transport/service/mod.rs @@ -13,7 +13,7 @@ mod user_agent; pub(crate) use self::add_origin::AddOrigin; pub(crate) use self::connection::Connection; -pub(crate) use self::connector::connector; +pub(crate) use self::connector::Connector; pub(crate) use self::discover::DynamicServiceStream; pub(crate) use self::executor::SharedExec; pub(crate) use self::grpc_timeout::GrpcTimeout; From 9d712c56e1c89de45f02491962f93ca883ae6a9e Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:08:36 +0900 Subject: [PATCH 09/14] chore(codec): Replace tonic::codec::encode::fuse with tokio-stream (#1533) --- tonic/src/codec/encode.rs | 65 +++------------------------------------ 1 file changed, 5 insertions(+), 60 deletions(-) diff --git a/tonic/src/codec/encode.rs b/tonic/src/codec/encode.rs index 593634f93..13eb2c96d 100644 --- a/tonic/src/codec/encode.rs +++ b/tonic/src/codec/encode.rs @@ -11,8 +11,6 @@ use std::{ }; use tokio_stream::{Stream, StreamExt}; -use fuse::Fuse; - pub(super) const BUFFER_SIZE: usize = 8 * 1024; const YIELD_THRESHOLD: usize = 32 * 1024; @@ -29,7 +27,7 @@ where { let stream = EncodedBytes::new( encoder, - source, + source.fuse(), compression_encoding, compression_override, max_message_size, @@ -50,7 +48,7 @@ where { let stream = EncodedBytes::new( encoder, - source.map(Ok), + source.fuse().map(Ok), compression_encoding, SingleMessageCompressionOverride::default(), max_message_size, @@ -71,7 +69,7 @@ where U: Stream>, { #[pin] - source: Fuse, + source: U, encoder: T, compression_encoding: Option, max_message_size: Option, @@ -84,6 +82,7 @@ where T: Encoder, U: Stream>, { + // `source` should be fused stream. fn new( encoder: T, source: U, @@ -107,7 +106,7 @@ where }; Self { - source: Fuse::new(source), + source, encoder, compression_encoding, max_message_size, @@ -345,57 +344,3 @@ where Poll::Ready(self.project().state.trailers()) } } - -mod fuse { - use std::{ - pin::Pin, - task::{ready, Context, Poll}, - }; - - use tokio_stream::Stream; - - /// Stream for the [`fuse`](super::StreamExt::fuse) method. - #[derive(Debug)] - #[pin_project::pin_project] - #[must_use = "streams do nothing unless polled"] - pub(crate) struct Fuse { - #[pin] - stream: St, - done: bool, - } - - impl Fuse { - pub(crate) fn new(stream: St) -> Self { - Self { - stream, - done: false, - } - } - } - - impl Stream for Fuse { - type Item = S::Item; - - fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - let this = self.project(); - - if *this.done { - return Poll::Ready(None); - } - - let item = ready!(this.stream.poll_next(cx)); - if item.is_none() { - *this.done = true; - } - Poll::Ready(item) - } - - fn size_hint(&self) -> (usize, Option) { - if self.done { - (0, Some(0)) - } else { - self.stream.size_hint() - } - } - } -} From aa67ae5e879ea8d20477d3fd2066b4071c5657a5 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:09:15 +0900 Subject: [PATCH 10/14] chore: Remove duplicated changelog (#1531) --- CHANGELOG.md | 638 --------------------------------------------------- 1 file changed, 638 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a06244a7b..07674643f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -617,641 +617,3 @@ an async `Endpoint::connect`. * **codgen:** Add default implementations for the generated serve… ([#27](https://github.com/hyperium/tonic/issues/27)) ([4559613](https://github.com/hyperium/tonic/commit/4559613c37f75dde67981ee38a7f5af5947ef0be)) * **transport:** Expose http/2 settings ([#28](https://github.com/hyperium/tonic/issues/28)) ([0218d58](https://github.com/hyperium/tonic/commit/0218d58c282d6de6f300229677c99369d3ea20ed)) - - - -# [v0.10.0](https://github.com/hyperium/tonic/compare/v0.9.2...v0.10) (2023-09-01) - -### Breaking Changes - -- Update to `prost` 0.12 -- MSRV bumped to 1.64 - - -### Bug Fixes - -* **codegen:** Use stream type from codegen mod ([#1446](https://github.com/hyperium/tonic/issues/1446)) ([60d776b](https://github.com/hyperium/tonic/commit/60d776b019854b6a6881d69823a36dcc18b1b4ce)) -* **examples:** Use https scheme when using tls ([#1466](https://github.com/hyperium/tonic/issues/1466)) ([388b177](https://github.com/hyperium/tonic/commit/388b177d99e7b0a2c8d5eab1dee65c4dbb671db4)) -* **tls:** Don't use tls w/ `http` scheme ([#1454](https://github.com/hyperium/tonic/issues/1454)) ([95e81f5](https://github.com/hyperium/tonic/commit/95e81f51fbbc32a5cf2b94ac0d7005d56b44a8d3)) - - -### Features - -* **build:** Add optional default unimplemented stubs ([#1344](https://github.com/hyperium/tonic/issues/1344)) ([aff1daf](https://github.com/hyperium/tonic/commit/aff1daf65d9a0d55b92719318eba2b5a4769c4e1)) -* **core:** amortize many ready messages into fewer, larger buffers ([#1423](https://github.com/hyperium/tonic/issues/1423)) ([76eedc1](https://github.com/hyperium/tonic/commit/76eedc13d0dd891892301afa38c3dd8ae6646edf)) -* **types:** add ability to extract rich error details from `google.rpc.Status` ([#1430](https://github.com/hyperium/tonic/issues/1430)) ([5fd635a](https://github.com/hyperium/tonic/commit/5fd635a30568ff629c4197c603c45b6b94750e88)) -* **transport:** Add `Router::into_router` ([#1442](https://github.com/hyperium/tonic/issues/1442)) ([ea06a1b](https://github.com/hyperium/tonic/commit/ea06a1bb30bc325c7f6d7763fe48bf8b88c1c3ed)) -* **transport:** Expose TcpConnectInfo fields ([#1449](https://github.com/hyperium/tonic/issues/1449)) ([74b079c](https://github.com/hyperium/tonic/commit/74b079ce752311fbe760d748804d801c385a5e7a)) -* **web:** Add `GrpcWebClientService` ([#1472](https://github.com/hyperium/tonic/issues/1472)) ([dc29c17](https://github.com/hyperium/tonic/commit/dc29c17ae3ef729024e1f80c66566b09d7a01051)) -* **transport:** Support for adding services dynamically - - -# [v0.9.2](https://github.com/hyperium/tonic/compare/v0.9.1...v0.9.2) (2023-04-17) - -### Features - -- **build:**: Support boxing fields ([#1252](https://github.com/hyperium/tonic/pull/1252)) - - -# [v0.9.1](https://github.com/hyperium/tonic/compare/v0.9.0...v0.9.1) (2023-04-03) - -### Features - -- **transport:** Update `rustls` to `0.21` ([#1340](https://github.com/hyperium/tonic/pull/1340)) - -# [v0.9.0](https://github.com/hyperium/tonic/compare/v0.8.4...v0.9.0) (2023-03-31) - -All tonic-* crates owned by this repository will now be versioned together to -make it easier to understand which crate matches the core tonic crate version. - -### Breaking Changes - -- All crates bumped to 2021 edition -- `tonic-health` and `tonic-reflection` internal protobuf module renamed. -- Default decoding message limit set to `4MiB` by default. - - -### Bug Fixes - -* **build:** Allow Services to be named Result ([#1203](https://github.com/hyperium/tonic/issues/1203)) ([a562a3c](https://github.com/hyperium/tonic/commit/a562a3ce329a38696dfcb0d82b7102d93fb30a5c)), closes [#1156](https://github.com/hyperium/tonic/issues/1156) -* **codec:** Cancelled client streaming handling ([#1315](https://github.com/hyperium/tonic/issues/1315)) ([c8027a1](https://github.com/hyperium/tonic/commit/c8027a1385dd5d3fb6abdce7be49c46a43d4f3c2)), closes [#848](https://github.com/hyperium/tonic/issues/848) -* MetadataKey::from_bytes returns an error ([#1246](https://github.com/hyperium/tonic/issues/1246)) ([930c805](https://github.com/hyperium/tonic/commit/930c805127cada70e4e4ab03c7680214b5c2a4f5)) -* **web:** Fix `enable` and update docs ([#1326](https://github.com/hyperium/tonic/issues/1326)) ([a9db219](https://github.com/hyperium/tonic/commit/a9db219e50b7d27e48cd44e76941113a36b72e26)) - - -### Features - -* add GrpcMethod extension into request for client ([#1275](https://github.com/hyperium/tonic/issues/1275)) ([7a6b20d](https://github.com/hyperium/tonic/commit/7a6b20d8ef5d31c9cc01f0cf697df1f3e28cb421)) -* **build:** Builder: add {enum,message}_attributes ([#1234](https://github.com/hyperium/tonic/issues/1234)) ([ff642f9](https://github.com/hyperium/tonic/commit/ff642f9233beab322333745f9edfa9c62ae18ca4)) -* **codec:** Configure max request message size ([#1274](https://github.com/hyperium/tonic/issues/1274)) ([9f716d8](https://github.com/hyperium/tonic/commit/9f716d841184b8521720c6ed941af137ca2ee6a0)), closes [#1097](https://github.com/hyperium/tonic/issues/1097) -* **core:** Default encoding/decoding limits ([#1335](https://github.com/hyperium/tonic/issues/1335)) ([ff33119](https://github.com/hyperium/tonic/commit/ff331199e45c8b53e93f1bd51ccd74dafc2146ac)) -* **reflection:** Add dummy implementation for extension ([#1209](https://github.com/hyperium/tonic/issues/1209)) ([fdff111](https://github.com/hyperium/tonic/commit/fdff11115b44c4cc7e3de59ea045a193fa6881bc)) -* Rename api related to protobuf ([#1224](https://github.com/hyperium/tonic/issues/1224)) ([d2542dc](https://github.com/hyperium/tonic/commit/d2542dc034e89383bd182a25a0d3235859fb10f9)) -* **tls:** add an option for optional TLS client authentication ([#1163](https://github.com/hyperium/tonic/issues/1163)) ([773e4e1](https://github.com/hyperium/tonic/commit/773e4e1749daf023222f2294816b1f09d9e916a0)), closes [#687](https://github.com/hyperium/tonic/issues/687) -* **tonic:** Use NamedService without transport feature ([#1273](https://github.com/hyperium/tonic/issues/1273)) ([5acde56](https://github.com/hyperium/tonic/commit/5acde56176d928ffddbf1076e922764fb151f959)) -* **transport:** Add `local_addr` to `Request o` ([#1327](https://github.com/hyperium/tonic/issues/1327)) ([b54ce23](https://github.com/hyperium/tonic/commit/b54ce2321a5cba1c32261f4eda2b27d1110b893d)) -* **transport:** added support for EC keys ([#1145](https://github.com/hyperium/tonic/issues/1145)) ([17d6a4b](https://github.com/hyperium/tonic/commit/17d6a4b576c1571bb149d3e935e9a835265a80dd)), closes [#1143](https://github.com/hyperium/tonic/issues/1143) -* **types:** Add gRPC Richer Error Model support (Docs) ([#1317](https://github.com/hyperium/tonic/issues/1317)) ([69ce71e](https://github.com/hyperium/tonic/commit/69ce71efa6f4601c9e8060e87d0641a51251e9ab)) -* **types:** Add gRPC Richer Error Model support (Examples) ([#1300](https://github.com/hyperium/tonic/issues/1300)) ([d471212](https://github.com/hyperium/tonic/commit/d471212ee8264ca6c5169a9893f361187e9378c9)) -* **types:** Add gRPC Richer Error Model support (Help) ([#1293](https://github.com/hyperium/tonic/issues/1293)) ([d6041a9](https://github.com/hyperium/tonic/commit/d6041a99c2a216a2ebc83b7bc5a0947ba7ca869c)) -* **types:** Add gRPC Richer Error Model support (LocalizedMessage) ([#1295](https://github.com/hyperium/tonic/issues/1295)) ([d54d02d](https://github.com/hyperium/tonic/commit/d54d02d3ed8bf221c0c54494b7ce692d412391a4)) -* **types:** Add gRPC Richer Error Model support (PreconditionFailure) ([#1276](https://github.com/hyperium/tonic/issues/1276)) ([2378581](https://github.com/hyperium/tonic/commit/2378581850483f26fd7c1dee0a797d936b73e881)) -* **types:** Add gRPC Richer Error Model support (QuotaFailure) ([#1204](https://github.com/hyperium/tonic/issues/1204)) ([03b4735](https://github.com/hyperium/tonic/commit/03b4735bb4ba7c6e84842d0515d1fd3be9d1cc13)) -* **types:** Add gRPC Richer Error Model support (ResourceInfo) ([#1282](https://github.com/hyperium/tonic/issues/1282)) ([7eeda24](https://github.com/hyperium/tonic/commit/7eeda24350c5a61cae7c8e56cc0439d9c40cc77d)) -* **types:** Add gRPC Richer Error Model support (RetryInfo) ([#1095](https://github.com/hyperium/tonic/issues/1095)) ([6cdb3d4](https://github.com/hyperium/tonic/commit/6cdb3d4685966b71f051e4cd67c50e1d2db402f5)) -* **types:** add support for `DebugInfo` error message type ([#1179](https://github.com/hyperium/tonic/issues/1179)) ([3076e82](https://github.com/hyperium/tonic/commit/3076e8251e602ed6e98a8b3029070b33e3459109)) -* **types:** Expose FILE_DESCRIPTOR_SET ([#1210](https://github.com/hyperium/tonic/issues/1210)) ([cc42d1f](https://github.com/hyperium/tonic/commit/cc42d1f88c39d87b244f863daf4ff625f6ff36df)) -* **core:** Make some functionality of Status public ([#1256](https://github.com/hyperium/tonic/issues/1256)) -* **core:** Expose Response#into_parts and Response#from_parts ([#1263](https://github.com/hyperium/tonic/issues/1263)) -* **build:** Allow setting skip_protoc_run on the prost Builder ([#1318](https://github.com/hyperium/tonic/issues/1318)) - - -# [v0.8.4](https://github.com/hyperium/tonic/compare/v0.8.3...v0.8.4) (2022-11-29) - -This release only contains a release for `tonic-build`. - -### Bug Fixes - -* **build:** Fix CodeGen8uilder typo ([#1165](https://github.com/hyperium/tonic/issues/1165)) ([#1166](https://github.com/hyperium/tonic/issues/1166)) ([c7476ff](https://github.com/hyperium/tonic/commit/c7476fff425b972c7966228fd38a9191e8d2ddc9)) - - -# [v0.8.3](https://github.com/hyperium/tonic/compare/v0.8.2...v0.8.3) (2022-11-28) - -**note:** this version has been yanked due to a typo in the `CodeGenBuilder` -type. - -Included in this release is also the sub-crate major version bumps: - -* `tonic-health` has been bumped to `0.8.0` -* `tonic-reflection` has been bumped to `0.6.0` -* `tonic-web` has been bumped to `0.5.0` - - -### Bug Fixes - -* do not panic while encoding oversized bodies ([#1142](https://github.com/hyperium/tonic/issues/1142)) ([33e22bb](https://github.com/hyperium/tonic/commit/33e22bbc5ef1b74de82394c3ebfea27382419620)), closes [#1141](https://github.com/hyperium/tonic/issues/1141) -* **reflection, health:** Remove transport feature ([#1112](https://github.com/hyperium/tonic/issues/1112)) ([7153289](https://github.com/hyperium/tonic/commit/7153289b51f7770cdd00cefeceddacc4cf36df97)) - - -### Features - -* **build:** Add `build_transport` builder option ([#1130](https://github.com/hyperium/tonic/issues/1130)) ([1f5bc9b](https://github.com/hyperium/tonic/commit/1f5bc9b9d55f814d1cb83de6f43239e275122265)) -* **build:** Add `CodeGenBuilder` ([#1154](https://github.com/hyperium/tonic/issues/1154)) ([c4525ba](https://github.com/hyperium/tonic/commit/c4525ba6ad21cf9db8d1857931f430cbe924aeb5)) -* **build:** Add disable_comments option ([#1127](https://github.com/hyperium/tonic/issues/1127)) ([e188521](https://github.com/hyperium/tonic/commit/e1885211495e63d962bc1d00f9be6eeaab2bb901)) -* Expose `Request#into_parts` and `Request#from_parts` ([#1118](https://github.com/hyperium/tonic/issues/1118)) ([b409ddd](https://github.com/hyperium/tonic/commit/b409ddd478959e239aeef3cb8715cd3ace470a8f)) -* **transport:** add `from_listener` for `TcpIncoming` ([#1093](https://github.com/hyperium/tonic/issues/1093)) ([0b03b30](https://github.com/hyperium/tonic/commit/0b03b30cccc67d517b05587614405d63d942b1bb)) -* **web:** Implement tower::Layer for tonic_web::Config ([#1119](https://github.com/hyperium/tonic/issues/1119)) ([40536dc](https://github.com/hyperium/tonic/commit/40536dc13428f6338610d74f7b45a5f9c87d9335)) -* **web:** Removed Cors impl and replaced with tower-http's CorsLayer ([#1123](https://github.com/hyperium/tonic/issues/1123)) ([a98d719](https://github.com/hyperium/tonic/commit/a98d719fb4b0a88127504a1ab3eb472e842c6b71)), closes [#1122](https://github.com/hyperium/tonic/issues/1122) - - -# [0.8.2](https://github.com/hyperium/tonic/compare/v0.8.1...v0.8.2) (2022-09-28) - - -### Bug Fixes - -* **transport:** Bump axum for CVE-2022-3212 ([#1088](https://github.com/hyperium/tonic/issues/1088)) ([cddd992](https://github.com/hyperium/tonic/commit/cddd99266682127a3fa0e5d601f56a6346369814)) - - -### Features - -* **tonic:** add `Result` type alias for `std::result::Result` ([#1085](https://github.com/hyperium/tonic/issues/1085)) ([56ff45d](https://github.com/hyperium/tonic/commit/56ff45d9a36040c429753d0d118ad980fbfe3eb8)) -* **build:** add `cleanup-markdown` feature flag ([#1086](https://github.com/hyperium/tonic/issues/1086)) ([c1b08df](https://github.com/hyperium/tonic/commit/c1b08dffacb67e13ce7e94a002eee8999ca7c0e5)) -* **tonic:** impl `Clone` for `Status` using `Arc` ([#1076](https://github.com/hyperium/tonic/issues/1076)) ([ee3d0df](https://github.com/hyperium/tonic/commit/ee3d0dfe7556fc7e996764f650ee3351097e7309)) -* **transport:** Expose hyper's H2 adaptive window on server ([#1071](https://github.com/hyperium/tonic/issues/1071)) ([919d28b](https://github.com/hyperium/tonic/commit/919d28b2b96c7c803cec131a9e36e80d2b071701)) - - -# [0.8.1](https://github.com/hyperium/tonic/compare/v0.8.0...v0.8.1) (2022-09-07) - - -### Features - -* **transport:** Expose hyper's H2 adaptive window on server ([#1071](https://github.com/hyperium/tonic/issues/1071)) ([919d28b](https://github.com/hyperium/tonic/commit/919d28b2b96c7c803cec131a9e36e80d2b071701)) -* Reduce the amount of monomorphized code. -* Expose `Extensions::into_http` and `Status::from_error`. -* **health:** Remove `build.rs` and commit generated code. - -# [0.8.0](https://github.com/hyperium/tonic/compare/v0.7.2...v0.8.0) (2022-07-29) - - -### Features - -* Add `Grpc::with_origin` for clients ([#1017](https://github.com/hyperium/tonic/issues/1017)) ([10f6d2f](https://github.com/hyperium/tonic/commit/10f6d2f1a9fa3969599ebd674f7be27f4f458754)) -* **build:** Add option to emit rerun-if-changed instructions ([#1021](https://github.com/hyperium/tonic/issues/1021)) ([1d2083a](https://github.com/hyperium/tonic/commit/1d2083a1a690edcb3f95343edfe229339c4257b7)) -* **build:** Better support for custom codecs ([#999](https://github.com/hyperium/tonic/issues/999)) ([de2e4ac](https://github.com/hyperium/tonic/commit/de2e4ac077c076736dc451f3415ea7da1a61a560)) -* Decouple `NamedService` from the `transport` feature ([#969](https://github.com/hyperium/tonic/issues/969)) ([feae96c](https://github.com/hyperium/tonic/commit/feae96c5be1247af368e6ce665c8df757d298e35)) -* reflection: Export server types. -* reflection: Add `with_service_name`. - -### BREAKING CHANGES - -* **build:** `CODEC_PATH` moved from const to fn -* **tonic** Remove codegen depedency on `compression` feature. -* **tonic** Remove `compression` feature in favor of `gzip` feature. - -# [0.7.2](https://github.com/hyperium/tonic/compare/v0.7.1...v0.7.2) (2022-05-04) - - -### Bug Fixes - -* **build:** Reduce `Default` bound requirement ([#974](https://github.com/hyperium/tonic/issues/974)) ([4533a6e](https://github.com/hyperium/tonic/commit/4533a6e20eb889f8f13446c0edf39613fa4fe9f6)) -* don't enable default features in tower ([#972](https://github.com/hyperium/tonic/issues/972)) ([b4f9634](https://github.com/hyperium/tonic/commit/b4f96343afe6106db80f41f49e576a687bfcd633)) -* **transport:** Emit `HttpsUriWithoutTlsSupport` only with tls feature enabled ([#996](https://github.com/hyperium/tonic/issues/996)) ([1dd5ad2](https://github.com/hyperium/tonic/commit/1dd5ad2b07810fc6eb5015c152ec737b5f0ca39c)) - - -### Features - -* Add TryFrom implementations for MetadataValue ([#990](https://github.com/hyperium/tonic/issues/990)) ([edc5a0d](https://github.com/hyperium/tonic/commit/edc5a0d88d4a392effe065dfcc1c005b6bb55b5d)) - - - -# [0.7.1](https://github.com/hyperium/tonic/compare/v0.7.0...v0.7.1) (2022-04-04) - -### Features - -* **transport:** Add `channel` feature flag ([#960](https://github.com/hyperium/tonic/issues/960)) ([f1ca90f](https://github.com/hyperium/tonic/commit/f1ca90f2882925c30f96ef60ccfd4fe39bc2c93b)) - - -# [0.7.0](https://github.com/hyperium/tonic/compare/v0.6.2...v0.7.0) (2022-03-31) - -### Breaking Changes - -* Update prost to 0.10 ([#948](https://github.com/hyperium/tonic/issues/948)) ([c78274e](https://github.com/hyperium/tonic/commit/c78274e3fe5763cba291a605979cd7175ad6c38f)) -* **build:** use prettyplease to format output ([#890](https://github.com/hyperium/tonic/issues/890)) ([#904](https://github.com/hyperium/tonic/issues/904)) ([d6c0fc1](https://github.com/hyperium/tonic/commit/d6c0fc112b2288a080fd0a727453b24d666e3d79)) -* **tls:** upgrade to tokio-rustls 0.23 (rustls 0.20) ([#859](https://github.com/hyperium/tonic/issues/859)) ([4548997](https://github.com/hyperium/tonic/commit/4548997080c9c34f12dc0ff83ab0e2bb35ceca9c)) -* **transport:** port router to axum ([#830](https://github.com/hyperium/tonic/issues/830)) ([6dfc20e](https://github.com/hyperium/tonic/commit/6dfc20e1db455be12b0a647533c65bbfd6ae78f2)) -* **build:** add must_use to gzip methods ([#892](https://github.com/hyperium/tonic/issues/892)) ([a337f13](https://github.com/hyperium/tonic/commit/a337f132a57dfcc262b70537cf31686519e0f73c)) -* **codec:** Remove `Default` bound on `Codec` ([#894](https://github.com/hyperium/tonic/issues/894)) ([d574cfd](https://github.com/hyperium/tonic/commit/d574cfda3a692d300db02f486a1792a99b3f9f6d)) -* **tonic:** Expose h2 error instead of reason ([#883](https://github.com/hyperium/tonic/issues/883)) ([a33e15a](https://github.com/hyperium/tonic/commit/a33e15a387a6ca1844748346904d28cb4caae84b)) -* **transport:** connect w/ connector infailable ([#922](https://github.com/hyperium/tonic/issues/922)) ([a197c20](https://github.com/hyperium/tonic/commit/a197c20469a666164c5cba280679e55b9e9e2b6c)) -* **transport:** Endpoint returns transport error ([#920](https://github.com/hyperium/tonic/issues/920)) ([ee6e726](https://github.com/hyperium/tonic/commit/ee6e726707a6839c6cabe672eb296c6118a2a1cd)) -* Handle interceptor errors as responses ([#840](https://github.com/hyperium/tonic/issues/840)) ([#842](https://github.com/hyperium/tonic/issues/842)) ([bf44940](https://github.com/hyperium/tonic/commit/bf44940f9b73709a83b31e4595a3d8ad262797a3)) - - -### Bug Fixes - -* **codec:** Return None after poll_data error ([#921](https://github.com/hyperium/tonic/issues/921)) ([d7cae70](https://github.com/hyperium/tonic/commit/d7cae702fc2284473846db7c946baf87977b7b48)) -* **health:** Correctly implement spec for overall health ([#897](https://github.com/hyperium/tonic/issues/897)) ([2b0ffee](https://github.com/hyperium/tonic/commit/2b0ffee62034f5983f8d6dcdafccd66f780559f2)) -* **tonic:** Preserve HTTP method in interceptor ([#912](https://github.com/hyperium/tonic/issues/912)) ([e623562](https://github.com/hyperium/tonic/commit/e6235623c4707f97e9b9f7c3ba88745050a884e5)) -* **transport:** Make `Server::layer()` support more than one layer ([#932](https://github.com/hyperium/tonic/issues/932)) ([e30bb7e](https://github.com/hyperium/tonic/commit/e30bb7ede7e107a3181cd786533c250ba09a2fcf)) -* **transport:** Make server builder more consistent ([#901](https://github.com/hyperium/tonic/issues/901)) ([6763d19](https://github.com/hyperium/tonic/commit/6763d191d267c1b9f861b96ad0f4b850e0264f4d)) -* Return error on non https uri instead of panic ([#838](https://github.com/hyperium/tonic/issues/838)) ([ef6e245](https://github.com/hyperium/tonic/commit/ef6e245180936097e56f5f95ed8b182674f3131b)) - - -### Features - -* **build:** Expose Prost generation plugin ([#947](https://github.com/hyperium/tonic/issues/947)) ([d4bd475](https://github.com/hyperium/tonic/commit/d4bd4758dd80135f89d3e559c5d7f42ccbbab504)) -* **build:** add constructor `from_arc` for gRPC servers ([#875](https://github.com/hyperium/tonic/issues/875)) ([7179f7a](https://github.com/hyperium/tonic/commit/7179f7ae6a5186bb64e4c120302084f56c053206)) -* **health:** Expose `HealthService` publically ([#930](https://github.com/hyperium/tonic/issues/930)) ([097e7e8](https://github.com/hyperium/tonic/commit/097e7e85a9079bb76bef54921f03c6f7e0ee0744)) -* **transport:** add unix socket support in server ([#861](https://github.com/hyperium/tonic/issues/861)) ([dee2ab5](https://github.com/hyperium/tonic/commit/dee2ab52ff4a2995156a3baf5ea916b479fd1d14)) -* **transport:** support customizing `Channel`'s async executor ([#935](https://github.com/hyperium/tonic/issues/935)) ([0859d82](https://github.com/hyperium/tonic/commit/0859d82e577fb024e39ce9b5b7356b95dcb66562)) -* Implement hash for `Code` ([#917](https://github.com/hyperium/tonic/issues/917)) ([6bc7dab](https://github.com/hyperium/tonic/commit/6bc7dab8e099c8ce226a6261e545d8d131c604f0)) - - - -# [0.6.2](https://github.com/hyperium/tonic/compare/v0.6.1...v0.6.2) (2021-12-07) - - -### Bug Fixes - -* **tonic:** revert to 2018 edition ([#843](https://github.com/hyperium/tonic/issues/843)) ([101f2f7](https://github.com/hyperium/tonic/commit/101f2f76d4a62757cac8ca209b1eb6b57094d524)) - - -# [0.6.1](https://github.com/hyperium/tonic/compare/v0.6.0...v0.6.1) (2021-10-27) - - -### Bug Fixes - -* **transport:** Bump hyper to 0.14.14 ([#813](https://github.com/hyperium/tonic/issues/813)) ([2a3e9b2](https://github.com/hyperium/tonic/commit/2a3e9b2f6fa459b065c5a4ebeab5f447a3515707)) - - - -# [0.6.0](https://github.com/hyperium/tonic/compare/v0.5.2...v0.6.0) (2021-10-25) - -### Breaking changes - -* **tonic:** Remove `Sync` requirement for streams ([#804](https://github.com/hyperium/tonic/issues/804)) ([23c1392](https://github.com/hyperium/tonic/commit/23c1392fb7e0ac50bcdedc35509917061bc858e1)) -* **tonic:** change `connect_lazy` to be infallible ([#712](https://github.com/hyperium/tonic/issues/712)) ([2e47154](https://github.com/hyperium/tonic/commit/2e471548d89be98d26b2332d059a24a3fc15ec23)) -* **build:** split path types in compile ([#721](https://github.com/hyperium/tonic/issues/721)) ([53ecc1f](https://github.com/hyperium/tonic/commit/53ecc1f85e7f7eeb0dce4ab23432d6c36d8a46b0)) -* Update `prost` and friends to 0.9 ([#791](https://github.com/hyperium/tonic/issues/791)) ([09805ec](https://github.com/hyperium/tonic/commit/09805ece453047bf609b1a69c72931eae6e1144a)) - -### Bug Fixes - -* **build:** Correctly convert `Empty` to `()` ([#734](https://github.com/hyperium/tonic/issues/734)) ([ff6a690](https://github.com/hyperium/tonic/commit/ff6a690cec9daca33984cabea66f9d370ac63462)) -* **tonic:** fix extensions disappearing during streaming requests ([5c1bb90](https://github.com/hyperium/tonic/commit/5c1bb90ce82ecf90843a7c959edd7ef8fc280f62)), closes [#770](https://github.com/hyperium/tonic/issues/770) -* **tonic:** Status code to set correct source on unknown error ([#799](https://github.com/hyperium/tonic/issues/799)) ([4054d61](https://github.com/hyperium/tonic/commit/4054d61e14b9794a72b48de1a051c26129ec36b1)) -* **transport:** AddOrigin panic on invalid uri ([#801](https://github.com/hyperium/tonic/issues/801)) ([3ab00f3](https://github.com/hyperium/tonic/commit/3ab00f304dd204fccf00d1995e635fa6b2f8503b)) -* **transport:** Correctly map hyper errors ([#629](https://github.com/hyperium/tonic/issues/629)) ([4947b07](https://github.com/hyperium/tonic/commit/4947b076f5b0b5149ee7f6144515535b85f65db5)) -* **tonic:** compression: handle compression flag but no header (#763) - - -### Features - -* **build:** Support prost's include_file option ([#774](https://github.com/hyperium/tonic/issues/774)) ([3f9ab80](https://github.com/hyperium/tonic/commit/3f9ab801f7ee50ec04ab0f73cd457898dc687e61)) -* **health, reflection:** make rustfmt dependency optional (#785) - - -# [0.5.2](https://github.com/hyperium/tonic/compare/v0.5.1...v0.5.2) (2021-08-10) - -* **tonic:** add `Interceptor` trait (#713) ([#713](https://github.com/hyperium/tonic/issues/713)) ([8c8f4d1](https://github.com/hyperium/tonic/commit/8c8f4d1)) - -# [0.5.1](https://github.com/hyperium/tonic/compare/v0.5.0...v0.5.1) (2021-08-09) - -### Features - -* **health:** Expose grpc_health_v1 file descriptor set ([#620](https://github.com/hyperium/tonic/issues/620)) ([167e8cb](https://github.com/hyperium/tonic/commit/167e8cb)), closes [#619](https://github.com/hyperium/tonic/issues/619) -* **tonic:** derive `Clone` for `RouterService` (#714) ([#714](https://github.com/hyperium/tonic/issues/714)) ([0a06603](https://github.com/hyperium/tonic/commit/0a06603)) -* **transport:** Add `Connected` impl for `DuplexStream` (#722) ([#722](https://github.com/hyperium/tonic/issues/722)) ([0e33a02](https://github.com/hyperium/tonic/commit/0e33a02)) - -### Bug Fixes - -* **build:** remove unnecessary `Debug` constraint for client streams ([#719](https://github.com/hyperium/tonic/issues/719)) ([167e8cb](https://github.com/hyperium/tonic/commit/167e8cb)), closes [#718](https://github.com/hyperium/tonic/issues/718) -* **build:** allow services to be named `Service` ([#709](https://github.com/hyperium/tonic/issues/709)) ([380d81d](https://github.com/hyperium/tonic/commit/380d81d)), closes [#676](https://github.com/hyperium/tonic/issues/676) - -# [0.5.0](https://github.com/hyperium/tonic/compare/v0.4.3...v0.5.0) (2021-07-08) - -This release includes a new crate `tonic-web` which is versioned at `0.1` and supports accepting `grpc-web`! - -### Breaking changes - -* `prost` bumped to `0.8`. -* `BoxBody` was removed in favor of the version provided in `http-body`. -* The `Connected` trait has been modified to support more generic `ConnectionInfo`. -* `Streaming` fixed to now return `None` once the stream has observed a trailing `Status`, notifying the user that the stream has ended. -* A new interceptor API. - -### Bug Fixes - -* **codec:** Fix streaming reponses w/ many status ([#689](https://github.com/hyperium/tonic/issues/689)) ([737ace3](https://github.com/hyperium/tonic/commit/737ace393d3d11fb179af939e5f1a5d16ebc2b82)), closes [#681](https://github.com/hyperium/tonic/issues/681) -* **build:** fix `with_interceptor` not building on Rust 1.51 ([#669](https://github.com/hyperium/tonic/issues/669)) ([9478fac](https://github.com/hyperium/tonic/commit/9478fac97984cf8291bf89c55eb9a02a06889e03)) -* **codec:** improve error message for invalid compression flag ([#663](https://github.com/hyperium/tonic/issues/663)) ([9cc14b7](https://github.com/hyperium/tonic/commit/9cc14b79fba9e789e215f7ea3fa40ccfaecc8e59)) -* **tonic:** don't include error's cause in Display impl ([#633](https://github.com/hyperium/tonic/issues/633)) ([31a3468](https://github.com/hyperium/tonic/commit/31a34681c7ba606e27615859d4b65dfcdcaa6f38)) -* **transport:** remove needless `BoxFuture` ([#644](https://github.com/hyperium/tonic/issues/644)) ([74ad0a9](https://github.com/hyperium/tonic/commit/74ad0a998fedb2507f6b2f035b961eb9bac5b494)) -* **web:** fix compilation ([#670](https://github.com/hyperium/tonic/issues/670)) ([e199387](https://github.com/hyperium/tonic/commit/e1993877c430906500aeda9ab1e3413e68ed483d)) - - -### Features - -* **build:** support adding attributes to clients and servers ([#684](https://github.com/hyperium/tonic/issues/684)) ([a948a8f](https://github.com/hyperium/tonic/commit/a948a8f884705b9f2a6df5c86d07cc6eb0bb1b7c)) -* **codec:** compression support ([#692](https://github.com/hyperium/tonic/issues/692)) ([0583cff](https://github.com/hyperium/tonic/commit/0583cff80f57ba071295416ee8828c3430851d0d)) -* **metadata:** expose `IterMut` and `ValuesMut` ([#639](https://github.com/hyperium/tonic/issues/639)) ([b0ec3ea](https://github.com/hyperium/tonic/commit/b0ec3ead344df44fc17e5ad22398ed2464768e63)) -* **metadata:** remove manual `Send + Sync` impls for metadata types ([#640](https://github.com/hyperium/tonic/issues/640)) ([e97f518](https://github.com/hyperium/tonic/commit/e97f5180250a567aead16fe9a8644216edc4bbb3)) -* **tonic:** add `h2::Error` as a `source` for `Status` ([#612](https://github.com/hyperium/tonic/issues/612)) ([b90bb7b](https://github.com/hyperium/tonic/commit/b90bb7bbc012207451fe2788a8efd69023312425)) -* **tonic:** add `Request` and `Response` extensions ([#642](https://github.com/hyperium/tonic/issues/642)) ([352b0f5](https://github.com/hyperium/tonic/commit/352b0f584be33bc49ca266698c9224d16a6825ff)) -* **tonic:** expose setting for `http2_adaptive_window` ([#657](https://github.com/hyperium/tonic/issues/657)) ([12815d0](https://github.com/hyperium/tonic/commit/12815d0a1d558eb9f661a85354336b04df1f5bab)) -* **tonic:** implement `From` for `i32` ([f33316d](https://github.com/hyperium/tonic/commit/f33316d5b32f6a44fa23ea12851f502c48bac5ea)) -* **tonic:** make it easier to add tower middleware to servers ([#651](https://github.com/hyperium/tonic/issues/651)) ([4d2667d](https://github.com/hyperium/tonic/commit/4d2667d1cb1b938756d20dafa3cccae1db23a831)) -* **tonic:** pass `trace_fn` the request rather than just the headers ([#634](https://github.com/hyperium/tonic/issues/634)) ([7862a22](https://github.com/hyperium/tonic/commit/7862a2259db8dc1af440604c6c582487a59a2709)) -* **tonic:** Use `BoxBody` from `http-body` crate ([#622](https://github.com/hyperium/tonic/issues/622)) ([4dda4cb](https://github.com/hyperium/tonic/commit/4dda4cbcca88fa46a7d8a6e4eabfb6d7c333617a)) -* **tonic-web:** implement grpc <-> grpc-web protocol translation ([#455](https://github.com/hyperium/tonic/issues/455)) ([c309063](https://github.com/hyperium/tonic/commit/c309063254dff42fd05afc5e56b0b0371b905758)) -* **transport:** Add `connect_with_connector_lazy` ([#696](https://github.com/hyperium/tonic/issues/696)) ([2a46ff5](https://github.com/hyperium/tonic/commit/2a46ff5c96415b217700353dadba74a80e5ad88c)), closes [#695](https://github.com/hyperium/tonic/issues/695) -* **transport:** Add a tls-webpki-roots feature to add trust roots from webpki-roots ([#660](https://github.com/hyperium/tonic/issues/660)) ([32173dc](https://github.com/hyperium/tonic/commit/32173dc7f6521bad8f26b055b6a86d807348f151)) -* **transport:** add connect timeout to `Endpoint` ([#662](https://github.com/hyperium/tonic/issues/662)) ([2b60a00](https://github.com/hyperium/tonic/commit/2b60a00614c5c4260ce0acaaa599da89bebfd267)) -* **transport:** provide generic access to connect info ([#647](https://github.com/hyperium/tonic/issues/647)) ([e5e3118](https://github.com/hyperium/tonic/commit/e5e311853bff347355722bc829d40f54e8954aee)) - - -# [0.4.3](https://github.com/hyperium/tonic/compare/v0.4.2...v0.4.3) (2021-04-29) - -### Features - -* **client:** Add `Request::set_timeout` ([#615](https://github.com/hyperium/tonic/issues/615)) ([dae31d0](https://github.com/hyperium/tonic/commit/dae31d0)) -* **transport:** Configure TLS automatically when possible ([#445](https://github.com/hyperium/tonic/issues/445)) ([b04c1c6](https://github.com/hyperium/tonic/commit/b04c1c6)) -* **transport:** Support timeouts with the `grpc-timeout` header ([#606](https://github.com/hyperium/tonic/issues/606)) ([9ff4f7b](https://github.com/hyperium/tonic/commit/9ff4f7b)) - -# [0.4.2](https://github.com/hyperium/tonic/compare/v0.4.1...v0.4.2) (2021-04-13) - -### Bug Fixes - -* **codec:** Allocate inbound buffer once ([#578](https://github.com/hyperium/tonic/issues/578)) ([1d2754f](https://github.com/hyperium/tonic/commit/1d2754feba6b49bfc813f41e8e8e42ffaf8ab0dd)) -* **reflection:** Depend on correct version of build ([#582](https://github.com/hyperium/tonic/issues/582)) ([db09093](https://github.com/hyperium/tonic/commit/db0909382b8ab1a385c1352feeea663844b7d799)) - - -### Features - -* **health:** Expose proto and client ([#471](https://github.com/hyperium/tonic/issues/471)) ([#602](https://github.com/hyperium/tonic/issues/602)) ([49f6137](https://github.com/hyperium/tonic/commit/49f613767341656cad1cc4883ff0e89b03d378ae)) -* Expose status constructors ([#579](https://github.com/hyperium/tonic/issues/579)) ([0d05aa0](https://github.com/hyperium/tonic/commit/0d05aa0d02bd3037e81c72dcf7fa5168d5a62097)) -* **build:** Add `prostoc_args` ([#577](https://github.com/hyperium/tonic/issues/577)) ([480a794](https://github.com/hyperium/tonic/commit/480a79409c4cb9a1c680e57d0f74ad1d4f18beaa)) - - -# [0.4.1](https://github.com/hyperium/tonic/compare/v0.3.1...v0.4.1) (2021-03-16) - -### Features - -* feat(reflection): Implement gRPC Reflection Service (#340) ([c54f247](https://github.com/hyperium/tonic/commit/c54f247)), closes [#340](https://github.com/hyperium/tonic/issues/340) -* feat(build): Add disable_package_emission option to tonic-build (#556) ([4f5e160](https://github.com/hyperium/tonic/commit/4f5e160)), closes [#556](https://github.com/hyperium/tonic/issues/556) -* feat(build): Support compiling well-known protobuf types (#522) ([61555ff](https://github.com/hyperium/tonic/commit/61555ff)), closes [#522](https://github.com/hyperium/tonic/issues/522) -* feat(build): Use `RUSTFMT` to find `rustfmt` binary (#566) ([ea56e2e](https://github.com/hyperium/tonic/commit/ea56e2e)), closes [#566](https://github.com/hyperium/tonic/issues/566) -* chore: add FromStr for Endpoint (#558) ([f49d4bd](https://github.com/hyperium/tonic/commit/f49d4bd)), closes [#558](https://github.com/hyperium/tonic/issues/558) - -### Bug Fixes - -* fix: Depend on at least tower 0.4.4 (#554) ([ca3b9a1](https://github.com/hyperium/tonic/commit/ca3b9a1)), closes [#554](https://github.com/hyperium/tonic/issues/554) [#553](https://github.com/hyperium/tonic/issues/553) [#552](https://github.com/hyperium/tonic/issues/552) [#553](https://github.com/hyperium/tonic/issues/553) [#552](https://github.com/hyperium/tonic/issues/552) - -# [0.4.0](https://github.com/hyperium/tonic/compare/v0.3.1...v0.4.0) (2021-01-15) - -This version brings Tonic inline with Tokio 1.0 and Prost 0.7! This release also includes new versions of `tonic-types`, `tonic-build`, and `tonic-health`. - -### Bug Fixes - -* **transport:** return Poll::ready until error is consumed ([#536](https://github.com/hyperium/tonic/issues/536)) ([dafea9a](https://github.com/hyperium/tonic/commit/dafea9adeec5626ee780bc3ad7dc69691db51a82)) -* gracefully handle bad native certs ([#520](https://github.com/hyperium/tonic/issues/520)) ([fe4d5b9](https://github.com/hyperium/tonic/commit/fe4d5b9d9a0fdcf414bbe31c2fcad59e8cc03da8)), closes [#519](https://github.com/hyperium/tonic/issues/519) -* **build:** Add content-type for generated unimplemented service ([#441](https://github.com/hyperium/tonic/issues/441)) ([62c1230](https://github.com/hyperium/tonic/commit/62c1230117bcaa6f45cb0fa0697b89b9255a94a5)) -* **build:** Match namespace code with other generated packages ([#472](https://github.com/hyperium/tonic/issues/472)) ([1b03ece](https://github.com/hyperium/tonic/commit/1b03ece2a81cb7e8b1922b3c3c1f496bd402d76c)) -* **transport:** Add content-type for Unimplemented ([#434](https://github.com/hyperium/tonic/issues/434)) ([594a542](https://github.com/hyperium/tonic/commit/594a542b8a9e8f9f4c3bd1d0a08e87ce74a850e5)) -* **transport:** reconnect lazy connections after first failure ([#458](https://github.com/hyperium/tonic/issues/458)) ([e9910d1](https://github.com/hyperium/tonic/commit/e9910d10a7c1287a2247a236b45dbf31eceb08bd)), closes [#452](https://github.com/hyperium/tonic/issues/452) -* **client:** Merge trailer and initla headers into status on err ([#510](https://github.com/hyperium/tonic/pull/510)) -* **transport:** Fix TLS accept w/ peer certs ([#535](https://github.com/hyperium/tonic/issues/535)) ([41c51f1](https://github.com/hyperium/tonic/commit/41c51f1c61ac957e439ced4302f09160c850787e)) - -### Features - -* **status:** implement From for Status ([#500](https://github.com/hyperium/tonic/issues/500)) ([fc86563](https://github.com/hyperium/tonic/commit/fc86563b369d0b73a79d3e8dc9a84d5ce1513303)) -* **transport:** Add `Router::into_service` ([#419](https://github.com/hyperium/tonic/issues/419)) ([37f6733](https://github.com/hyperium/tonic/commit/37f6733f85a42e828c124026c3a0f21919549b12)) -* **transport:** add max http2 frame size to server. ([#529](https://github.com/hyperium/tonic/issues/529)) ([31936e0](https://github.com/hyperium/tonic/commit/31936e0513a41e83c8137786bd417fe57ecd05eb)), closes [#264](https://github.com/hyperium/tonic/issues/264) -* **transport:** add user-agent header to client requests. ([#457](https://github.com/hyperium/tonic/issues/457)) ([d4899df](https://github.com/hyperium/tonic/commit/d4899df83287a4eb1a91754c2e2955000d13c5f4)), closes [#453](https://github.com/hyperium/tonic/issues/453) -* **transport:** Connect lazily in the load balanced channel ([#493](https://github.com/hyperium/tonic/issues/493)) ([2e964c7](https://github.com/hyperium/tonic/commit/2e964c78c666ecd6e6cfc37689d30300cad81f4c)) -* **transport:** expose HTTP2 server keepalive interval and timeout ([#486](https://github.com/hyperium/tonic/issues/486)) ([2b9cdb9](https://github.com/hyperium/tonic/commit/2b9cdb9779eb5cb7d3862e1ce95ab63f847ec223)), closes [#474](https://github.com/hyperium/tonic/issues/474) -* **transport:** Move error! to debug! ([#537](https://github.com/hyperium/tonic/issues/537)) ([a7778ad](https://github.com/hyperium/tonic/commit/a7778ad16611b7ade64c33256eecf9825408f06a)) -* **transport:** Do not panic when building and Endpoint with an invali… (#438) ([26ce9d1](https://github.com/hyperium/tonic/commit/26ce9d12bf1765e5a7acb07cab05b6bd75bd4e4d)), closes [#438](https://github.com/hyperium/tonic/issues/438) - - -### BREAKING CHANGES - -* `TryFrom` API has been changed. -* Upgraded to `tokio 1.0` and `prost 0.7`. -* `Channel` now implements `Service` instead of `GrpcService`. - - -# [0.3.1](https://github.com/hyperium/tonic/compare/v0.3.0...v0.3.1) (2020-08-20) - - -### Bug Fixes - -* **transport:** Return connection error on `Channel::connect` ([#413](https://github.com/hyperium/tonic/issues/413)) ([2ea17b2](https://github.com/hyperium/tonic/commit/2ea17b2ecfc40a20f4d9608f807b3d099a8f415d)), closes [#403](https://github.com/hyperium/tonic/issues/403) - - - -# [0.3.0](https://github.com/hyperium/tonic/compare/v0.2.1...v0.3.0) (2020-07-13) - - -### Bug Fixes - -* `Status::details` leaking base64 encoding ([#395](https://github.com/hyperium/tonic/issues/395)) ([2c4c544](https://github.com/hyperium/tonic/commit/2c4c544d902c588fc0654910fba1f0d21d78eab3)), closes [#379](https://github.com/hyperium/tonic/issues/379) -* **build:** Allow empty packages ([#382](https://github.com/hyperium/tonic/issues/382)) ([f085aba](https://github.com/hyperium/tonic/commit/f085aba302001986fd04219d2843f659f73c4031)), closes [#381](https://github.com/hyperium/tonic/issues/381) -* **build:** Make generated server service public ([#347](https://github.com/hyperium/tonic/issues/347)) ([8cd6f05](https://github.com/hyperium/tonic/commit/8cd6f0506429cfbe59e63b0216f208482d12358a)) -* **transport:** Propagate errors in tls_config instead of unwrap/panic ([#385](https://github.com/hyperium/tonic/issues/385)) ([3b9d6a6](https://github.com/hyperium/tonic/commit/3b9d6a6262b62f30b8c9953f0da8e403be53216e)) -* Remove uses of pin_project::project attribute ([#367](https://github.com/hyperium/tonic/issues/367)) ([5bda615](https://github.com/hyperium/tonic/commit/5bda6156328bd2c94bc274588871b666f1b72d6e)) - - -### Features - -* **codec:** Improve compression flag log ([#374](https://github.com/hyperium/tonic/issues/374)) ([d68dd36](https://github.com/hyperium/tonic/commit/d68dd365321764aceaf4e37a106a519797926495)) -* **transport:** Add Endpoint::connect_lazy method ([#392](https://github.com/hyperium/tonic/issues/392)) ([ec9046d](https://github.com/hyperium/tonic/commit/ec9046dfc23d63828363d9555cd7b96811ad442d)), closes [#167](https://github.com/hyperium/tonic/issues/167) -* **transport:** Add optional service methods ([#275](https://github.com/hyperium/tonic/issues/275)) ([2b997b0](https://github.com/hyperium/tonic/commit/2b997b0c5f37d69f3cd8b5b566b64df110d9f4eb)) -* **transport:** Dynamic load balancing ([#341](https://github.com/hyperium/tonic/issues/341)) ([85ae0a4](https://github.com/hyperium/tonic/commit/85ae0a4733b9e99edaa05e65160d98f21f288fc1)) -* **types:** Add `tonic-types` crate ([#391](https://github.com/hyperium/tonic/issues/391)) ([ea7fe66](https://github.com/hyperium/tonic/commit/ea7fe66b145e01891f1c1f16d247e02524d98fae)) -* Add `Display` implementation for `Code` ([#386](https://github.com/hyperium/tonic/issues/386)) ([ab1de44](https://github.com/hyperium/tonic/commit/ab1de44771f3fa6ac283485bdbf1035d6407ac1a)) -* Add `Status::to_http` ([#376](https://github.com/hyperium/tonic/issues/376)) ([327b4ff](https://github.com/hyperium/tonic/commit/327b4fffa3381345ee4620df7e9998efe2aa9454)) -* Add metadata to error responses ([#348](https://github.com/hyperium/tonic/issues/348)) ([372da52](https://github.com/hyperium/tonic/commit/372da52e96114ca76cc221f3c598be82bfae970c)) -* add new method get_uri for Endpoint ([#371](https://github.com/hyperium/tonic/issues/371)) ([54d7a7a](https://github.com/hyperium/tonic/commit/54d7a7af6b6530b80353c5741586c38cca8382c9)) - - - -## [0.2.1](https://github.com/hyperium/tonic/compare/v0.2.0...v0.2.1) (2020-05-07) - - -### Bug Fixes - -* base64 encode details header ([#345](https://github.com/hyperium/tonic/issues/345)) ([e683ffe](https://github.com/hyperium/tonic/commit/e683ffef1fcbe0ace9cc696232489f5f6600e83f)) -* **build:** Remove ambiguity in service method call ([#327](https://github.com/hyperium/tonic/issues/327)) ([5d56daa](https://github.com/hyperium/tonic/commit/5d56daa721cfb18edc74cf50db4270e2c8461fc9)) -* **transport:** Apply tls-connector for discovery when applicable ([#334](https://github.com/hyperium/tonic/issues/334)) ([#338](https://github.com/hyperium/tonic/issues/338)) ([99fbe22](https://github.com/hyperium/tonic/commit/99fbe22e7c1340d6be9ee5d3ae9738850881af61)) - - -### Features - -* **transport:** Add AsRef impl for Certificate ([#326](https://github.com/hyperium/tonic/issues/326)) ([d2ad8df](https://github.com/hyperium/tonic/commit/d2ad8df629a349cc151a0a4ede96f04356f73839)) - - - -# [0.2.0](https://github.com/hyperium/tonic/compare/v0.1.1...v0.2.0) (2020-04-01) - - -### Bug Fixes - -* **build:** Allow non_camel_case_types on codegen structs ([224280d](https://github.com/hyperium/tonic/commit/224280dfff8944e9e553337416d23d6e5a050945)), closes [#295](https://github.com/hyperium/tonic/issues/295) -* **build:** Don't replace extern_paths ([#261](https://github.com/hyperium/tonic/issues/261)) ([1b3d107](https://github.com/hyperium/tonic/commit/1b3d107206136312a2536d3b72748c52191d99b1)) -* **build:** Ignore non `.rs` files with rustfmt ([#284](https://github.com/hyperium/tonic/issues/284)) ([7dfa2a2](https://github.com/hyperium/tonic/commit/7dfa2a277b593e008cea53eef7163ca59a06c56a)), closes [#283](https://github.com/hyperium/tonic/issues/283) -* **build:** Implement Debug for client struct ([6dbe88d](https://github.com/hyperium/tonic/commit/6dbe88d445e378fff48d05083c23baeb2020cb2d)), closes [#298](https://github.com/hyperium/tonic/issues/298) -* **build:** Remove debug println! ([#287](https://github.com/hyperium/tonic/issues/287)) ([e2c2be2](https://github.com/hyperium/tonic/commit/e2c2be2f084b7c1ef4e93f6994cb9c728de0c1ed)) -* **build:** Server service uses generic body bound ([#306](https://github.com/hyperium/tonic/issues/306)) ([5758b75](https://github.com/hyperium/tonic/commit/5758b758b2d44059b0149a31542d11589999a789)) -* **health:** Set referenced version of tonic ([59c7788](https://github.com/hyperium/tonic/commit/59c77888464a0302993dbe07fed7c1848b415f8f)) -* **metadata:** Remove deprecated error description ([61e0429](https://github.com/hyperium/tonic/commit/61e0429ae810354363835c36a046b5113b3c74b4)) -* **transport:** Handle tls accepting on task ([#320](https://github.com/hyperium/tonic/issues/320)) ([04a8c0c](https://github.com/hyperium/tonic/commit/04a8c0c82a4007f48c3bf3539a3f2312746fedd1)) - - -### Features - -* **build:** Add support for custom prost config ([#318](https://github.com/hyperium/tonic/issues/318)) ([202093c](https://github.com/hyperium/tonic/commit/202093c31715b52997c6c206c758924ff5f69bc8)) -* **health:** Add tonic-health server impl ([da92dbf](https://github.com/hyperium/tonic/commit/da92dbf8aa885ea0ea05755e9432532fc980e353)), closes [#135](https://github.com/hyperium/tonic/issues/135) [#135](https://github.com/hyperium/tonic/issues/135) -* Add Status with Details Constructor ([#308](https://github.com/hyperium/tonic/issues/308)) ([cfd59db](https://github.com/hyperium/tonic/commit/cfd59dbb342a8b7d216f4856e13d24b564c606f3)) -* **build:** Decouple codgen from `prost` ([#170](https://github.com/hyperium/tonic/issues/170)) ([f65cda1](https://github.com/hyperium/tonic/commit/f65cda1ea0a190fe07c4f8d91473baad9a6f1f77)) -* **transport:** Expose http2 keep-alive support ([#307](https://github.com/hyperium/tonic/issues/307)) ([012fa3c](https://github.com/hyperium/tonic/commit/012fa3cb4a0e010dafa28305416fab6c4278fc7b)) - - - -## [0.1.1](https://github.com/hyperium/tonic/compare/v0.1.0...v0.1.1) (2020-01-20) - - -### Bug Fixes - -* **build:** Typo with client mod docstring ([#237](https://github.com/hyperium/tonic/issues/237)) ([5fc6762](https://github.com/hyperium/tonic/commit/5fc6762435494d8df023bea8e35a5d20d81f2f3b)) -* **transport:** Add Connected impl for TcpStream ([#245](https://github.com/hyperium/tonic/issues/245)) ([cfdf0af](https://github.com/hyperium/tonic/commit/cfdf0aff549196af0c3b7f6e531dbeacfb6990dc)) -* **transport:** Use Uri host if no domain for tls ([#244](https://github.com/hyperium/tonic/issues/244)) ([6de0b4d](https://github.com/hyperium/tonic/commit/6de0b4d26fd82b4d1303080b0ba8c4db2d4f0fd1)) - - - -# [0.1.0](https://github.com/hyperium/tonic/compare/v0.1.0-beta.1...v0.1.0) (2020-01-14) - - -### Bug Fixes - -* **build:** Remove default impl for Server traits ([#229](https://github.com/hyperium/tonic/issues/229)) ([a41f55a](https://github.com/hyperium/tonic/commit/a41f55ab9dfe77fca920b3c2e89343c7ce963225)) -* **transport:** Improve `Error` type ([#217](https://github.com/hyperium/tonic/issues/217)) ([ec1f37e](https://github.com/hyperium/tonic/commit/ec1f37e4b46279d20f4fadafa5bf30cfb729fa42)) - - -### chore - -* rename ServiceName -> NamedService ([#233](https://github.com/hyperium/tonic/issues/233)) ([6ee2ed9](https://github.com/hyperium/tonic/commit/6ee2ed9b4ff30c0517d70908c6348a633dab5b91)) - - -### Features - -* Add gRPC interceptors ([#232](https://github.com/hyperium/tonic/issues/232)) ([eba7ec7](https://github.com/hyperium/tonic/commit/eba7ec7b32fb96938cbdc3d2dfd91c238afda0dc)) -* **build:** Add extern_path config support ([#223](https://github.com/hyperium/tonic/issues/223)) ([e034288](https://github.com/hyperium/tonic/commit/e034288c3739467238aee54fdbe0a2a3a87bf824)) -* **codec:** Introduce `Decoder/Encoder` traits ([#208](https://github.com/hyperium/tonic/issues/208)) ([0fa2bf1](https://github.com/hyperium/tonic/commit/0fa2bf1cea9d1166d49e40f2211268611b6993de)) -* **transport:** Add `serve_with_incoming_shutdown` ([#220](https://github.com/hyperium/tonic/issues/220)) ([a66595b](https://github.com/hyperium/tonic/commit/a66595bfe3c146daaa437bddd5ce3db4542b1bf6)) -* **transport:** Add server side peer cert support ([#228](https://github.com/hyperium/tonic/issues/228)) ([af807c3](https://github.com/hyperium/tonic/commit/af807c3ccd283cee0e424e75298cd176424767ca)) - - -### BREAKING CHANGES - -* Rename `ServiceName` to `NamedService`. -* removed `interceptor_fn` and `intercep_headers_fn` from `transport` in favor of using `tonic::Interceptor`. -* **codec:** Add new `Decoder/Encoder` traits and use `EncodeBuf/DecodeBuf` over `BytesMut` directly. -* **build:** remove default implementations for server traits. - - - -# [0.1.0-beta.1](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.5...v0.1.0-beta.1) (2019-12-19) - - -### Bug Fixes - -* **build:** Allow creating multiple services in the same package ([#173](https://github.com/hyperium/tonic/issues/173)) ([0847b67](https://github.com/hyperium/tonic/commit/0847b67c4eb66a814c8c447a57fade2552e64a85)) -* **build:** Prevent duplicated client/server generated code ([#121](https://github.com/hyperium/tonic/issues/121)) ([b02b4b2](https://github.com/hyperium/tonic/commit/b02b4b238bfee96b886609396b957e2592477ecb)) -* **build:** Remove async ready ([#185](https://github.com/hyperium/tonic/issues/185)) ([97d5363](https://github.com/hyperium/tonic/commit/97d5363e2b2aee456edc5db4b5b53316c8b40745)) -* **build:** snake_case service names ([#190](https://github.com/hyperium/tonic/issues/190)) ([3a5c66d](https://github.com/hyperium/tonic/commit/3a5c66d5f236eaece05dbd9fd1e1a00a3ab98259)) -* **docs:** typo in lib.rs ([#142](https://github.com/hyperium/tonic/issues/142)) ([c63c107](https://github.com/hyperium/tonic/commit/c63c107560db165303c369487006b3507a0e7e07)) -* **examples:** Remove use of VecDeque as a placeholder type ([#143](https://github.com/hyperium/tonic/issues/143)) ([354d4fd](https://github.com/hyperium/tonic/commit/354d4fdc35dc51575f4c685fc04354f2058061ff)) -* **transport:** Fix infinite recursion in `poll_ready` ([#192](https://github.com/hyperium/tonic/issues/192)) ([c99d13c](https://github.com/hyperium/tonic/commit/c99d13c6e669be3a6ecf428ae32d4b937393738a)), closes [#184](https://github.com/hyperium/tonic/issues/184) [#191](https://github.com/hyperium/tonic/issues/191) -* **transport:** Fix lazily reconnecting ([#187](https://github.com/hyperium/tonic/issues/187)) ([0505dff](https://github.com/hyperium/tonic/commit/0505dff65a18c162c3ae398d42ed20ac54351439)), closes [#167](https://github.com/hyperium/tonic/issues/167) -* **transport:** Load balance connecting panic ([#128](https://github.com/hyperium/tonic/issues/128)) ([23e7695](https://github.com/hyperium/tonic/commit/23e7695800d8f22ee8e0ba7456f5ffc4b19430c3)), closes [#127](https://github.com/hyperium/tonic/issues/127) -* **transport:** Remove support for OpenSSL ([#141](https://github.com/hyperium/tonic/issues/141)) ([8506050](https://github.com/hyperium/tonic/commit/85060500f3a8f91ed47c632e07896c9e5567629a)) -* **transport:** Remove with_rustls for tls config ([#188](https://github.com/hyperium/tonic/issues/188)) ([502491a](https://github.com/hyperium/tonic/commit/502491a59031dc0aa6e51a764f8edab04ab85581)) -* Sanitize custom metadata ([#138](https://github.com/hyperium/tonic/issues/138)) ([f9502df](https://github.com/hyperium/tonic/commit/f9502dfd7ef306fff86c83b711bc96623555ef5c)) -* **transport:** Update builders to move self ([#132](https://github.com/hyperium/tonic/issues/132)) ([85ef18f](https://github.com/hyperium/tonic/commit/85ef18f8b7f91047ca5bcfe5fc90e3c510c7936a)) - - -### Features - -* **transport:** Add `remote_addr` to `Request` on the server si… ([#186](https://github.com/hyperium/tonic/issues/186)) ([3eb76ab](https://github.com/hyperium/tonic/commit/3eb76abf9fdce5f903de1a7f05b8afc8694fa0ce)) -* **transport:** Add server graceful shutdown ([#169](https://github.com/hyperium/tonic/issues/169)) ([393a57e](https://github.com/hyperium/tonic/commit/393a57eadebb8e2e6d3633f70141edba647b5f65)) -* **transport:** Add system root anchors for TLS ([#114](https://github.com/hyperium/tonic/issues/114)) ([ac0e333](https://github.com/hyperium/tonic/commit/ac0e333b39f60f9c304d7798a49e07e9f08a16d4)), closes [#101](https://github.com/hyperium/tonic/issues/101) -* **transport:** Add tracing support to server ([#175](https://github.com/hyperium/tonic/issues/175)) ([f46a454](https://github.com/hyperium/tonic/commit/f46a45401d42f6c8b6ab449f7462735a9aea0bfc)) -* **transport:** Allow custom IO and UDS example ([#184](https://github.com/hyperium/tonic/issues/184)) ([b90c340](https://github.com/hyperium/tonic/commit/b90c3408001f762a32409f7e2cf688ebae39d89e)), closes [#136](https://github.com/hyperium/tonic/issues/136) -* expose tcp_nodelay for clients and servers ([#145](https://github.com/hyperium/tonic/issues/145)) ([0eb9991](https://github.com/hyperium/tonic/commit/0eb9991b9fcd4a688904788966d1e5ab74918571)) -* **transport:** Enable TCP_NODELAY. ([#120](https://github.com/hyperium/tonic/issues/120)) ([0299509](https://github.com/hyperium/tonic/commit/029950904a5e1398bb508446b660c1863e9f631c)) -* **transport:** Expose tcp keepalive to clients & servers ([#151](https://github.com/hyperium/tonic/issues/151)) ([caccfad](https://github.com/hyperium/tonic/commit/caccfad7e7b03d42aa1679c00a270c92a621bb0f)) -* Add `Status` constructors ([#137](https://github.com/hyperium/tonic/issues/137)) ([997241c](https://github.com/hyperium/tonic/commit/997241c43fdb390caad19a41dc6bf67724de521a)) - - -### BREAKING CHANGES - -* **build:** Build will now generate each service client and server into their own modules. -* **transport:** Remove support for OpenSSL within the transport. - - - -# [0.1.0-alpha.5](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.4...v0.1.0-alpha.5) (2019-10-31) - - -### Bug Fixes - -* **build:** Fix missing argument in generate_connect ([#95](https://github.com/hyperium/tonic/issues/95)) ([eea3c0f](https://github.com/hyperium/tonic/commit/eea3c0f99ac292efb7b8d4956fa014108af871ac)) -* **codec:** Enforce encoders/decoders are `Sync` ([#84](https://github.com/hyperium/tonic/issues/84)) ([3ce61d9](https://github.com/hyperium/tonic/commit/3ce61d9860528dd4a13f719774d5c649198fb55c)), closes [#81](https://github.com/hyperium/tonic/issues/81) -* **codec:** Remove custom content-type ([#104](https://github.com/hyperium/tonic/issues/104)) ([a17049f](https://github.com/hyperium/tonic/commit/a17049f1f72c9655a72fef8021072d56b3f4e543)) - - -### Features - -* **transport:** Add service multiplexing/routing ([#99](https://github.com/hyperium/tonic/issues/99)) ([5b4f468](https://github.com/hyperium/tonic/commit/5b4f4689a253ccca34f34bb5329b420efb9159c1)), closes [#29](https://github.com/hyperium/tonic/issues/29) -* **transport:** Change channel connect to be async ([#107](https://github.com/hyperium/tonic/issues/107)) ([5c2f4db](https://github.com/hyperium/tonic/commit/5c2f4dba322b28e8132b21acfa184309de791d12)) -* Add `IntoRequest` and `IntoStreamingRequest` traits ([#66](https://github.com/hyperium/tonic/issues/66)) ([4bb087b](https://github.com/hyperium/tonic/commit/4bb087b5ff19636a20e10a669ba3b46f99c84358)) - - -### BREAKING CHANGES - -* **transport:** `Endpoint::channel` was removed in favor of -an async `Endpoint::connect`. - - - -# [0.1.0-alpha.4](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.3...v0.1.0-alpha.4) (2019-10-23) - - -### Bug Fixes - -* **build:** Fix service and rpc name conflict ([#92](https://github.com/hyperium/tonic/issues/92)) ([1dbde95](https://github.com/hyperium/tonic/commit/1dbde95d844378121af54f16d9f8aa9f0f7fc2f2)), closes [#89](https://github.com/hyperium/tonic/issues/89) -* **client:** Use `Stream` instead of `TrySteam` for client calls ([#61](https://github.com/hyperium/tonic/issues/61)) ([7eda823](https://github.com/hyperium/tonic/commit/7eda823c9cbe6054c39b42f8f3e7efce4698aebe)) -* **codec:** Properly decode partial DATA frames ([#83](https://github.com/hyperium/tonic/issues/83)) ([9079e0f](https://github.com/hyperium/tonic/commit/9079e0f66bc75d2ce49a5537bf66c9ff5effbdab)) -* **transport:** Rename server tls config method ([#73](https://github.com/hyperium/tonic/issues/73)) ([2a4bdb2](https://github.com/hyperium/tonic/commit/2a4bdb24f62bb3bbceb73e9551ba70512f94c187)) - - -### Features - -* **docs:** Add routeguide tutorial ([#21](https://github.com/hyperium/tonic/issues/21)) ([5d0a795](https://github.com/hyperium/tonic/commit/5d0a7955541509d2dbfdb9b689fb57cd2b842172)) -* **transport:** Add support client mTLS ([#77](https://github.com/hyperium/tonic/issues/77)) ([335a373](https://github.com/hyperium/tonic/commit/335a373a403615a9737b2e19d0089c89bcaa3c4e)) - - -### BREAKING CHANGES - -* **transport:** `rustls_client_config` for the server has been renamed to `rustls_server_config`. - - - -# [0.1.0-alpha.3](https://github.com/hyperium/tonic/compare/v0.1.0-alpha.2...v0.1.0-alpha.3) (2019-10-09) - - -### Features - -* **build:** Expose prost-build type_attributes and field_attribu… ([#60](https://github.com/hyperium/tonic/issues/60)) ([06ff619](https://github.com/hyperium/tonic/commit/06ff619944a2f44d3aea60e653b39157c392f541)) -* **transport:** Expose more granular control of TLS configuration ([#48](https://github.com/hyperium/tonic/issues/48)) ([8db3961](https://github.com/hyperium/tonic/commit/8db3961491c35955c76bf2da6a17bf8a60e3b146)) - - - -# [0.1.0-alpha.2](https://github.com/hyperium/tonic/compare/2670b349f96666c8d30d9d5d6ac2e611bb4584e2...v0.1.0-alpha.2) (2019-10-08) - - -### Bug Fixes - -* **codec:** Fix buffer decode panic on full ([#43](https://github.com/hyperium/tonic/issues/43)) ([ed3e7e9](https://github.com/hyperium/tonic/commit/ed3e7e95a5401b9b224640e17908c2182286197d)) -* **codegen:** Fix Empty protobuf type and add unimplemented ([#26](https://github.com/hyperium/tonic/issues/26)) ([2670b34](https://github.com/hyperium/tonic/commit/2670b349f96666c8d30d9d5d6ac2e611bb4584e2)) -* **codegen:** Use wellknown types from `prost-types` ([#49](https://github.com/hyperium/tonic/issues/49)) ([4e1fcec](https://github.com/hyperium/tonic/commit/4e1fcece150fb1f373b0ccbb69d302463ed6bcfd)) -* **transport:** Attempt to load RSA private keys in rustls ([#39](https://github.com/hyperium/tonic/issues/39)) ([2c5c3a2](https://github.com/hyperium/tonic/commit/2c5c3a282a1ccc9288bc0f6fb138fc123f45dd09)) -* **transport:** Avoid exit after bad TLS handshake ([#51](https://github.com/hyperium/tonic/issues/51)) ([412a0bd](https://github.com/hyperium/tonic/commit/412a0bd697b4822b94c55cb18d2373a6ed75b690)) - - -### Features - -* **codgen:** Add default implementations for the generated serve… ([#27](https://github.com/hyperium/tonic/issues/27)) ([4559613](https://github.com/hyperium/tonic/commit/4559613c37f75dde67981ee38a7f5af5947ef0be)) -* **transport:** Expose http/2 settings ([#28](https://github.com/hyperium/tonic/issues/28)) ([0218d58](https://github.com/hyperium/tonic/commit/0218d58c282d6de6f300229677c99369d3ea20ed)) - - From 15663f18c5a2a5b80039e243a61635a5aba11a3d Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:09:47 +0900 Subject: [PATCH 11/14] chore(transport): Deprecate re-exported NamedService (#1521) --- interop/src/server.rs | 2 +- tests/integration_tests/tests/extensions.rs | 3 ++- tonic/src/transport/mod.rs | 1 + tonic/src/transport/server/mod.rs | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/interop/src/server.rs b/interop/src/server.rs index f4dd71bcb..6ffb16309 100644 --- a/interop/src/server.rs +++ b/interop/src/server.rs @@ -7,7 +7,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; use std::time::Duration; use tokio_stream::StreamExt; -use tonic::{body::BoxBody, transport::NamedService, Code, Request, Response, Status}; +use tonic::{body::BoxBody, server::NamedService, Code, Request, Response, Status}; use tower::Service; pub use pb::test_service_server::TestServiceServer; diff --git a/tests/integration_tests/tests/extensions.rs b/tests/integration_tests/tests/extensions.rs index 85dde0fc7..b112f8e66 100644 --- a/tests/integration_tests/tests/extensions.rs +++ b/tests/integration_tests/tests/extensions.rs @@ -10,7 +10,8 @@ use std::{ use tokio::sync::oneshot; use tonic::{ body::BoxBody, - transport::{Endpoint, NamedService, Server}, + server::NamedService, + transport::{Endpoint, Server}, Request, Response, Status, }; use tower_service::Service; diff --git a/tonic/src/transport/mod.rs b/tonic/src/transport/mod.rs index d5f217528..3fa2bc8c9 100644 --- a/tonic/src/transport/mod.rs +++ b/tonic/src/transport/mod.rs @@ -105,6 +105,7 @@ pub use self::server::Server; pub use self::service::grpc_timeout::TimeoutExpired; pub use self::tls::Certificate; #[doc(inline)] +/// A deprecated re-export. Please use `tonic::server::NamedService` directly. pub use crate::server::NamedService; pub use axum::{body::BoxBody as AxumBoxBody, Router as AxumRouter}; pub use hyper::{Body, Uri}; diff --git a/tonic/src/transport/server/mod.rs b/tonic/src/transport/server/mod.rs index 7c9e94635..e10f11f68 100644 --- a/tonic/src/transport/server/mod.rs +++ b/tonic/src/transport/server/mod.rs @@ -12,6 +12,8 @@ mod unix; pub use super::service::Routes; pub use super::service::RoutesBuilder; +#[doc(inline)] +/// A deprecated re-export. Please use `tonic::server::NamedService` directly. pub use crate::server::NamedService; pub use conn::{Connected, TcpConnectInfo}; #[cfg(feature = "tls")] From 7cb1cd23625d7ac0e78cd750f9043c2ac62e37a5 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:10:20 +0900 Subject: [PATCH 12/14] chore(tonic): Deprecate API when they only return None (#1520) --- tonic/src/request.rs | 27 ++++++++++++++++++++++++++- tonic/src/transport/mod.rs | 1 + tonic/src/transport/tls.rs | 9 +++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/tonic/src/request.rs b/tonic/src/request.rs index e0295be59..5edd88c84 100644 --- a/tonic/src/request.rs +++ b/tonic/src/request.rs @@ -1,8 +1,11 @@ use crate::metadata::{MetadataMap, MetadataValue}; +#[cfg(feature = "transport")] +use crate::transport::server::TcpConnectInfo; #[cfg(all(feature = "transport", feature = "tls"))] use crate::transport::server::TlsConnectInfo; #[cfg(feature = "transport")] -use crate::transport::{server::TcpConnectInfo, Certificate}; +#[allow(deprecated)] +use crate::transport::Certificate; use crate::Extensions; #[cfg(feature = "transport")] use std::sync::Arc; @@ -207,6 +210,13 @@ impl Request { /// This will return `None` if the `IO` type used /// does not implement `Connected` or when using a unix domain socket. /// This currently only works on the server side. + #[cfg_attr( + not(feature = "transport"), + deprecated( + since = "0.10.3", + note = "`remote_addr` only returns `None` without transport feature. This API will require transport feature.", + ) + )] pub fn local_addr(&self) -> Option { #[cfg(feature = "transport")] { @@ -241,6 +251,13 @@ impl Request { /// This will return `None` if the `IO` type used /// does not implement `Connected` or when using a unix domain socket. /// This currently only works on the server side. + #[cfg_attr( + not(feature = "transport"), + deprecated( + since = "0.10.3", + note = "`remote_addr` only returns `None` without transport feature. This API will require transport feature.", + ) + )] pub fn remote_addr(&self) -> Option { #[cfg(feature = "transport")] { @@ -277,7 +294,15 @@ impl Request { /// `Some` on the server side of the `transport` server with /// TLS enabled connections. #[cfg(feature = "transport")] + #[cfg_attr( + all(feature = "transport", not(feature = "tls")), + deprecated( + since = "0.10.3", + note = "`peer_certs` only returns `None` without tls feature. This API will require tls feature.", + ) + )] #[cfg_attr(docsrs, doc(cfg(feature = "transport")))] + #[allow(deprecated)] pub fn peer_certs(&self) -> Option>> { #[cfg(feature = "tls")] { diff --git a/tonic/src/transport/mod.rs b/tonic/src/transport/mod.rs index 3fa2bc8c9..c676bfb92 100644 --- a/tonic/src/transport/mod.rs +++ b/tonic/src/transport/mod.rs @@ -103,6 +103,7 @@ pub use self::error::Error; pub use self::server::Server; #[doc(inline)] pub use self::service::grpc_timeout::TimeoutExpired; +#[allow(deprecated)] pub use self::tls::Certificate; #[doc(inline)] /// A deprecated re-export. Please use `tonic::server::NamedService` directly. diff --git a/tonic/src/transport/tls.rs b/tonic/src/transport/tls.rs index a4151c748..39fcc20c5 100644 --- a/tonic/src/transport/tls.rs +++ b/tonic/src/transport/tls.rs @@ -1,4 +1,11 @@ /// Represents a X509 certificate. +#[cfg_attr( + not(feature = "tls"), + deprecated( + since = "0.10.3", + note = "`Certificate` is used only by deprecated API without tls feature.", + ) +)] #[derive(Debug, Clone)] pub struct Certificate { pub(crate) pem: Vec, @@ -13,6 +20,7 @@ pub struct Identity { pub(crate) key: Vec, } +#[allow(deprecated)] impl Certificate { /// Parse a PEM encoded X509 Certificate. /// @@ -38,6 +46,7 @@ impl Certificate { } } +#[allow(deprecated)] impl AsRef<[u8]> for Certificate { fn as_ref(&self) -> &[u8] { self.pem.as_ref() From 53267a301b4a118fe8d17fb63fcaa075c2375356 Mon Sep 17 00:00:00 2001 From: tottoto Date: Thu, 16 Nov 2023 06:11:34 +0900 Subject: [PATCH 13/14] chore(codec): Remove redundant type converting (#1504) --- tonic/src/codec/decode.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tonic/src/codec/decode.rs b/tonic/src/codec/decode.rs index 38644b6e5..cb88a0649 100644 --- a/tonic/src/codec/decode.rs +++ b/tonic/src/codec/decode.rs @@ -233,15 +233,13 @@ impl StreamingInner { fn poll_data(&mut self, cx: &mut Context<'_>) -> Poll, Status>> { let chunk = match ready!(Pin::new(&mut self.body).poll_data(cx)) { Some(Ok(d)) => Some(d), - Some(Err(e)) => { - if self.direction == Direction::Request && e.code() == Code::Cancelled { + Some(Err(status)) => { + if self.direction == Direction::Request && status.code() == Code::Cancelled { return Poll::Ready(Ok(None)); } let _ = std::mem::replace(&mut self.state, State::Error); - let err: crate::Error = e.into(); - debug!("decoder inner stream error: {:?}", err); - let status = Status::from_error(err); + debug!("decoder inner stream error: {:?}", status); return Poll::Ready(Err(status)); } None => None, @@ -278,10 +276,8 @@ impl StreamingInner { self.trailers = trailer.map(MetadataMap::from_headers); } } - Err(e) => { - let err: crate::Error = e.into(); - debug!("decoder inner trailers error: {:?}", err); - let status = Status::from_error(err); + Err(status) => { + debug!("decoder inner trailers error: {:?}", status); return Poll::Ready(Err(status)); } } From e8cb48fce3b23333dbef1283b8004cae1025e552 Mon Sep 17 00:00:00 2001 From: Quentin Perez Date: Wed, 15 Nov 2023 22:15:54 +0100 Subject: [PATCH 14/14] Add zstd compression support (#1532) * Implement zstd compression * Parametrize compression tests * add tests for accepting multiple encodings * add some missing feature cfg for zstd * make as_str only crate public * make into_accept_encoding_header_value handle all combinations * make decompress implementation consistent * use zstd::stream::read::Encoder * use default compression level for zstd * fix rebase * fix CI issue --------- Co-authored-by: martinabeleda Co-authored-by: Quentin Perez Co-authored-by: Lucio Franco --- tests/compression/Cargo.toml | 3 +- tests/compression/src/bidirectional_stream.rs | 54 ++++- tests/compression/src/client_stream.rs | 108 ++++++--- tests/compression/src/compressing_request.rs | 137 ++++++++++-- tests/compression/src/compressing_response.rs | 208 ++++++++++++++---- tests/compression/src/server_stream.rs | 51 +++-- tests/compression/src/util.rs | 40 ++++ tonic/Cargo.toml | 2 + tonic/src/client/grpc.rs | 1 + tonic/src/codec/compression.rs | 80 ++++++- tonic/src/server/grpc.rs | 1 + 11 files changed, 560 insertions(+), 125 deletions(-) diff --git a/tests/compression/Cargo.toml b/tests/compression/Cargo.toml index cada8e69e..5bc87c829 100644 --- a/tests/compression/Cargo.toml +++ b/tests/compression/Cargo.toml @@ -11,11 +11,12 @@ bytes = "1" http = "0.2" http-body = "0.4" hyper = "0.14.3" +paste = "1.0.12" pin-project = "1.0" prost = "0.12" tokio = {version = "1.0", features = ["macros", "rt-multi-thread", "net"]} tokio-stream = "0.1" -tonic = {path = "../../tonic", features = ["gzip"]} +tonic = {path = "../../tonic", features = ["gzip", "zstd"]} tower = {version = "0.4", features = []} tower-http = {version = "0.4", features = ["map-response-body", "map-request-body"]} diff --git a/tests/compression/src/bidirectional_stream.rs b/tests/compression/src/bidirectional_stream.rs index d8b17c3a0..898fe5b05 100644 --- a/tests/compression/src/bidirectional_stream.rs +++ b/tests/compression/src/bidirectional_stream.rs @@ -1,20 +1,45 @@ use super::*; +use http_body::Body; use tonic::codec::CompressionEncoding; -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_enabled() { +util::parametrized_tests! { + client_enabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc::default()) - .accept_compressed(CompressionEncoding::Gzip) - .send_compressed(CompressionEncoding::Gzip); + .accept_compressed(encoding) + .send_compressed(encoding); let request_bytes_counter = Arc::new(AtomicUsize::new(0)); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); - fn assert_right_encoding(req: http::Request) -> http::Request { - assert_eq!(req.headers().get("grpc-encoding").unwrap(), "gzip"); - req + #[derive(Clone)] + pub struct AssertRightEncoding { + encoding: CompressionEncoding, + } + + #[allow(dead_code)] + impl AssertRightEncoding { + pub fn new(encoding: CompressionEncoding) -> Self { + Self { encoding } + } + + pub fn call(self, req: http::Request) -> http::Request { + let expected = match self.encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", self.encoding), + }; + assert_eq!(req.headers().get("grpc-encoding").unwrap(), expected); + + req + } } tokio::spawn({ @@ -24,7 +49,9 @@ async fn client_enabled_server_enabled() { Server::builder() .layer( ServiceBuilder::new() - .map_request(assert_right_encoding) + .map_request(move |req| { + AssertRightEncoding::new(encoding).clone().call(req) + }) .layer(measure_request_body_size_layer( request_bytes_counter.clone(), )) @@ -44,8 +71,8 @@ async fn client_enabled_server_enabled() { }); let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .send_compressed(CompressionEncoding::Gzip) - .accept_compressed(CompressionEncoding::Gzip); + .send_compressed(encoding) + .accept_compressed(encoding); let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(); let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]); @@ -56,7 +83,12 @@ async fn client_enabled_server_enabled() { .await .unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let mut stream: Streaming = res.into_inner(); diff --git a/tests/compression/src/client_stream.rs b/tests/compression/src/client_stream.rs index 9c210c574..9402c75f2 100644 --- a/tests/compression/src/client_stream.rs +++ b/tests/compression/src/client_stream.rs @@ -1,19 +1,42 @@ use super::*; -use http_body::Body as _; +use http_body::Body; use tonic::codec::CompressionEncoding; -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_enabled() { +util::parametrized_tests! { + client_enabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).accept_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding); let request_bytes_counter = Arc::new(AtomicUsize::new(0)); - fn assert_right_encoding(req: http::Request) -> http::Request { - assert_eq!(req.headers().get("grpc-encoding").unwrap(), "gzip"); - req + #[derive(Clone)] + pub struct AssertRightEncoding { + encoding: CompressionEncoding, + } + + #[allow(dead_code)] + impl AssertRightEncoding { + pub fn new(encoding: CompressionEncoding) -> Self { + Self { encoding } + } + + pub fn call(self, req: http::Request) -> http::Request { + let expected = match self.encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", self.encoding), + }; + assert_eq!(req.headers().get("grpc-encoding").unwrap(), expected); + + req + } } tokio::spawn({ @@ -22,7 +45,9 @@ async fn client_enabled_server_enabled() { Server::builder() .layer( ServiceBuilder::new() - .map_request(assert_right_encoding) + .map_request(move |req| { + AssertRightEncoding::new(encoding).clone().call(req) + }) .layer(measure_request_body_size_layer( request_bytes_counter.clone(), )) @@ -35,8 +60,8 @@ async fn client_enabled_server_enabled() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .send_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding); let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(); let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]); @@ -48,12 +73,17 @@ async fn client_enabled_server_enabled() { assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn client_disabled_server_enabled() { +util::parametrized_tests! { + client_disabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_disabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).accept_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding); let request_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -93,8 +123,14 @@ async fn client_disabled_server_enabled() { assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_disabled() { +util::parametrized_tests! { + client_enabled_server_disabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_disabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc::default()); @@ -107,8 +143,8 @@ async fn client_enabled_server_disabled() { .unwrap(); }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .send_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding); let data = [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(); let stream = tokio_stream::iter(vec![SomeData { data: data.clone() }, SomeData { data }]); @@ -117,18 +153,31 @@ async fn client_enabled_server_disabled() { let status = client.compress_input_client_stream(req).await.unwrap_err(); assert_eq!(status.code(), tonic::Code::Unimplemented); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; assert_eq!( status.message(), - "Content is compressed with `gzip` which isn't supported" + format!( + "Content is compressed with `{}` which isn't supported", + expected + ) ); } -#[tokio::test(flavor = "multi_thread")] -async fn compressing_response_from_client_stream() { +util::parametrized_tests! { + compressing_response_from_client_stream, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn compressing_response_from_client_stream(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -153,13 +202,18 @@ async fn compressing_response_from_client_stream() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let req = Request::new(Box::pin(tokio_stream::empty())); let res = client.compress_output_client_stream(req).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let bytes_sent = response_bytes_counter.load(SeqCst); assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE); } diff --git a/tests/compression/src/compressing_request.rs b/tests/compression/src/compressing_request.rs index b1c9009b8..87a02de64 100644 --- a/tests/compression/src/compressing_request.rs +++ b/tests/compression/src/compressing_request.rs @@ -1,18 +1,103 @@ use super::*; -use http_body::Body as _; +use http_body::Body; use tonic::codec::CompressionEncoding; -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_enabled() { +util::parametrized_tests! { + client_enabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).accept_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding); + + let request_bytes_counter = Arc::new(AtomicUsize::new(0)); + + #[derive(Clone)] + pub struct AssertRightEncoding { + encoding: CompressionEncoding, + } + + #[allow(dead_code)] + impl AssertRightEncoding { + pub fn new(encoding: CompressionEncoding) -> Self { + Self { encoding } + } + + pub fn call(self, req: http::Request) -> http::Request { + let expected = match self.encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", self.encoding), + }; + assert_eq!(req.headers().get("grpc-encoding").unwrap(), expected); + + req + } + } + + tokio::spawn({ + let request_bytes_counter = request_bytes_counter.clone(); + async move { + Server::builder() + .layer( + ServiceBuilder::new() + .layer( + ServiceBuilder::new() + .map_request(move |req| { + AssertRightEncoding::new(encoding).clone().call(req) + }) + .layer(measure_request_body_size_layer(request_bytes_counter)) + .into_inner(), + ) + .into_inner(), + ) + .add_service(svc) + .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .await + .unwrap(); + } + }); + + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding); + + for _ in 0..3 { + client + .compress_input_unary(SomeData { + data: [0_u8; UNCOMPRESSED_MIN_BODY_SIZE].to_vec(), + }) + .await + .unwrap(); + let bytes_sent = request_bytes_counter.load(SeqCst); + assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE); + } +} + +util::parametrized_tests! { + client_enabled_server_enabled_multi_encoding, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled_multi_encoding(encoding: CompressionEncoding) { + let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); + + let svc = test_server::TestServer::new(Svc::default()) + .accept_compressed(CompressionEncoding::Gzip) + .accept_compressed(CompressionEncoding::Zstd); let request_bytes_counter = Arc::new(AtomicUsize::new(0)); fn assert_right_encoding(req: http::Request) -> http::Request { - assert_eq!(req.headers().get("grpc-encoding").unwrap(), "gzip"); + let supported_encodings = ["gzip", "zstd"]; + let req_encoding = req.headers().get("grpc-encoding").unwrap(); + assert!(supported_encodings.iter().any(|e| e == req_encoding)); + req } @@ -37,8 +122,8 @@ async fn client_enabled_server_enabled() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .send_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding); for _ in 0..3 { client @@ -52,8 +137,14 @@ async fn client_enabled_server_enabled() { } } -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_disabled() { +parametrized_tests! { + client_enabled_server_disabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_disabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc::default()); @@ -66,8 +157,8 @@ async fn client_enabled_server_disabled() { .unwrap(); }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .send_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).send_compressed(encoding); let status = client .compress_input_unary(SomeData { @@ -77,9 +168,17 @@ async fn client_enabled_server_disabled() { .unwrap_err(); assert_eq!(status.code(), tonic::Code::Unimplemented); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; assert_eq!( status.message(), - "Content is compressed with `gzip` which isn't supported" + format!( + "Content is compressed with `{}` which isn't supported", + expected + ) ); assert_eq!( @@ -87,13 +186,17 @@ async fn client_enabled_server_disabled() { "identity" ); } +parametrized_tests! { + client_mark_compressed_without_header_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} -#[tokio::test(flavor = "multi_thread")] -async fn client_mark_compressed_without_header_server_enabled() { +#[allow(dead_code)] +async fn client_mark_compressed_without_header_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).accept_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).accept_compressed(encoding); tokio::spawn({ async move { diff --git a/tests/compression/src/compressing_response.rs b/tests/compression/src/compressing_response.rs index a9b73e6d9..86b0fa6cf 100644 --- a/tests/compression/src/compressing_response.rs +++ b/tests/compression/src/compressing_response.rs @@ -1,12 +1,21 @@ use super::*; use tonic::codec::CompressionEncoding; -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_enabled() { +util::parametrized_tests! { + client_enabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); #[derive(Clone, Copy)] - struct AssertCorrectAcceptEncoding(S); + struct AssertCorrectAcceptEncoding { + service: S, + encoding: CompressionEncoding, + } impl Service> for AssertCorrectAcceptEncoding where @@ -20,20 +29,28 @@ async fn client_enabled_server_enabled() { &mut self, cx: &mut std::task::Context<'_>, ) -> std::task::Poll> { - self.0.poll_ready(cx) + self.service.poll_ready(cx) } fn call(&mut self, req: http::Request) -> Self::Future { + let expected = match self.encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", self.encoding), + }; assert_eq!( - req.headers().get("grpc-accept-encoding").unwrap(), - "gzip,identity" + req.headers() + .get("grpc-accept-encoding") + .unwrap() + .to_str() + .unwrap(), + format!("{},identity", expected) ); - self.0.call(req) + self.service.call(req) } } - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -43,7 +60,10 @@ async fn client_enabled_server_enabled() { Server::builder() .layer( ServiceBuilder::new() - .layer(layer_fn(AssertCorrectAcceptEncoding)) + .layer(layer_fn(|service| AssertCorrectAcceptEncoding { + service, + encoding, + })) .layer(MapResponseBodyLayer::new(move |body| { util::CountBytesBody { inner: body, @@ -59,19 +79,72 @@ async fn client_enabled_server_enabled() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); + + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; for _ in 0..3 { let res = client.compress_output_unary(()).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let bytes_sent = response_bytes_counter.load(SeqCst); assert!(bytes_sent < UNCOMPRESSED_MIN_BODY_SIZE); } } +util::parametrized_tests! { + client_enabled_server_disabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_disabled(encoding: CompressionEncoding) { + let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); + + let svc = test_server::TestServer::new(Svc::default()); + + let response_bytes_counter = Arc::new(AtomicUsize::new(0)); + + tokio::spawn({ + let response_bytes_counter = response_bytes_counter.clone(); + async move { + Server::builder() + // no compression enable on the server so responses should not be compressed + .layer( + ServiceBuilder::new() + .layer(MapResponseBodyLayer::new(move |body| { + util::CountBytesBody { + inner: body, + counter: response_bytes_counter.clone(), + } + })) + .into_inner(), + ) + .add_service(svc) + .serve_with_incoming(tokio_stream::iter(vec![Ok::<_, std::io::Error>(server)])) + .await + .unwrap(); + } + }); + + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); + + let res = client.compress_output_unary(()).await.unwrap(); + + assert!(res.metadata().get("grpc-encoding").is_none()); + + let bytes_sent = response_bytes_counter.load(SeqCst); + assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); +} + #[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_disabled() { +async fn client_enabled_server_disabled_multi_encoding() { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc::default()); @@ -101,7 +174,8 @@ async fn client_enabled_server_disabled() { }); let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + .accept_compressed(CompressionEncoding::Gzip) + .accept_compressed(CompressionEncoding::Zstd); let res = client.compress_output_unary(()).await.unwrap(); @@ -111,8 +185,14 @@ async fn client_enabled_server_disabled() { assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn client_disabled() { +util::parametrized_tests! { + client_disabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_disabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); #[derive(Clone, Copy)] @@ -139,8 +219,7 @@ async fn client_disabled() { } } - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -176,12 +255,17 @@ async fn client_disabled() { assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn server_replying_with_unsupported_encoding() { +util::parametrized_tests! { + server_replying_with_unsupported_encoding, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn server_replying_with_unsupported_encoding(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); fn add_weird_content_encoding(mut response: http::Response) -> http::Response { response @@ -203,8 +287,8 @@ async fn server_replying_with_unsupported_encoding() { .unwrap(); }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let status: Status = client.compress_output_unary(()).await.unwrap_err(); assert_eq!(status.code(), tonic::Code::Unimplemented); @@ -214,14 +298,20 @@ async fn server_replying_with_unsupported_encoding() { ); } -#[tokio::test(flavor = "multi_thread")] -async fn disabling_compression_on_single_response() { +util::parametrized_tests! { + disabling_compression_on_single_response, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn disabling_compression_on_single_response(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc { disable_compressing_on_response: true, }) - .send_compressed(CompressionEncoding::Gzip); + .send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -246,23 +336,38 @@ async fn disabling_compression_on_single_response() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let res = client.compress_output_unary(()).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); + let bytes_sent = response_bytes_counter.load(SeqCst); assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn disabling_compression_on_response_but_keeping_compression_on_stream() { +util::parametrized_tests! { + disabling_compression_on_response_but_keeping_compression_on_stream, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn disabling_compression_on_response_but_keeping_compression_on_stream( + encoding: CompressionEncoding, +) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc { disable_compressing_on_response: true, }) - .send_compressed(CompressionEncoding::Gzip); + .send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -287,12 +392,17 @@ async fn disabling_compression_on_response_but_keeping_compression_on_stream() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let res = client.compress_output_server_stream(()).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let mut stream: Streaming = res.into_inner(); @@ -311,14 +421,20 @@ async fn disabling_compression_on_response_but_keeping_compression_on_stream() { assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn disabling_compression_on_response_from_client_stream() { +util::parametrized_tests! { + disabling_compression_on_response_from_client_stream, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn disabling_compression_on_response_from_client_stream(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc { disable_compressing_on_response: true, }) - .send_compressed(CompressionEncoding::Gzip); + .send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -343,13 +459,19 @@ async fn disabling_compression_on_response_from_client_stream() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let req = Request::new(Box::pin(tokio_stream::empty())); let res = client.compress_output_client_stream(req).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let bytes_sent = response_bytes_counter.load(SeqCst); assert!(bytes_sent > UNCOMPRESSED_MIN_BODY_SIZE); } diff --git a/tests/compression/src/server_stream.rs b/tests/compression/src/server_stream.rs index 3a7fe7104..9d0e4f390 100644 --- a/tests/compression/src/server_stream.rs +++ b/tests/compression/src/server_stream.rs @@ -2,12 +2,17 @@ use super::*; use tonic::codec::CompressionEncoding; use tonic::Streaming; -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_enabled() { +util::parametrized_tests! { + client_enabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -32,12 +37,17 @@ async fn client_enabled_server_enabled() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let res = client.compress_output_server_stream(()).await.unwrap(); - assert_eq!(res.metadata().get("grpc-encoding").unwrap(), "gzip"); + let expected = match encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", encoding), + }; + assert_eq!(res.metadata().get("grpc-encoding").unwrap(), expected); let mut stream: Streaming = res.into_inner(); @@ -56,12 +66,17 @@ async fn client_enabled_server_enabled() { assert!(response_bytes_counter.load(SeqCst) < UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn client_disabled_server_enabled() { +util::parametrized_tests! { + client_disabled_server_enabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_disabled_server_enabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); - let svc = - test_server::TestServer::new(Svc::default()).send_compressed(CompressionEncoding::Gzip); + let svc = test_server::TestServer::new(Svc::default()).send_compressed(encoding); let response_bytes_counter = Arc::new(AtomicUsize::new(0)); @@ -102,8 +117,14 @@ async fn client_disabled_server_enabled() { assert!(response_bytes_counter.load(SeqCst) > UNCOMPRESSED_MIN_BODY_SIZE); } -#[tokio::test(flavor = "multi_thread")] -async fn client_enabled_server_disabled() { +util::parametrized_tests! { + client_enabled_server_disabled, + zstd: CompressionEncoding::Zstd, + gzip: CompressionEncoding::Gzip, +} + +#[allow(dead_code)] +async fn client_enabled_server_disabled(encoding: CompressionEncoding) { let (client, server) = tokio::io::duplex(UNCOMPRESSED_MIN_BODY_SIZE * 10); let svc = test_server::TestServer::new(Svc::default()); @@ -131,8 +152,8 @@ async fn client_enabled_server_disabled() { } }); - let mut client = test_client::TestClient::new(mock_io_channel(client).await) - .accept_compressed(CompressionEncoding::Gzip); + let mut client = + test_client::TestClient::new(mock_io_channel(client).await).accept_compressed(encoding); let res = client.compress_output_server_stream(()).await.unwrap(); diff --git a/tests/compression/src/util.rs b/tests/compression/src/util.rs index a8d652adc..28fa5d96a 100644 --- a/tests/compression/src/util.rs +++ b/tests/compression/src/util.rs @@ -11,9 +11,26 @@ use std::{ task::{ready, Context, Poll}, }; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; +use tonic::codec::CompressionEncoding; use tonic::transport::{server::Connected, Channel}; use tower_http::map_request_body::MapRequestBodyLayer; +macro_rules! parametrized_tests { + ($fn_name:ident, $($test_name:ident: $input:expr),+ $(,)?) => { + paste::paste! { + $( + #[tokio::test(flavor = "multi_thread")] + async fn [<$fn_name _ $test_name>]() { + let input = $input; + $fn_name(input).await; + } + )+ + } + } +} + +pub(crate) use parametrized_tests; + /// A body that tracks how many bytes passes through it #[pin_project] pub struct CountBytesBody { @@ -99,3 +116,26 @@ pub async fn mock_io_channel(client: tokio::io::DuplexStream) -> Channel { .await .unwrap() } + +#[derive(Clone)] +pub struct AssertRightEncoding { + encoding: CompressionEncoding, +} + +#[allow(dead_code)] +impl AssertRightEncoding { + pub fn new(encoding: CompressionEncoding) -> Self { + Self { encoding } + } + + pub fn call(self, req: http::Request) -> http::Request { + let expected = match self.encoding { + CompressionEncoding::Gzip => "gzip", + CompressionEncoding::Zstd => "zstd", + _ => panic!("unexpected encoding {:?}", self.encoding), + }; + assert_eq!(req.headers().get("grpc-encoding").unwrap(), expected); + + req + } +} diff --git a/tonic/Cargo.toml b/tonic/Cargo.toml index 0d3442702..013cc6e72 100644 --- a/tonic/Cargo.toml +++ b/tonic/Cargo.toml @@ -25,6 +25,7 @@ version = "0.10.2" [features] codegen = ["dep:async-trait"] gzip = ["dep:flate2"] +zstd = ["dep:zstd"] default = ["transport", "codegen", "prost"] prost = ["dep:prost"] tls = ["dep:rustls-pemfile", "transport", "dep:tokio-rustls", "dep:rustls", "tokio/rt", "tokio/macros"] @@ -85,6 +86,7 @@ webpki-roots = { version = "0.25.0", optional = true } # compression flate2 = {version = "1.0", optional = true} +zstd = { version = "0.12.3", optional = true } [dev-dependencies] bencher = "0.1.5" diff --git a/tonic/src/client/grpc.rs b/tonic/src/client/grpc.rs index 0d52fb42f..09ef3e934 100644 --- a/tonic/src/client/grpc.rs +++ b/tonic/src/client/grpc.rs @@ -399,6 +399,7 @@ impl GrpcConfig { .headers_mut() .insert(CONTENT_TYPE, HeaderValue::from_static("application/grpc")); + #[cfg(any(feature = "gzip", feature = "zstd"))] if let Some(encoding) = self.send_compression_encodings { request.headers_mut().insert( crate::codec::compression::ENCODING_HEADER, diff --git a/tonic/src/codec/compression.rs b/tonic/src/codec/compression.rs index 7063bd865..70d758415 100644 --- a/tonic/src/codec/compression.rs +++ b/tonic/src/codec/compression.rs @@ -4,6 +4,8 @@ use bytes::{Buf, BytesMut}; #[cfg(feature = "gzip")] use flate2::read::{GzDecoder, GzEncoder}; use std::fmt; +#[cfg(feature = "zstd")] +use zstd::stream::read::{Decoder, Encoder}; pub(crate) const ENCODING_HEADER: &str = "grpc-encoding"; pub(crate) const ACCEPT_ENCODING_HEADER: &str = "grpc-accept-encoding"; @@ -13,6 +15,8 @@ pub(crate) const ACCEPT_ENCODING_HEADER: &str = "grpc-accept-encoding"; pub struct EnabledCompressionEncodings { #[cfg(feature = "gzip")] pub(crate) gzip: bool, + #[cfg(feature = "zstd")] + pub(crate) zstd: bool, } impl EnabledCompressionEncodings { @@ -21,6 +25,8 @@ impl EnabledCompressionEncodings { match encoding { #[cfg(feature = "gzip")] CompressionEncoding::Gzip => self.gzip, + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => self.zstd, } } @@ -29,14 +35,17 @@ impl EnabledCompressionEncodings { match encoding { #[cfg(feature = "gzip")] CompressionEncoding::Gzip => self.gzip = true, + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => self.zstd = true, } } pub(crate) fn into_accept_encoding_header_value(self) -> Option { - if self.is_gzip_enabled() { - Some(http::HeaderValue::from_static("gzip,identity")) - } else { - None + match (self.is_gzip_enabled(), self.is_zstd_enabled()) { + (true, false) => Some(http::HeaderValue::from_static("gzip,identity")), + (false, true) => Some(http::HeaderValue::from_static("zstd,identity")), + (true, true) => Some(http::HeaderValue::from_static("gzip,zstd,identity")), + (false, false) => None, } } @@ -49,6 +58,16 @@ impl EnabledCompressionEncodings { const fn is_gzip_enabled(&self) -> bool { false } + + #[cfg(feature = "zstd")] + const fn is_zstd_enabled(&self) -> bool { + self.zstd + } + + #[cfg(not(feature = "zstd"))] + const fn is_zstd_enabled(&self) -> bool { + false + } } /// The compression encodings Tonic supports. @@ -59,6 +78,10 @@ pub enum CompressionEncoding { #[cfg(feature = "gzip")] #[cfg_attr(docsrs, doc(cfg(feature = "gzip")))] Gzip, + #[allow(missing_docs)] + #[cfg(feature = "zstd")] + #[cfg_attr(docsrs, doc(cfg(feature = "zstd")))] + Zstd, } impl CompressionEncoding { @@ -67,7 +90,7 @@ impl CompressionEncoding { map: &http::HeaderMap, enabled_encodings: EnabledCompressionEncodings, ) -> Option { - if !enabled_encodings.is_gzip_enabled() { + if !enabled_encodings.is_gzip_enabled() && !enabled_encodings.is_zstd_enabled() { return None; } @@ -77,6 +100,8 @@ impl CompressionEncoding { split_by_comma(header_value_str).find_map(|value| match value { #[cfg(feature = "gzip")] "gzip" => Some(CompressionEncoding::Gzip), + #[cfg(feature = "zstd")] + "zstd" => Some(CompressionEncoding::Zstd), _ => None, }) } @@ -103,6 +128,10 @@ impl CompressionEncoding { "gzip" if enabled_encodings.is_enabled(CompressionEncoding::Gzip) => { Ok(Some(CompressionEncoding::Gzip)) } + #[cfg(feature = "zstd")] + "zstd" if enabled_encodings.is_enabled(CompressionEncoding::Zstd) => { + Ok(Some(CompressionEncoding::Zstd)) + } "identity" => Ok(None), other => { let mut status = Status::unimplemented(format!( @@ -123,17 +152,28 @@ impl CompressionEncoding { } } - pub(crate) fn into_header_value(self) -> http::HeaderValue { + #[allow(missing_docs)] + #[cfg(any(feature = "gzip", feature = "zstd"))] + pub(crate) fn as_str(&self) -> &'static str { match self { #[cfg(feature = "gzip")] - CompressionEncoding::Gzip => http::HeaderValue::from_static("gzip"), + CompressionEncoding::Gzip => "gzip", + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => "zstd", } } + #[cfg(any(feature = "gzip", feature = "zstd"))] + pub(crate) fn into_header_value(self) -> http::HeaderValue { + http::HeaderValue::from_static(self.as_str()) + } + pub(crate) fn encodings() -> &'static [Self] { &[ #[cfg(feature = "gzip")] CompressionEncoding::Gzip, + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd, ] } } @@ -144,6 +184,8 @@ impl fmt::Display for CompressionEncoding { match *self { #[cfg(feature = "gzip")] CompressionEncoding::Gzip => write!(f, "gzip"), + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => write!(f, "zstd"), } } } @@ -163,6 +205,9 @@ pub(crate) fn compress( let capacity = ((len / BUFFER_SIZE) + 1) * BUFFER_SIZE; out_buf.reserve(capacity); + #[cfg(any(feature = "gzip", feature = "zstd"))] + let mut out_writer = bytes::BufMut::writer(out_buf); + match encoding { #[cfg(feature = "gzip")] CompressionEncoding::Gzip => { @@ -171,10 +216,17 @@ pub(crate) fn compress( // FIXME: support customizing the compression level flate2::Compression::new(6), ); - let mut out_writer = bytes::BufMut::writer(out_buf); - std::io::copy(&mut gzip_encoder, &mut out_writer)?; } + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => { + let mut zstd_encoder = Encoder::new( + &decompressed_buf[0..len], + // FIXME: support customizing the compression level + zstd::DEFAULT_COMPRESSION_LEVEL, + )?; + std::io::copy(&mut zstd_encoder, &mut out_writer)?; + } } decompressed_buf.advance(len); @@ -194,14 +246,20 @@ pub(crate) fn decompress( let capacity = ((estimate_decompressed_len / BUFFER_SIZE) + 1) * BUFFER_SIZE; out_buf.reserve(capacity); + #[cfg(any(feature = "gzip", feature = "zstd"))] + let mut out_writer = bytes::BufMut::writer(out_buf); + match encoding { #[cfg(feature = "gzip")] CompressionEncoding::Gzip => { let mut gzip_decoder = GzDecoder::new(&compressed_buf[0..len]); - let mut out_writer = bytes::BufMut::writer(out_buf); - std::io::copy(&mut gzip_decoder, &mut out_writer)?; } + #[cfg(feature = "zstd")] + CompressionEncoding::Zstd => { + let mut zstd_decoder = Decoder::new(&compressed_buf[0..len])?; + std::io::copy(&mut zstd_decoder, &mut out_writer)?; + } } compressed_buf.advance(len); diff --git a/tonic/src/server/grpc.rs b/tonic/src/server/grpc.rs index d8ec2a89c..ec94b97fb 100644 --- a/tonic/src/server/grpc.rs +++ b/tonic/src/server/grpc.rs @@ -443,6 +443,7 @@ where http::header::HeaderValue::from_static("application/grpc"), ); + #[cfg(any(feature = "gzip", feature = "zstd"))] if let Some(encoding) = accept_encoding { // Set the content encoding parts.headers.insert(