poem_openapi/param/
header.rs

1use std::ops::{Deref, DerefMut};
2
3use itertools::Either;
4use poem::{Request, RequestBody, Result};
5
6use crate::{
7    ApiExtractor, ApiExtractorType, ExtractParamOptions,
8    error::ParseParamError,
9    registry::{MetaParamIn, MetaSchemaRef, Registry},
10    types::ParseFromParameter,
11};
12
13/// Represents the parameters passed by the request header.
14pub struct Header<T>(pub T);
15
16impl<T> Deref for Header<T> {
17    type Target = T;
18
19    fn deref(&self) -> &Self::Target {
20        &self.0
21    }
22}
23
24impl<T> DerefMut for Header<T> {
25    fn deref_mut(&mut self) -> &mut Self::Target {
26        &mut self.0
27    }
28}
29
30impl<'a, T: ParseFromParameter> ApiExtractor<'a> for Header<T> {
31    const TYPES: &'static [ApiExtractorType] = &[ApiExtractorType::Parameter];
32    const PARAM_IS_REQUIRED: bool = T::IS_REQUIRED;
33
34    type ParamType = T;
35    type ParamRawType = T::RawValueType;
36
37    fn register(registry: &mut Registry) {
38        T::register(registry);
39    }
40
41    fn param_in() -> Option<MetaParamIn> {
42        Some(MetaParamIn::Header)
43    }
44
45    fn param_schema_ref() -> Option<MetaSchemaRef> {
46        Some(T::schema_ref())
47    }
48
49    fn param_raw_type(&self) -> Option<&Self::ParamRawType> {
50        self.0.as_raw_value()
51    }
52
53    async fn from_request(
54        request: &'a Request,
55        _body: &mut RequestBody,
56        param_opts: ExtractParamOptions<Self::ParamType>,
57    ) -> Result<Self> {
58        let mut values = if !param_opts.ignore_case {
59            Either::Left(
60                request
61                    .headers()
62                    .get_all(param_opts.name)
63                    .iter()
64                    .filter_map(|value| value.to_str().ok()),
65            )
66        } else {
67            Either::Right(
68                request
69                    .headers()
70                    .iter()
71                    .filter(|(n, _)| n.as_str().eq_ignore_ascii_case(param_opts.name))
72                    .filter_map(|(_, value)| value.to_str().ok()),
73            )
74        }
75        .peekable();
76
77        match &param_opts.default_value {
78            Some(default_value) if values.peek().is_none() => {
79                return Ok(Self(default_value()));
80            }
81            _ => {}
82        }
83
84        ParseFromParameter::parse_from_parameters(values)
85            .map(Self)
86            .map_err(|err| {
87                ParseParamError {
88                    name: param_opts.name,
89                    reason: err.into_message(),
90                }
91                .into()
92            })
93    }
94}