tower_http/
builder.rs

1use tower::ServiceBuilder;
2
3#[allow(unused_imports)]
4use http::header::HeaderName;
5#[allow(unused_imports)]
6use tower_layer::Stack;
7
8/// Extension trait that adds methods to [`tower::ServiceBuilder`] for adding middleware from
9/// tower-http.
10///
11/// [`Service`]: tower::Service
12///
13/// # Example
14///
15/// ```rust
16/// use http::{Request, Response, header::HeaderName};
17/// use bytes::Bytes;
18/// use http_body_util::Full;
19/// use std::{time::Duration, convert::Infallible};
20/// use tower::{ServiceBuilder, ServiceExt, Service};
21/// use tower_http::ServiceBuilderExt;
22///
23/// async fn handle(request: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, Infallible> {
24///     Ok(Response::new(Full::default()))
25/// }
26///
27/// # #[tokio::main]
28/// # async fn main() {
29/// let service = ServiceBuilder::new()
30///     // Methods from tower
31///     .timeout(Duration::from_secs(30))
32///     // Methods from tower-http
33///     .trace_for_http()
34///     .propagate_header(HeaderName::from_static("x-request-id"))
35///     .service_fn(handle);
36/// # let mut service = service;
37/// # service.ready().await.unwrap().call(Request::new(Full::default())).await.unwrap();
38/// # }
39/// ```
40#[cfg(feature = "util")]
41// ^ work around rustdoc not inferring doc(cfg)s for cfg's from surrounding scopes
42pub trait ServiceBuilderExt<L>: crate::sealed::Sealed<L> + Sized {
43    /// Propagate a header from the request to the response.
44    ///
45    /// See [`tower_http::propagate_header`] for more details.
46    ///
47    /// [`tower_http::propagate_header`]: crate::propagate_header
48    #[cfg(feature = "propagate-header")]
49    fn propagate_header(
50        self,
51        header: HeaderName,
52    ) -> ServiceBuilder<Stack<crate::propagate_header::PropagateHeaderLayer, L>>;
53
54    /// Add some shareable value to [request extensions].
55    ///
56    /// See [`tower_http::add_extension`] for more details.
57    ///
58    /// [`tower_http::add_extension`]: crate::add_extension
59    /// [request extensions]: https://docs.rs/http/latest/http/struct.Extensions.html
60    #[cfg(feature = "add-extension")]
61    fn add_extension<T>(
62        self,
63        value: T,
64    ) -> ServiceBuilder<Stack<crate::add_extension::AddExtensionLayer<T>, L>>;
65
66    /// Apply a transformation to the request body.
67    ///
68    /// See [`tower_http::map_request_body`] for more details.
69    ///
70    /// [`tower_http::map_request_body`]: crate::map_request_body
71    #[cfg(feature = "map-request-body")]
72    fn map_request_body<F>(
73        self,
74        f: F,
75    ) -> ServiceBuilder<Stack<crate::map_request_body::MapRequestBodyLayer<F>, L>>;
76
77    /// Apply a transformation to the response body.
78    ///
79    /// See [`tower_http::map_response_body`] for more details.
80    ///
81    /// [`tower_http::map_response_body`]: crate::map_response_body
82    #[cfg(feature = "map-response-body")]
83    fn map_response_body<F>(
84        self,
85        f: F,
86    ) -> ServiceBuilder<Stack<crate::map_response_body::MapResponseBodyLayer<F>, L>>;
87
88    /// Compresses response bodies.
89    ///
90    /// See [`tower_http::compression`] for more details.
91    ///
92    /// [`tower_http::compression`]: crate::compression
93    #[cfg(any(
94        feature = "compression-br",
95        feature = "compression-deflate",
96        feature = "compression-gzip",
97        feature = "compression-zstd",
98    ))]
99    fn compression(self) -> ServiceBuilder<Stack<crate::compression::CompressionLayer, L>>;
100
101    /// Decompress response bodies.
102    ///
103    /// See [`tower_http::decompression`] for more details.
104    ///
105    /// [`tower_http::decompression`]: crate::decompression
106    #[cfg(any(
107        feature = "decompression-br",
108        feature = "decompression-deflate",
109        feature = "decompression-gzip",
110        feature = "decompression-zstd",
111    ))]
112    fn decompression(self) -> ServiceBuilder<Stack<crate::decompression::DecompressionLayer, L>>;
113
114    /// High level tracing that classifies responses using HTTP status codes.
115    ///
116    /// This method does not support customizing the output, to do that use [`TraceLayer`]
117    /// instead.
118    ///
119    /// See [`tower_http::trace`] for more details.
120    ///
121    /// [`tower_http::trace`]: crate::trace
122    /// [`TraceLayer`]: crate::trace::TraceLayer
123    #[cfg(feature = "trace")]
124    fn trace_for_http(
125        self,
126    ) -> ServiceBuilder<Stack<crate::trace::TraceLayer<crate::trace::HttpMakeClassifier>, L>>;
127
128    /// High level tracing that classifies responses using gRPC headers.
129    ///
130    /// This method does not support customizing the output, to do that use [`TraceLayer`]
131    /// instead.
132    ///
133    /// See [`tower_http::trace`] for more details.
134    ///
135    /// [`tower_http::trace`]: crate::trace
136    /// [`TraceLayer`]: crate::trace::TraceLayer
137    #[cfg(feature = "trace")]
138    fn trace_for_grpc(
139        self,
140    ) -> ServiceBuilder<Stack<crate::trace::TraceLayer<crate::trace::GrpcMakeClassifier>, L>>;
141
142    /// Follow redirect resposes using the [`Standard`] policy.
143    ///
144    /// See [`tower_http::follow_redirect`] for more details.
145    ///
146    /// [`tower_http::follow_redirect`]: crate::follow_redirect
147    /// [`Standard`]: crate::follow_redirect::policy::Standard
148    #[cfg(feature = "follow-redirect")]
149    fn follow_redirects(
150        self,
151    ) -> ServiceBuilder<
152        Stack<
153            crate::follow_redirect::FollowRedirectLayer<crate::follow_redirect::policy::Standard>,
154            L,
155        >,
156    >;
157
158    /// Mark headers as [sensitive] on both requests and responses.
159    ///
160    /// See [`tower_http::sensitive_headers`] for more details.
161    ///
162    /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
163    /// [`tower_http::sensitive_headers`]: crate::sensitive_headers
164    #[cfg(feature = "sensitive-headers")]
165    fn sensitive_headers<I>(
166        self,
167        headers: I,
168    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveHeadersLayer, L>>
169    where
170        I: IntoIterator<Item = HeaderName>;
171
172    /// Mark headers as [sensitive] on requests.
173    ///
174    /// See [`tower_http::sensitive_headers`] for more details.
175    ///
176    /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
177    /// [`tower_http::sensitive_headers`]: crate::sensitive_headers
178    #[cfg(feature = "sensitive-headers")]
179    fn sensitive_request_headers(
180        self,
181        headers: std::sync::Arc<[HeaderName]>,
182    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveRequestHeadersLayer, L>>;
183
184    /// Mark headers as [sensitive] on responses.
185    ///
186    /// See [`tower_http::sensitive_headers`] for more details.
187    ///
188    /// [sensitive]: https://docs.rs/http/latest/http/header/struct.HeaderValue.html#method.set_sensitive
189    /// [`tower_http::sensitive_headers`]: crate::sensitive_headers
190    #[cfg(feature = "sensitive-headers")]
191    fn sensitive_response_headers(
192        self,
193        headers: std::sync::Arc<[HeaderName]>,
194    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveResponseHeadersLayer, L>>;
195
196    /// Insert a header into the request.
197    ///
198    /// If a previous value exists for the same header, it is removed and replaced with the new
199    /// header value.
200    ///
201    /// See [`tower_http::set_header`] for more details.
202    ///
203    /// [`tower_http::set_header`]: crate::set_header
204    #[cfg(feature = "set-header")]
205    fn override_request_header<M>(
206        self,
207        header_name: HeaderName,
208        make: M,
209    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>>;
210
211    /// Append a header into the request.
212    ///
213    /// If previous values exist, the header will have multiple values.
214    ///
215    /// See [`tower_http::set_header`] for more details.
216    ///
217    /// [`tower_http::set_header`]: crate::set_header
218    #[cfg(feature = "set-header")]
219    fn append_request_header<M>(
220        self,
221        header_name: HeaderName,
222        make: M,
223    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>>;
224
225    /// Insert a header into the request, if the header is not already present.
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 insert_request_header_if_not_present<M>(
232        self,
233        header_name: HeaderName,
234        make: M,
235    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>>;
236
237    /// Insert a header into the response.
238    ///
239    /// If a previous value exists for the same header, it is removed and replaced with the new
240    /// header value.
241    ///
242    /// See [`tower_http::set_header`] for more details.
243    ///
244    /// [`tower_http::set_header`]: crate::set_header
245    #[cfg(feature = "set-header")]
246    fn override_response_header<M>(
247        self,
248        header_name: HeaderName,
249        make: M,
250    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>>;
251
252    /// Append a header into the response.
253    ///
254    /// If previous values exist, the header will have multiple values.
255    ///
256    /// See [`tower_http::set_header`] for more details.
257    ///
258    /// [`tower_http::set_header`]: crate::set_header
259    #[cfg(feature = "set-header")]
260    fn append_response_header<M>(
261        self,
262        header_name: HeaderName,
263        make: M,
264    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>>;
265
266    /// Insert a header into the response, if the header is not already present.
267    ///
268    /// See [`tower_http::set_header`] for more details.
269    ///
270    /// [`tower_http::set_header`]: crate::set_header
271    #[cfg(feature = "set-header")]
272    fn insert_response_header_if_not_present<M>(
273        self,
274        header_name: HeaderName,
275        make: M,
276    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>>;
277
278    /// Add request id header and extension.
279    ///
280    /// See [`tower_http::request_id`] for more details.
281    ///
282    /// [`tower_http::request_id`]: crate::request_id
283    #[cfg(feature = "request-id")]
284    fn set_request_id<M>(
285        self,
286        header_name: HeaderName,
287        make_request_id: M,
288    ) -> ServiceBuilder<Stack<crate::request_id::SetRequestIdLayer<M>, L>>
289    where
290        M: crate::request_id::MakeRequestId;
291
292    /// Add request id header and extension, using `x-request-id` as the header name.
293    ///
294    /// See [`tower_http::request_id`] for more details.
295    ///
296    /// [`tower_http::request_id`]: crate::request_id
297    #[cfg(feature = "request-id")]
298    fn set_x_request_id<M>(
299        self,
300        make_request_id: M,
301    ) -> ServiceBuilder<Stack<crate::request_id::SetRequestIdLayer<M>, L>>
302    where
303        M: crate::request_id::MakeRequestId,
304    {
305        self.set_request_id(
306            HeaderName::from_static(crate::request_id::X_REQUEST_ID),
307            make_request_id,
308        )
309    }
310
311    /// Propgate request ids from requests to responses.
312    ///
313    /// See [`tower_http::request_id`] for more details.
314    ///
315    /// [`tower_http::request_id`]: crate::request_id
316    #[cfg(feature = "request-id")]
317    fn propagate_request_id(
318        self,
319        header_name: HeaderName,
320    ) -> ServiceBuilder<Stack<crate::request_id::PropagateRequestIdLayer, L>>;
321
322    /// Propgate request ids from requests to responses, using `x-request-id` as the header name.
323    ///
324    /// See [`tower_http::request_id`] for more details.
325    ///
326    /// [`tower_http::request_id`]: crate::request_id
327    #[cfg(feature = "request-id")]
328    fn propagate_x_request_id(
329        self,
330    ) -> ServiceBuilder<Stack<crate::request_id::PropagateRequestIdLayer, L>> {
331        self.propagate_request_id(HeaderName::from_static(crate::request_id::X_REQUEST_ID))
332    }
333
334    /// Catch panics and convert them into `500 Internal Server` responses.
335    ///
336    /// See [`tower_http::catch_panic`] for more details.
337    ///
338    /// [`tower_http::catch_panic`]: crate::catch_panic
339    #[cfg(feature = "catch-panic")]
340    fn catch_panic(
341        self,
342    ) -> ServiceBuilder<
343        Stack<crate::catch_panic::CatchPanicLayer<crate::catch_panic::DefaultResponseForPanic>, L>,
344    >;
345
346    /// Intercept requests with over-sized payloads and convert them into
347    /// `413 Payload Too Large` responses.
348    ///
349    /// See [`tower_http::limit`] for more details.
350    ///
351    /// [`tower_http::limit`]: crate::limit
352    #[cfg(feature = "limit")]
353    fn request_body_limit(
354        self,
355        limit: usize,
356    ) -> ServiceBuilder<Stack<crate::limit::RequestBodyLimitLayer, L>>;
357
358    /// Remove trailing slashes from paths.
359    ///
360    /// See [`tower_http::normalize_path`] for more details.
361    ///
362    /// [`tower_http::normalize_path`]: crate::normalize_path
363    #[cfg(feature = "normalize-path")]
364    fn trim_trailing_slash(
365        self,
366    ) -> ServiceBuilder<Stack<crate::normalize_path::NormalizePathLayer, L>>;
367}
368
369impl<L> crate::sealed::Sealed<L> for ServiceBuilder<L> {}
370
371impl<L> ServiceBuilderExt<L> for ServiceBuilder<L> {
372    #[cfg(feature = "propagate-header")]
373    fn propagate_header(
374        self,
375        header: HeaderName,
376    ) -> ServiceBuilder<Stack<crate::propagate_header::PropagateHeaderLayer, L>> {
377        self.layer(crate::propagate_header::PropagateHeaderLayer::new(header))
378    }
379
380    #[cfg(feature = "add-extension")]
381    fn add_extension<T>(
382        self,
383        value: T,
384    ) -> ServiceBuilder<Stack<crate::add_extension::AddExtensionLayer<T>, L>> {
385        self.layer(crate::add_extension::AddExtensionLayer::new(value))
386    }
387
388    #[cfg(feature = "map-request-body")]
389    fn map_request_body<F>(
390        self,
391        f: F,
392    ) -> ServiceBuilder<Stack<crate::map_request_body::MapRequestBodyLayer<F>, L>> {
393        self.layer(crate::map_request_body::MapRequestBodyLayer::new(f))
394    }
395
396    #[cfg(feature = "map-response-body")]
397    fn map_response_body<F>(
398        self,
399        f: F,
400    ) -> ServiceBuilder<Stack<crate::map_response_body::MapResponseBodyLayer<F>, L>> {
401        self.layer(crate::map_response_body::MapResponseBodyLayer::new(f))
402    }
403
404    #[cfg(any(
405        feature = "compression-br",
406        feature = "compression-deflate",
407        feature = "compression-gzip",
408        feature = "compression-zstd",
409    ))]
410    fn compression(self) -> ServiceBuilder<Stack<crate::compression::CompressionLayer, L>> {
411        self.layer(crate::compression::CompressionLayer::new())
412    }
413
414    #[cfg(any(
415        feature = "decompression-br",
416        feature = "decompression-deflate",
417        feature = "decompression-gzip",
418        feature = "decompression-zstd",
419    ))]
420    fn decompression(self) -> ServiceBuilder<Stack<crate::decompression::DecompressionLayer, L>> {
421        self.layer(crate::decompression::DecompressionLayer::new())
422    }
423
424    #[cfg(feature = "trace")]
425    fn trace_for_http(
426        self,
427    ) -> ServiceBuilder<Stack<crate::trace::TraceLayer<crate::trace::HttpMakeClassifier>, L>> {
428        self.layer(crate::trace::TraceLayer::new_for_http())
429    }
430
431    #[cfg(feature = "trace")]
432    fn trace_for_grpc(
433        self,
434    ) -> ServiceBuilder<Stack<crate::trace::TraceLayer<crate::trace::GrpcMakeClassifier>, L>> {
435        self.layer(crate::trace::TraceLayer::new_for_grpc())
436    }
437
438    #[cfg(feature = "follow-redirect")]
439    fn follow_redirects(
440        self,
441    ) -> ServiceBuilder<
442        Stack<
443            crate::follow_redirect::FollowRedirectLayer<crate::follow_redirect::policy::Standard>,
444            L,
445        >,
446    > {
447        self.layer(crate::follow_redirect::FollowRedirectLayer::new())
448    }
449
450    #[cfg(feature = "sensitive-headers")]
451    fn sensitive_headers<I>(
452        self,
453        headers: I,
454    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveHeadersLayer, L>>
455    where
456        I: IntoIterator<Item = HeaderName>,
457    {
458        self.layer(crate::sensitive_headers::SetSensitiveHeadersLayer::new(
459            headers,
460        ))
461    }
462
463    #[cfg(feature = "sensitive-headers")]
464    fn sensitive_request_headers(
465        self,
466        headers: std::sync::Arc<[HeaderName]>,
467    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveRequestHeadersLayer, L>> {
468        self.layer(crate::sensitive_headers::SetSensitiveRequestHeadersLayer::from_shared(headers))
469    }
470
471    #[cfg(feature = "sensitive-headers")]
472    fn sensitive_response_headers(
473        self,
474        headers: std::sync::Arc<[HeaderName]>,
475    ) -> ServiceBuilder<Stack<crate::sensitive_headers::SetSensitiveResponseHeadersLayer, L>> {
476        self.layer(crate::sensitive_headers::SetSensitiveResponseHeadersLayer::from_shared(headers))
477    }
478
479    #[cfg(feature = "set-header")]
480    fn override_request_header<M>(
481        self,
482        header_name: HeaderName,
483        make: M,
484    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>> {
485        self.layer(crate::set_header::SetRequestHeaderLayer::overriding(
486            header_name,
487            make,
488        ))
489    }
490
491    #[cfg(feature = "set-header")]
492    fn append_request_header<M>(
493        self,
494        header_name: HeaderName,
495        make: M,
496    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>> {
497        self.layer(crate::set_header::SetRequestHeaderLayer::appending(
498            header_name,
499            make,
500        ))
501    }
502
503    #[cfg(feature = "set-header")]
504    fn insert_request_header_if_not_present<M>(
505        self,
506        header_name: HeaderName,
507        make: M,
508    ) -> ServiceBuilder<Stack<crate::set_header::SetRequestHeaderLayer<M>, L>> {
509        self.layer(crate::set_header::SetRequestHeaderLayer::if_not_present(
510            header_name,
511            make,
512        ))
513    }
514
515    #[cfg(feature = "set-header")]
516    fn override_response_header<M>(
517        self,
518        header_name: HeaderName,
519        make: M,
520    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>> {
521        self.layer(crate::set_header::SetResponseHeaderLayer::overriding(
522            header_name,
523            make,
524        ))
525    }
526
527    #[cfg(feature = "set-header")]
528    fn append_response_header<M>(
529        self,
530        header_name: HeaderName,
531        make: M,
532    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>> {
533        self.layer(crate::set_header::SetResponseHeaderLayer::appending(
534            header_name,
535            make,
536        ))
537    }
538
539    #[cfg(feature = "set-header")]
540    fn insert_response_header_if_not_present<M>(
541        self,
542        header_name: HeaderName,
543        make: M,
544    ) -> ServiceBuilder<Stack<crate::set_header::SetResponseHeaderLayer<M>, L>> {
545        self.layer(crate::set_header::SetResponseHeaderLayer::if_not_present(
546            header_name,
547            make,
548        ))
549    }
550
551    #[cfg(feature = "request-id")]
552    fn set_request_id<M>(
553        self,
554        header_name: HeaderName,
555        make_request_id: M,
556    ) -> ServiceBuilder<Stack<crate::request_id::SetRequestIdLayer<M>, L>>
557    where
558        M: crate::request_id::MakeRequestId,
559    {
560        self.layer(crate::request_id::SetRequestIdLayer::new(
561            header_name,
562            make_request_id,
563        ))
564    }
565
566    #[cfg(feature = "request-id")]
567    fn propagate_request_id(
568        self,
569        header_name: HeaderName,
570    ) -> ServiceBuilder<Stack<crate::request_id::PropagateRequestIdLayer, L>> {
571        self.layer(crate::request_id::PropagateRequestIdLayer::new(header_name))
572    }
573
574    #[cfg(feature = "catch-panic")]
575    fn catch_panic(
576        self,
577    ) -> ServiceBuilder<
578        Stack<crate::catch_panic::CatchPanicLayer<crate::catch_panic::DefaultResponseForPanic>, L>,
579    > {
580        self.layer(crate::catch_panic::CatchPanicLayer::new())
581    }
582
583    #[cfg(feature = "limit")]
584    fn request_body_limit(
585        self,
586        limit: usize,
587    ) -> ServiceBuilder<Stack<crate::limit::RequestBodyLimitLayer, L>> {
588        self.layer(crate::limit::RequestBodyLimitLayer::new(limit))
589    }
590
591    #[cfg(feature = "normalize-path")]
592    fn trim_trailing_slash(
593        self,
594    ) -> ServiceBuilder<Stack<crate::normalize_path::NormalizePathLayer, L>> {
595        self.layer(crate::normalize_path::NormalizePathLayer::trim_trailing_slash())
596    }
597}