Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tonic-build/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub fn generate<T: Service>(

pub fn with_interceptor<F>(inner: T, interceptor: F) -> #service_ident<InterceptedService<T, F>>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
F: tonic::service::Interceptor,
T: tonic::codegen::Service<
http::Request<tonic::body::BoxBody>,
Response = http::Response<<T as tonic::client::GrpcService<tonic::body::BoxBody>>::ResponseBody>
Expand Down
2 changes: 1 addition & 1 deletion tonic-build/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub fn generate<T: Service>(

pub fn with_interceptor<F>(inner: T, interceptor: F) -> InterceptedService<Self, F>
where
F: FnMut(tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status>,
F: tonic::service::Interceptor,
{
InterceptedService::new(Self::new(inner), interceptor)
}
Expand Down
4 changes: 2 additions & 2 deletions tonic/src/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use std::fmt;

/// A type map of protocol extensions.
///
/// `Extensions` can be used by [`interceptor_fn`] and [`Request`] to store extra data derived from
/// `Extensions` can be used by [`Interceptor`] and [`Request`] to store extra data derived from
/// the underlying protocol.
///
/// [`interceptor_fn`]: crate::service::interceptor_fn
/// [`Interceptor`]: crate::service::Interceptor
/// [`Request`]: crate::Request
pub struct Extensions {
inner: http::Extensions,
Expand Down
44 changes: 34 additions & 10 deletions tonic/src/service/interceptor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! gRPC interceptors which are a kind of middleware.
//!
//! See [`interceptor_fn`] for more details.
//! See [`Interceptor`] for more details.

use crate::{request::SanitizeHeaders, Status};
use pin_project::pin_project;
Expand All @@ -13,12 +13,15 @@ use std::{
use tower_layer::Layer;
use tower_service::Service;

/// Create a new interceptor from a function.
/// A gRPC incerceptor.
///
/// gRPC interceptors are similar to middleware but have less flexibility. An interceptor allows
/// you to do two main things, one is to add/remove/check items in the `MetadataMap` of each
/// request. Two, cancel a request with a `Status`.
///
/// Any function that satisfies the bound `FnMut(Request<()>) -> Result<Request<()>, Status>` can be
/// used as an `Interceptor`.
///
/// An interceptor can be used on both the server and client side through the `tonic-build` crate's
/// generated structs.
///
Expand All @@ -35,24 +38,42 @@ use tower_service::Service;
/// [tower]: https://crates.io/crates/tower
/// [example]: https://github.com/hyperium/tonic/tree/master/examples/src/interceptor
/// [tower-example]: https://github.com/hyperium/tonic/tree/master/examples/src/tower
pub fn interceptor_fn<F>(f: F) -> InterceptorFn<F>
pub trait Interceptor {
/// Intercept a request before it is sent, optionally cancelling it.
fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status>;
}

impl<F> Interceptor for F
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
{
fn call(&mut self, request: crate::Request<()>) -> Result<crate::Request<()>, Status> {
self(request)
}
}

/// Create a new interceptor layer.
///
/// See [`Interceptor`] for more details.
pub fn interceptor_fn<F>(f: F) -> InterceptorFn<F>
where
F: Interceptor,
{
InterceptorFn { f }
}

/// An interceptor created from a function.
/// A gRPC interceptor that can be used as a [`Layer`],
/// created by calling [`interceptor_fn`].
///
/// See [`interceptor_fn`] for more details.
/// See [`Interceptor`] for more details.
#[derive(Debug, Clone, Copy)]
pub struct InterceptorFn<F> {
f: F,
}

impl<S, F> Layer<S> for InterceptorFn<F>
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status> + Clone,
F: Interceptor + Clone,
{
type Service = InterceptedService<S, F>;

Expand All @@ -63,7 +84,7 @@ where

/// A service wrapped in an interceptor middleware.
///
/// See [`interceptor_fn`] for more details.
/// See [`Interceptor`] for more details.
#[derive(Clone, Copy)]
pub struct InterceptedService<S, F> {
inner: S,
Expand All @@ -75,7 +96,7 @@ impl<S, F> InterceptedService<S, F> {
/// function `F`.
pub fn new(service: S, f: F) -> Self
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
F: Interceptor,
{
Self { inner: service, f }
}
Expand All @@ -95,7 +116,7 @@ where

impl<S, F, ReqBody, ResBody> Service<http::Request<ReqBody>> for InterceptedService<S, F>
where
F: FnMut(crate::Request<()>) -> Result<crate::Request<()>, Status>,
F: Interceptor,
S: Service<http::Request<ReqBody>, Response = http::Response<ResBody>>,
S::Error: Into<crate::Error>,
{
Expand All @@ -113,7 +134,10 @@ where
let req = crate::Request::from_http(req);
let (metadata, extensions, msg) = req.into_parts();

match (self.f)(crate::Request::from_parts(metadata, extensions, ())) {
match self
.f
.call(crate::Request::from_parts(metadata, extensions, ()))
{
Ok(req) => {
let (metadata, extensions, _) = req.into_parts();
let req = crate::Request::from_parts(metadata, extensions, msg);
Expand Down
2 changes: 1 addition & 1 deletion tonic/src/service/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
pub mod interceptor;

#[doc(inline)]
pub use self::interceptor::interceptor_fn;
pub use self::interceptor::{interceptor_fn, Interceptor};
2 changes: 1 addition & 1 deletion tonic/src/transport/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ impl<L> Server<L> {
/// [`Layer`]: tower::layer::Layer
/// [eco]: https://github.com/tower-rs
/// [`ServiceBuilder`]: tower::ServiceBuilder
/// [interceptors]: crate::service::interceptor_fn
/// [interceptors]: crate::service::Interceptor
pub fn layer<NewLayer>(self, new_layer: NewLayer) -> Server<NewLayer> {
Server {
layer: new_layer,
Expand Down