Skip to main content

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}