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