Skip to content

Commit 2c3f8f3

Browse files
authored
Add ServiceExt trait (#563)
1 parent 001be27 commit 2c3f8f3

File tree

2 files changed

+360
-1
lines changed

2 files changed

+360
-1
lines changed

tower-http/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,10 +334,12 @@ pub mod services;
334334

335335
#[cfg(feature = "util")]
336336
mod builder;
337+
#[cfg(feature = "util")]
338+
mod service_ext;
337339

338340
#[cfg(feature = "util")]
339341
#[doc(inline)]
340-
pub use self::builder::ServiceBuilderExt;
342+
pub use self::{builder::ServiceBuilderExt, service_ext::ServiceExt};
341343

342344
#[cfg(feature = "validate-request")]
343345
pub mod validate_request;

tower-http/src/service_ext.rs

Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
#[allow(unused_imports)]
2+
use http::header::HeaderName;
3+
4+
mod sealed {
5+
#[allow(unreachable_pub, unused)]
6+
pub trait Sealed<R> {}
7+
}
8+
9+
/// Extension trait that adds methods to any [`Service`] for adding middleware from
10+
/// tower-http.
11+
///
12+
/// [`Service`]: tower::Service
13+
#[cfg(feature = "util")]
14+
// ^ work around rustdoc not inferring doc(cfg)s for cfg's from surrounding scopes
15+
pub trait ServiceExt<R>: sealed::Sealed<R> + tower::Service<R> + Sized {
16+
/// Propagate a header from the request to the response.
17+
///
18+
/// See [`tower_http::propagate_header`] for more details.
19+
///
20+
/// [`tower_http::propagate_header`]: crate::propagate_header
21+
#[cfg(feature = "propagate-header")]
22+
fn propagate_header(
23+
self,
24+
header: HeaderName,
25+
) -> crate::propagate_header::PropagateHeader<Self> {
26+
crate::propagate_header::PropagateHeader::new(self, header)
27+
}
28+
29+
/// Add some shareable value to [request extensions].
30+
///
31+
/// See [`tower_http::add_extension`] for more details.
32+
///
33+
/// [`tower_http::add_extension`]: crate::add_extension
34+
/// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
35+
#[cfg(feature = "add-extension")]
36+
fn add_extension<T>(self, value: T) -> crate::add_extension::AddExtension<Self, T> {
37+
crate::add_extension::AddExtension::new(self, value)
38+
}
39+
40+
/// Apply a transformation to the request body.
41+
///
42+
/// See [`tower_http::map_request_body`] for more details.
43+
///
44+
/// [`tower_http::map_request_body`]: crate::map_request_body
45+
#[cfg(feature = "map-request-body")]
46+
fn map_request_body<F>(self, f: F) -> crate::map_request_body::MapRequestBody<Self, F> {
47+
crate::map_request_body::MapRequestBody::new(self, f)
48+
}
49+
50+
/// Apply a transformation to the response body.
51+
///
52+
/// See [`tower_http::map_response_body`] for more details.
53+
///
54+
/// [`tower_http::map_response_body`]: crate::map_response_body
55+
#[cfg(feature = "map-response-body")]
56+
fn map_response_body<F>(self, f: F) -> crate::map_response_body::MapResponseBody<Self, F> {
57+
crate::map_response_body::MapResponseBody::new(self, f)
58+
}
59+
60+
/// Compresses response bodies.
61+
///
62+
/// See [`tower_http::compression`] for more details.
63+
///
64+
/// [`tower_http::compression`]: crate::compression
65+
#[cfg(any(
66+
feature = "compression-br",
67+
feature = "compression-deflate",
68+
feature = "compression-gzip",
69+
feature = "compression-zstd",
70+
))]
71+
fn compression(self) -> crate::compression::Compression<Self> {
72+
crate::compression::Compression::new(self)
73+
}
74+
75+
/// Decompress response bodies.
76+
///
77+
/// See [`tower_http::decompression`] for more details.
78+
///
79+
/// [`tower_http::decompression`]: crate::decompression
80+
#[cfg(any(
81+
feature = "decompression-br",
82+
feature = "decompression-deflate",
83+
feature = "decompression-gzip",
84+
feature = "decompression-zstd",
85+
))]
86+
fn decompression(self) -> crate::decompression::Decompression<Self> {
87+
crate::decompression::Decompression::new(self)
88+
}
89+
90+
/// High level tracing that classifies responses using HTTP status codes.
91+
///
92+
/// This method does not support customizing the output, to do that use [`TraceLayer`]
93+
/// instead.
94+
///
95+
/// See [`tower_http::trace`] for more details.
96+
///
97+
/// [`tower_http::trace`]: crate::trace
98+
/// [`TraceLayer`]: crate::trace::TraceLayer
99+
#[cfg(feature = "trace")]
100+
fn trace_for_http(self) -> crate::trace::Trace<Self, crate::trace::HttpMakeClassifier> {
101+
crate::trace::Trace::new_for_http(self)
102+
}
103+
104+
/// High level tracing that classifies responses using gRPC headers.
105+
///
106+
/// This method does not support customizing the output, to do that use [`TraceLayer`]
107+
/// instead.
108+
///
109+
/// See [`tower_http::trace`] for more details.
110+
///
111+
/// [`tower_http::trace`]: crate::trace
112+
/// [`TraceLayer`]: crate::trace::TraceLayer
113+
#[cfg(feature = "trace")]
114+
fn trace_for_grpc(self) -> crate::trace::Trace<Self, crate::trace::GrpcMakeClassifier> {
115+
crate::trace::Trace::new_for_grpc(self)
116+
}
117+
118+
/// Follow redirect resposes using the [`Standard`] policy.
119+
///
120+
/// See [`tower_http::follow_redirect`] for more details.
121+
///
122+
/// [`tower_http::follow_redirect`]: crate::follow_redirect
123+
/// [`Standard`]: crate::follow_redirect::policy::Standard
124+
#[cfg(feature = "follow-redirect")]
125+
fn follow_redirects(
126+
self,
127+
) -> crate::follow_redirect::FollowRedirect<Self, crate::follow_redirect::policy::Standard>
128+
{
129+
crate::follow_redirect::FollowRedirect::new(self)
130+
}
131+
132+
/// Mark headers as [sensitive] on both requests and responses.
133+
///
134+
/// See [`tower_http::sensitive_headers`] for more details.
135+
///
136+
/// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
137+
/// [`tower_http::sensitive_headers`]: crate::sensitive_headers
138+
#[cfg(feature = "sensitive-headers")]
139+
fn sensitive_headers(
140+
self,
141+
headers: impl IntoIterator<Item = HeaderName>,
142+
) -> crate::sensitive_headers::SetSensitiveHeaders<Self> {
143+
use tower_layer::Layer as _;
144+
crate::sensitive_headers::SetSensitiveHeadersLayer::new(headers).layer(self)
145+
}
146+
147+
/// Mark headers as [sensitive] on requests.
148+
///
149+
/// See [`tower_http::sensitive_headers`] for more details.
150+
///
151+
/// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
152+
/// [`tower_http::sensitive_headers`]: crate::sensitive_headers
153+
#[cfg(feature = "sensitive-headers")]
154+
fn sensitive_request_headers(
155+
self,
156+
headers: impl IntoIterator<Item = HeaderName>,
157+
) -> crate::sensitive_headers::SetSensitiveRequestHeaders<Self> {
158+
crate::sensitive_headers::SetSensitiveRequestHeaders::new(self, headers)
159+
}
160+
161+
/// Mark headers as [sensitive] on responses.
162+
///
163+
/// See [`tower_http::sensitive_headers`] for more details.
164+
///
165+
/// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
166+
/// [`tower_http::sensitive_headers`]: crate::sensitive_headers
167+
#[cfg(feature = "sensitive-headers")]
168+
fn sensitive_response_headers(
169+
self,
170+
headers: impl IntoIterator<Item = HeaderName>,
171+
) -> crate::sensitive_headers::SetSensitiveResponseHeaders<Self> {
172+
crate::sensitive_headers::SetSensitiveResponseHeaders::new(self, headers)
173+
}
174+
175+
/// Insert a header into the request.
176+
///
177+
/// If a previous value exists for the same header, it is removed and replaced with the new
178+
/// header value.
179+
///
180+
/// See [`tower_http::set_header`] for more details.
181+
///
182+
/// [`tower_http::set_header`]: crate::set_header
183+
#[cfg(feature = "set-header")]
184+
fn override_request_header<M>(
185+
self,
186+
header_name: HeaderName,
187+
make: M,
188+
) -> crate::set_header::SetRequestHeader<Self, M> {
189+
crate::set_header::SetRequestHeader::overriding(self, header_name, make)
190+
}
191+
192+
/// Append a header into the request.
193+
///
194+
/// If previous values exist, the header will have multiple values.
195+
///
196+
/// See [`tower_http::set_header`] for more details.
197+
///
198+
/// [`tower_http::set_header`]: crate::set_header
199+
#[cfg(feature = "set-header")]
200+
fn append_request_header<M>(
201+
self,
202+
header_name: HeaderName,
203+
make: M,
204+
) -> crate::set_header::SetRequestHeader<Self, M> {
205+
crate::set_header::SetRequestHeader::appending(self, header_name, make)
206+
}
207+
208+
/// Insert a header into the request, if the header is not already present.
209+
///
210+
/// See [`tower_http::set_header`] for more details.
211+
///
212+
/// [`tower_http::set_header`]: crate::set_header
213+
#[cfg(feature = "set-header")]
214+
fn insert_request_header_if_not_present<M>(
215+
self,
216+
header_name: HeaderName,
217+
make: M,
218+
) -> crate::set_header::SetRequestHeader<Self, M> {
219+
crate::set_header::SetRequestHeader::if_not_present(self, header_name, make)
220+
}
221+
222+
/// Insert a header into the response.
223+
///
224+
/// If a previous value exists for the same header, it is removed and replaced with the new
225+
/// header value.
226+
///
227+
/// See [`tower_http::set_header`] for more details.
228+
///
229+
/// [`tower_http::set_header`]: crate::set_header
230+
#[cfg(feature = "set-header")]
231+
fn override_response_header<M>(
232+
self,
233+
header_name: HeaderName,
234+
make: M,
235+
) -> crate::set_header::SetResponseHeader<Self, M> {
236+
crate::set_header::SetResponseHeader::overriding(self, header_name, make)
237+
}
238+
239+
/// Append a header into the response.
240+
///
241+
/// If previous values exist, the header will have multiple values.
242+
///
243+
/// See [`tower_http::set_header`] for more details.
244+
///
245+
/// [`tower_http::set_header`]: crate::set_header
246+
#[cfg(feature = "set-header")]
247+
fn append_response_header<M>(
248+
self,
249+
header_name: HeaderName,
250+
make: M,
251+
) -> crate::set_header::SetResponseHeader<Self, M> {
252+
crate::set_header::SetResponseHeader::appending(self, header_name, make)
253+
}
254+
255+
/// Insert a header into the response, if the header is not already present.
256+
///
257+
/// See [`tower_http::set_header`] for more details.
258+
///
259+
/// [`tower_http::set_header`]: crate::set_header
260+
#[cfg(feature = "set-header")]
261+
fn insert_response_header_if_not_present<M>(
262+
self,
263+
header_name: HeaderName,
264+
make: M,
265+
) -> crate::set_header::SetResponseHeader<Self, M> {
266+
crate::set_header::SetResponseHeader::if_not_present(self, header_name, make)
267+
}
268+
269+
/// Add request id header and extension.
270+
///
271+
/// See [`tower_http::request_id`] for more details.
272+
///
273+
/// [`tower_http::request_id`]: crate::request_id
274+
#[cfg(feature = "request-id")]
275+
fn set_request_id<M>(
276+
self,
277+
header_name: HeaderName,
278+
make_request_id: M,
279+
) -> crate::request_id::SetRequestId<Self, M>
280+
where
281+
M: crate::request_id::MakeRequestId,
282+
{
283+
crate::request_id::SetRequestId::new(self, header_name, make_request_id)
284+
}
285+
286+
/// Add request id header and extension, using `x-request-id` as the header name.
287+
///
288+
/// See [`tower_http::request_id`] for more details.
289+
///
290+
/// [`tower_http::request_id`]: crate::request_id
291+
#[cfg(feature = "request-id")]
292+
fn set_x_request_id<M>(self, make_request_id: M) -> crate::request_id::SetRequestId<Self, M>
293+
where
294+
M: crate::request_id::MakeRequestId,
295+
{
296+
self.set_request_id(crate::request_id::X_REQUEST_ID, make_request_id)
297+
}
298+
299+
/// Propgate request ids from requests to responses.
300+
///
301+
/// See [`tower_http::request_id`] for more details.
302+
///
303+
/// [`tower_http::request_id`]: crate::request_id
304+
#[cfg(feature = "request-id")]
305+
fn propagate_request_id(
306+
self,
307+
header_name: HeaderName,
308+
) -> crate::request_id::PropagateRequestId<Self> {
309+
crate::request_id::PropagateRequestId::new(self, header_name)
310+
}
311+
312+
/// Propgate request ids from requests to responses, using `x-request-id` as the header name.
313+
///
314+
/// See [`tower_http::request_id`] for more details.
315+
///
316+
/// [`tower_http::request_id`]: crate::request_id
317+
#[cfg(feature = "request-id")]
318+
fn propagate_x_request_id(self) -> crate::request_id::PropagateRequestId<Self> {
319+
self.propagate_request_id(crate::request_id::X_REQUEST_ID)
320+
}
321+
322+
/// Catch panics and convert them into `500 Internal Server` responses.
323+
///
324+
/// See [`tower_http::catch_panic`] for more details.
325+
///
326+
/// [`tower_http::catch_panic`]: crate::catch_panic
327+
#[cfg(feature = "catch-panic")]
328+
fn catch_panic(
329+
self,
330+
) -> crate::catch_panic::CatchPanic<Self, crate::catch_panic::DefaultResponseForPanic> {
331+
crate::catch_panic::CatchPanic::new(self)
332+
}
333+
334+
/// Intercept requests with over-sized payloads and convert them into
335+
/// `413 Payload Too Large` responses.
336+
///
337+
/// See [`tower_http::limit`] for more details.
338+
///
339+
/// [`tower_http::limit`]: crate::limit
340+
#[cfg(feature = "limit")]
341+
fn request_body_limit(self, limit: usize) -> crate::limit::RequestBodyLimit<Self> {
342+
crate::limit::RequestBodyLimit::new(self, limit)
343+
}
344+
345+
/// Remove trailing slashes from paths.
346+
///
347+
/// See [`tower_http::normalize_path`] for more details.
348+
///
349+
/// [`tower_http::normalize_path`]: crate::normalize_path
350+
#[cfg(feature = "normalize-path")]
351+
fn trim_trailing_slash(self) -> crate::normalize_path::NormalizePath<Self> {
352+
crate::normalize_path::NormalizePath::trim_trailing_slash(self)
353+
}
354+
}
355+
356+
impl<R, T> sealed::Sealed<R> for T where T: tower::Service<R> {}
357+
impl<R, T> ServiceExt<R> for T where T: tower::Service<R> {}

0 commit comments

Comments
 (0)