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}