rama_http/layer/set_header/response/mod.rs
1//! Set a header on the response.
2//!
3//! The header value to be set may be provided as a fixed value when the
4//! middleware is constructed, or determined dynamically based on the response
5//! by a closure. See the [`MakeHeaderValue`] trait for details.
6//!
7//! # Example
8//!
9//! Setting a header from a fixed value provided when the middleware is constructed:
10//!
11//! ```
12//! use rama_http::layer::set_header::SetResponseHeaderLayer;
13//! use rama_http::{Body, Request, Response, header::{self, HeaderValue}};
14//! use rama_core::service::service_fn;
15//! use rama_core::{Service, Layer};
16//! use rama_core::error::BoxError;
17//!
18//! # #[tokio::main]
19//! # async fn main() -> Result<(), BoxError> {
20//! # let render_html = service_fn(async |request: Request| {
21//! # Ok::<_, std::convert::Infallible>(Response::new(request.into_body()))
22//! # });
23//! #
24//! let mut svc = (
25//! // Layer that sets `Content-Type: text/html` on responses.
26//! //
27//! // `if_not_present` will only insert the header if it does not already
28//! // have a value.
29//! SetResponseHeaderLayer::if_not_present(
30//! header::CONTENT_TYPE,
31//! HeaderValue::from_static("text/html"),
32//! ),
33//! ).into_layer(render_html);
34//!
35//! let request = Request::new(Body::empty());
36//!
37//! let response = svc.serve(request).await?;
38//!
39//! assert_eq!(response.headers()["content-type"], "text/html");
40//! #
41//! # Ok(())
42//! # }
43//! ```
44//!
45//! Setting a header based on a value determined dynamically from the response:
46//!
47//! ```
48//! use rama_core::error::BoxError;
49//! use rama_core::service::service_fn;
50//! use rama_core::{Layer, Service};
51//! use rama_http::StreamingBody as _;
52//! use rama_http::layer::set_header::SetResponseHeaderLayer;
53//! use rama_http::{
54//! header::{self, HeaderValue},
55//! Body, Request, Response,
56//! };
57//!
58//! #[tokio::main]
59//! async fn main() -> Result<(), BoxError> {
60//! let render_html = service_fn(async |_request: Request| {
61//! Ok::<_, std::convert::Infallible>(Response::new(Body::from("1234567890")))
62//! });
63//!
64//! let svc = (
65//! // Layer that sets `Content-Length` if the body has a known size.
66//! // Bodies with streaming responses won't have a known size.
67//! //
68//! // `overriding` will insert the header and override any previous values it
69//! // may have.
70//! SetResponseHeaderLayer::overriding_fn(
71//! header::CONTENT_LENGTH,
72//! async |response: Response| {
73//! let value = if let Some(size) = response.body().size_hint().exact() {
74//! // If the response body has a known size, returning `Some` will
75//! // set the `Content-Length` header to that value.
76//! Some(HeaderValue::try_from(size.to_string()).unwrap())
77//! } else {
78//! // If the response body doesn't have a known size, return `None`
79//! // to skip setting the header on this response.
80//! None
81//! };
82//! (response, value)
83//! },
84//! ),
85//! )
86//! .into_layer(render_html);
87//!
88//! let request = Request::new(Body::empty());
89//!
90//! let response = svc.serve(request).await?;
91//!
92//! assert_eq!(response.headers()["content-length"], "10");
93//!
94//! Ok(())
95//! }
96//! ```
97//!
98//! Setting a header based on the incoming Context and response combined.
99//!
100//! ```
101//! use rama_core::{extensions::{Extension, ExtensionsRef}, service::service_fn, Service};
102//! use rama_http::{
103//! layer::set_header::{response::BoxMakeHeaderValueFn, SetResponseHeader},
104//! Body, HeaderName, HeaderValue, Request, Response,
105//! service::web::response::IntoResponse,
106//! };
107//! use std::convert::Infallible;
108//!
109//! #[tokio::main]
110//! async fn main() {
111//! #[derive(Debug, Clone, Extension)]
112//! struct RequestID(String);
113//!
114//! #[derive(Debug, Clone, Extension)]
115//! struct Success;
116//!
117//! let svc = SetResponseHeader::overriding_fn(
118//! service_fn(async || {
119//! let mut res = ().into_response();
120//! res.extensions().insert(Success);
121//! Ok::<_, Infallible>(res)
122//! }),
123//! HeaderName::from_static("x-used-request-id"),
124//! async |req: Request| {
125//! let factory = req.extensions().get_ref::<RequestID>().cloned().map(|id| {
126//! BoxMakeHeaderValueFn::new(async move |res: Response| {
127//! let header_value = res.extensions().get_ref::<Success>().map(|_| {
128//! HeaderValue::from_str(id.0.as_str()).unwrap()
129//! });
130//! (res, header_value)
131//! })
132//! });
133//! (req, factory)
134//! },
135//! );
136//!
137//! const FAKE_USER_ID: &str = "abc123";
138//!
139//! let mut req = Request::new(Body::empty());
140//! req.extensions().insert(RequestID(FAKE_USER_ID.to_owned()));
141//!
142//! let res = svc.serve(req).await.unwrap();
143//!
144//! let mut values = res
145//! .headers()
146//! .get_all(HeaderName::from_static("x-used-request-id"))
147//! .iter();
148//! assert_eq!(values.next().unwrap(), FAKE_USER_ID);
149//! assert_eq!(values.next(), None);
150//! }
151//! ```
152
153use crate::{HeaderValue, Request, Response, header::HeaderName, headers::HeaderEncode};
154use rama_core::{Layer, Service};
155use rama_http_headers::TypedHeader;
156use rama_utils::macros::define_inner_service_accessors;
157use std::fmt;
158
159mod header;
160use header::InsertHeaderMode;
161
162pub use header::{
163 BoxMakeHeaderValueFactoryFn, BoxMakeHeaderValueFn, MakeHeaderValue, MakeHeaderValueDefault,
164 MakeHeaderValueFactory, MakeHeaderValueFactoryFn, MakeHeaderValueFn, TypedHeaderAsMaker,
165};
166
167/// Layer that applies [`SetResponseHeader`] which adds a response header.
168///
169/// See [`SetResponseHeader`] for more details.
170#[derive(Clone)]
171pub struct SetResponseHeaderLayer<M> {
172 header_name: HeaderName,
173 make: M,
174 mode: InsertHeaderMode,
175}
176
177impl<M> fmt::Debug for SetResponseHeaderLayer<M> {
178 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
179 f.debug_struct("SetResponseHeaderLayer")
180 .field("header_name", &self.header_name)
181 .field("mode", &self.mode)
182 .field("make", &std::any::type_name::<M>())
183 .finish()
184 }
185}
186
187impl<M> SetResponseHeaderLayer<M> {
188 /// Create a new [`SetResponseHeaderLayer`].
189 ///
190 /// If a previous value exists for the same header, it is removed and replaced with the new
191 /// header value.
192 #[inline(always)]
193 pub fn overriding(header_name: HeaderName, make: M) -> Self {
194 Self::new(header_name, make, InsertHeaderMode::Override)
195 }
196
197 /// Create a new [`SetResponseHeaderLayer`].
198 ///
199 /// The new header is always added, preserving any existing values. If previous values exist,
200 /// the header will have multiple values.
201 #[inline(always)]
202 pub fn appending(header_name: HeaderName, make: M) -> Self {
203 Self::new(header_name, make, InsertHeaderMode::Append)
204 }
205
206 /// Create a new [`SetResponseHeaderLayer`].
207 ///
208 /// If a previous value exists for the header, the new value is not inserted.
209 #[inline(always)]
210 pub fn if_not_present(header_name: HeaderName, make: M) -> Self {
211 Self::new(header_name, make, InsertHeaderMode::IfNotPresent)
212 }
213
214 #[inline(always)]
215 fn new(header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
216 Self {
217 make,
218 header_name,
219 mode,
220 }
221 }
222}
223
224impl SetResponseHeaderLayer<Option<HeaderValue>> {
225 /// Create a new [`SetResponseHeaderLayer`] from a typed [`HeaderEncode`].
226 ///
227 /// See [`SetResponseHeaderLayer::overriding`] for more details.
228 #[inline(always)]
229 pub fn overriding_typed<H: HeaderEncode>(header: H) -> Self {
230 Self::overriding(H::name().clone(), header.encode_to_value())
231 }
232
233 /// Create a new [`SetResponseHeaderLayer`] from a typed [`HeaderEncode`].
234 ///
235 /// See [`SetResponseHeaderLayer::appending`] for more details.
236 #[inline(always)]
237 pub fn appending_typed<H: HeaderEncode>(header: H) -> Self {
238 Self::appending(H::name().clone(), header.encode_to_value())
239 }
240
241 /// Create a new [`SetResponseHeaderLayer`] from a typed [`HeaderEncode`].
242 ///
243 /// See [`SetResponseHeaderLayer::if_not_present`] for more details.
244 #[inline(always)]
245 pub fn if_not_present_typed<H: HeaderEncode>(header: H) -> Self {
246 Self::if_not_present(H::name().clone(), header.encode_to_value())
247 }
248}
249
250impl<F, A> SetResponseHeaderLayer<BoxMakeHeaderValueFactoryFn<F, A>> {
251 /// Create a new [`SetResponseHeaderLayer`] from a [`header::MakeHeaderValueFn`].
252 ///
253 /// See [`SetResponseHeaderLayer::overriding`] for more details.
254 #[inline(always)]
255 pub fn overriding_fn(header_name: HeaderName, make_fn: F) -> Self {
256 Self::new(
257 header_name,
258 BoxMakeHeaderValueFactoryFn::new(make_fn),
259 InsertHeaderMode::Override,
260 )
261 }
262
263 /// Create a new [`SetResponseHeaderLayer`] from a [`header::MakeHeaderValueFn`].
264 ///
265 /// See [`SetResponseHeaderLayer::appending`] for more details.
266 #[inline(always)]
267 pub fn appending_fn(header_name: HeaderName, make_fn: F) -> Self {
268 Self::new(
269 header_name,
270 BoxMakeHeaderValueFactoryFn::new(make_fn),
271 InsertHeaderMode::Append,
272 )
273 }
274
275 /// Create a new [`SetResponseHeaderLayer`] from a [`header::MakeHeaderValueFn`].
276 ///
277 /// See [`SetResponseHeaderLayer::if_not_present`] for more details.
278 #[inline(always)]
279 pub fn if_not_present_fn(header_name: HeaderName, make_fn: F) -> Self {
280 Self::new(
281 header_name,
282 BoxMakeHeaderValueFactoryFn::new(make_fn),
283 InsertHeaderMode::IfNotPresent,
284 )
285 }
286}
287
288impl<M> SetResponseHeaderLayer<M> {
289 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`MakeHeaderValue`].
290 ///
291 /// See [`SetResponseHeaderLayer::overriding`] for more details.
292 #[inline(always)]
293 pub fn overriding_default(
294 header_name: HeaderName,
295 ) -> SetResponseHeaderLayer<MakeHeaderValueDefault<M>> {
296 SetResponseHeaderLayer::new(
297 header_name,
298 MakeHeaderValueDefault::new(),
299 InsertHeaderMode::Override,
300 )
301 }
302
303 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`MakeHeaderValue`].
304 ///
305 /// See [`SetResponseHeaderLayer::appending`] for more details.
306 #[inline(always)]
307 pub fn appending_default(
308 header_name: HeaderName,
309 ) -> SetResponseHeaderLayer<MakeHeaderValueDefault<M>> {
310 SetResponseHeaderLayer::new(
311 header_name,
312 MakeHeaderValueDefault::new(),
313 InsertHeaderMode::Append,
314 )
315 }
316
317 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`MakeHeaderValue`].
318 ///
319 /// See [`SetResponseHeaderLayer::if_not_present`] for more details.
320 #[inline(always)]
321 pub fn if_not_present_default(
322 header_name: HeaderName,
323 ) -> SetResponseHeaderLayer<MakeHeaderValueDefault<M>> {
324 SetResponseHeaderLayer::new(
325 header_name,
326 MakeHeaderValueDefault::new(),
327 InsertHeaderMode::IfNotPresent,
328 )
329 }
330}
331
332impl<M: TypedHeader> SetResponseHeaderLayer<M> {
333 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`TypedHeader`].
334 ///
335 /// See [`SetResponseHeaderLayer::overriding`] for more details.
336 #[inline(always)]
337 #[must_use]
338 pub fn overriding_default_typed()
339 -> SetResponseHeaderLayer<MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
340 SetResponseHeaderLayer::new(
341 M::name().clone(),
342 MakeHeaderValueDefault::new(),
343 InsertHeaderMode::Override,
344 )
345 }
346
347 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`TypedHeader`].
348 ///
349 /// See [`SetResponseHeaderLayer::appending`] for more details.
350 #[inline(always)]
351 #[must_use]
352 pub fn appending_default_typed()
353 -> SetResponseHeaderLayer<MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
354 SetResponseHeaderLayer::new(
355 M::name().clone(),
356 MakeHeaderValueDefault::new(),
357 InsertHeaderMode::Append,
358 )
359 }
360
361 /// Create a new [`SetResponseHeaderLayer`] from a [`Default`] [`TypedHeader`].
362 ///
363 /// See [`SetResponseHeaderLayer::if_not_present`] for more details.
364 #[inline(always)]
365 #[must_use]
366 pub fn if_not_present_default_typed()
367 -> SetResponseHeaderLayer<MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
368 SetResponseHeaderLayer::new(
369 M::name().clone(),
370 MakeHeaderValueDefault::new(),
371 InsertHeaderMode::IfNotPresent,
372 )
373 }
374}
375
376impl<S, M> Layer<S> for SetResponseHeaderLayer<M>
377where
378 M: Clone,
379{
380 type Service = SetResponseHeader<S, M>;
381
382 fn layer(&self, inner: S) -> Self::Service {
383 SetResponseHeader {
384 inner,
385 header_name: self.header_name.clone(),
386 make: self.make.clone(),
387 mode: self.mode,
388 }
389 }
390
391 fn into_layer(self, inner: S) -> Self::Service {
392 SetResponseHeader {
393 inner,
394 header_name: self.header_name,
395 make: self.make,
396 mode: self.mode,
397 }
398 }
399}
400
401/// Middleware that sets a header on the response.
402#[derive(Clone)]
403pub struct SetResponseHeader<S, M> {
404 inner: S,
405 header_name: HeaderName,
406 make: M,
407 mode: InsertHeaderMode,
408}
409
410impl<S, H: HeaderEncode> SetResponseHeader<S, TypedHeaderAsMaker<H>> {
411 /// Create a new [`SetResponseHeader`] from a typed [`HeaderEncode`].
412 ///
413 /// See [`SetResponseHeader::overriding`] for more details.
414 pub fn overriding_typed(inner: S, header: H) -> Self {
415 Self::overriding(inner, H::name().clone(), TypedHeaderAsMaker(header))
416 }
417
418 /// Create a new [`SetResponseHeader`] from a typed [`HeaderEncode`].
419 ///
420 /// See [`SetResponseHeader::appending`] for more details.
421 pub fn appending_typed(inner: S, header: H) -> Self {
422 Self::appending(inner, H::name().clone(), TypedHeaderAsMaker(header))
423 }
424
425 /// Create a new [`SetResponseHeader`] from a typed [`HeaderEncode`].
426 ///
427 /// See [`SetResponseHeader::if_not_present`] for more details.
428 pub fn if_not_present_typed(inner: S, header: H) -> Self {
429 Self::if_not_present(inner, H::name().clone(), TypedHeaderAsMaker(header))
430 }
431}
432
433impl<S, M> SetResponseHeader<S, M> {
434 /// Create a new [`SetResponseHeader`].
435 ///
436 /// If a previous value exists for the same header, it is removed and replaced with the new
437 /// header value.
438 #[inline(always)]
439 pub fn overriding(inner: S, header_name: HeaderName, make: M) -> Self {
440 Self::new(inner, header_name, make, InsertHeaderMode::Override)
441 }
442
443 /// Create a new [`SetResponseHeader`].
444 ///
445 /// The new header is always added, preserving any existing values. If previous values exist,
446 /// the header will have multiple values.
447 #[inline(always)]
448 pub fn appending(inner: S, header_name: HeaderName, make: M) -> Self {
449 Self::new(inner, header_name, make, InsertHeaderMode::Append)
450 }
451
452 /// Create a new [`SetResponseHeader`].
453 ///
454 /// If a previous value exists for the header, the new value is not inserted.
455 #[inline(always)]
456 pub fn if_not_present(inner: S, header_name: HeaderName, make: M) -> Self {
457 Self::new(inner, header_name, make, InsertHeaderMode::IfNotPresent)
458 }
459
460 fn new(inner: S, header_name: HeaderName, make: M, mode: InsertHeaderMode) -> Self {
461 Self {
462 inner,
463 header_name,
464 make,
465 mode,
466 }
467 }
468
469 define_inner_service_accessors!();
470}
471
472impl<S, F, A> SetResponseHeader<S, BoxMakeHeaderValueFactoryFn<F, A>> {
473 /// Create a new [`SetResponseHeader`] from a [`header::MakeHeaderValueFn`].
474 ///
475 /// See [`SetResponseHeader::overriding`] for more details.
476 #[inline(always)]
477 pub fn overriding_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
478 Self::new(
479 inner,
480 header_name,
481 BoxMakeHeaderValueFactoryFn::new(make_fn),
482 InsertHeaderMode::Override,
483 )
484 }
485
486 /// Create a new [`SetResponseHeader`] from a [`header::MakeHeaderValueFn`].
487 ///
488 /// See [`SetResponseHeader::appending`] for more details.
489 #[inline(always)]
490 pub fn appending_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
491 Self::new(
492 inner,
493 header_name,
494 BoxMakeHeaderValueFactoryFn::new(make_fn),
495 InsertHeaderMode::Append,
496 )
497 }
498
499 /// Create a new [`SetResponseHeader`] from a [`header::MakeHeaderValueFn`].
500 ///
501 /// See [`SetResponseHeader::if_not_present`] for more details.
502 #[inline(always)]
503 pub fn if_not_present_fn(inner: S, header_name: HeaderName, make_fn: F) -> Self {
504 Self::new(
505 inner,
506 header_name,
507 BoxMakeHeaderValueFactoryFn::new(make_fn),
508 InsertHeaderMode::IfNotPresent,
509 )
510 }
511}
512
513impl<S, M> SetResponseHeader<S, M> {
514 /// Create a new [`SetResponseHeader`] from a [`Default`] [`MakeHeaderValue`].
515 ///
516 /// See [`SetResponseHeader::overriding`] for more details.
517 #[inline(always)]
518 pub fn overriding_default(
519 inner: S,
520 header_name: HeaderName,
521 ) -> SetResponseHeader<S, MakeHeaderValueDefault<M>> {
522 SetResponseHeader::new(
523 inner,
524 header_name,
525 MakeHeaderValueDefault::new(),
526 InsertHeaderMode::Override,
527 )
528 }
529
530 /// Create a new [`SetResponseHeader`] from a [`Default`] [`MakeHeaderValue`].
531 ///
532 /// See [`SetResponseHeader::appending`] for more details.
533 #[inline(always)]
534 pub fn appending_default(
535 inner: S,
536 header_name: HeaderName,
537 ) -> SetResponseHeader<S, MakeHeaderValueDefault<M>> {
538 SetResponseHeader::new(
539 inner,
540 header_name,
541 MakeHeaderValueDefault::new(),
542 InsertHeaderMode::Append,
543 )
544 }
545
546 /// Create a new [`SetResponseHeader`] from a [`Default`] [`MakeHeaderValue`].
547 ///
548 /// See [`SetResponseHeader::if_not_present`] for more details.
549 #[inline(always)]
550 pub fn if_not_present_default(
551 inner: S,
552 header_name: HeaderName,
553 ) -> SetResponseHeader<S, MakeHeaderValueDefault<M>> {
554 SetResponseHeader::new(
555 inner,
556 header_name,
557 MakeHeaderValueDefault::new(),
558 InsertHeaderMode::IfNotPresent,
559 )
560 }
561}
562
563impl<S, M: TypedHeader> SetResponseHeader<S, M> {
564 /// Create a new [`SetResponseHeader`] from a [`Default`] [`TypedHeader`].
565 ///
566 /// See [`SetResponseHeader::overriding`] for more details.
567 #[inline(always)]
568 pub fn overriding_default_typed(
569 inner: S,
570 ) -> SetResponseHeader<S, MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
571 SetResponseHeader::new(
572 inner,
573 M::name().clone(),
574 MakeHeaderValueDefault::new(),
575 InsertHeaderMode::Override,
576 )
577 }
578
579 /// Create a new [`SetResponseHeader`] from a [`Default`] [`TypedHeader`].
580 ///
581 /// See [`SetResponseHeader::appending`] for more details.
582 #[inline(always)]
583 pub fn appending_default_typed(
584 inner: S,
585 ) -> SetResponseHeader<S, MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
586 SetResponseHeader::new(
587 inner,
588 M::name().clone(),
589 MakeHeaderValueDefault::new(),
590 InsertHeaderMode::Append,
591 )
592 }
593
594 /// Create a new [`SetResponseHeader`] from a [`Default`] [`TypedHeader`].
595 ///
596 /// See [`SetResponseHeader::if_not_present`] for more details.
597 #[inline(always)]
598 pub fn if_not_present_default_typed(
599 inner: S,
600 ) -> SetResponseHeader<S, MakeHeaderValueDefault<TypedHeaderAsMaker<M>>> {
601 SetResponseHeader::new(
602 inner,
603 M::name().clone(),
604 MakeHeaderValueDefault::new(),
605 InsertHeaderMode::IfNotPresent,
606 )
607 }
608}
609
610impl<S, M> fmt::Debug for SetResponseHeader<S, M>
611where
612 S: fmt::Debug,
613{
614 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
615 f.debug_struct("SetResponseHeader")
616 .field("inner", &self.inner)
617 .field("header_name", &self.header_name)
618 .field("mode", &self.mode)
619 .field("make", &std::any::type_name::<M>())
620 .finish()
621 }
622}
623
624impl<ReqBody, ResBody, S, M> Service<Request<ReqBody>> for SetResponseHeader<S, M>
625where
626 ReqBody: Send + 'static,
627 ResBody: Send + 'static,
628 S: Service<Request<ReqBody>, Output = Response<ResBody>>,
629 M: MakeHeaderValueFactory<ReqBody, ResBody>,
630{
631 type Output = S::Output;
632 type Error = S::Error;
633
634 async fn serve(&self, req: Request<ReqBody>) -> Result<Self::Output, Self::Error> {
635 let (req, header_maker) = self.make.make_header_value_maker(req).await;
636 let res = self.inner.serve(req).await?;
637 let res = self.mode.apply(&self.header_name, res, header_maker).await;
638 Ok(res)
639 }
640}
641
642#[cfg(test)]
643mod tests {
644 use super::*;
645
646 use crate::{Body, HeaderValue, Request, Response, header};
647 use rama_core::service::service_fn;
648 use std::convert::Infallible;
649
650 #[tokio::test]
651 async fn test_override_mode() {
652 let svc = SetResponseHeader::overriding(
653 service_fn(async || {
654 let res = Response::builder()
655 .header(header::CONTENT_TYPE, "good-content")
656 .body(Body::empty())
657 .unwrap();
658 Ok::<_, Infallible>(res)
659 }),
660 header::CONTENT_TYPE,
661 HeaderValue::from_static("text/html"),
662 );
663
664 let res = svc.serve(Request::new(Body::empty())).await.unwrap();
665
666 let mut values = res.headers().get_all(header::CONTENT_TYPE).iter();
667 assert_eq!(values.next().unwrap(), "text/html");
668 assert_eq!(values.next(), None);
669 }
670
671 #[tokio::test]
672 async fn test_append_mode() {
673 let svc = SetResponseHeader::appending(
674 service_fn(async || {
675 let res = Response::builder()
676 .header(header::CONTENT_TYPE, "good-content")
677 .body(Body::empty())
678 .unwrap();
679 Ok::<_, Infallible>(res)
680 }),
681 header::CONTENT_TYPE,
682 HeaderValue::from_static("text/html"),
683 );
684
685 let res = svc.serve(Request::new(Body::empty())).await.unwrap();
686
687 let mut values = res.headers().get_all(header::CONTENT_TYPE).iter();
688 assert_eq!(values.next().unwrap(), "good-content");
689 assert_eq!(values.next().unwrap(), "text/html");
690 assert_eq!(values.next(), None);
691 }
692
693 #[tokio::test]
694 async fn test_skip_if_present_mode() {
695 let svc = SetResponseHeader::if_not_present(
696 service_fn(async || {
697 let res = Response::builder()
698 .header(header::CONTENT_TYPE, "good-content")
699 .body(Body::empty())
700 .unwrap();
701 Ok::<_, Infallible>(res)
702 }),
703 header::CONTENT_TYPE,
704 HeaderValue::from_static("text/html"),
705 );
706
707 let res = svc.serve(Request::new(Body::empty())).await.unwrap();
708
709 let mut values = res.headers().get_all(header::CONTENT_TYPE).iter();
710 assert_eq!(values.next().unwrap(), "good-content");
711 assert_eq!(values.next(), None);
712 }
713
714 #[tokio::test]
715 async fn test_skip_if_present_mode_when_not_present() {
716 let svc = SetResponseHeader::if_not_present(
717 service_fn(async || {
718 let res = Response::builder().body(Body::empty()).unwrap();
719 Ok::<_, Infallible>(res)
720 }),
721 header::CONTENT_TYPE,
722 HeaderValue::from_static("text/html"),
723 );
724
725 let res = svc.serve(Request::new(Body::empty())).await.unwrap();
726
727 let mut values = res.headers().get_all(header::CONTENT_TYPE).iter();
728 assert_eq!(values.next().unwrap(), "text/html");
729 assert_eq!(values.next(), None);
730 }
731}