tower_http/
service_ext.rs

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