grafbase_sdk/types/
headers.rs

1pub(crate) use as_header_name::AsHeaderName;
2pub(crate) use as_header_value::AsHeaderValue;
3
4use crate::wit;
5
6/// HTTP headers.
7pub struct Headers(wit::Headers);
8
9/// HTTP headers for the subgraph request.
10/// Those are the result of the GatewayHeaders passed through the
11/// - on_request hook
12/// - global header rules
13/// - authorize_query from the authorization extensions
14/// - subgraph-specific header rules
15pub type SubgraphHeaders = Headers;
16
17/// HTTP headers for the gateway request.
18pub type GatewayHeaders = Headers;
19
20impl From<wit::Headers> for Headers {
21    fn from(headers: wit::Headers) -> Self {
22        Self(headers)
23    }
24}
25
26impl From<Headers> for wit::Headers {
27    fn from(headers: Headers) -> Self {
28        headers.0
29    }
30}
31
32impl Default for Headers {
33    fn default() -> Self {
34        Headers::new()
35    }
36}
37
38// Imitates as much as possible the http::HeaderMap API
39impl Headers {
40    /// Initialize an empty set of headers.
41    pub fn new() -> Headers {
42        Headers(wit::Headers::new())
43    }
44
45    /// Get the value associated with the given name. If there are multiple values associated with
46    /// the name, then the first one is returned. Use `get_all` to get all values associated with
47    /// a given name. Returns None if there are no values associated with the name.
48    pub fn get(&self, name: impl AsHeaderName) -> Option<http::HeaderValue> {
49        self.0
50            .get(name.as_str())
51            .into_iter()
52            .next()
53            .map(|value| value.try_into().unwrap())
54    }
55
56    /// Get all of the values corresponding to a name. If the name is not present,
57    /// an empty list is returned. However, if the name is present but empty, this
58    /// is represented by a list with one or more empty values present.
59    pub fn get_all(&self, name: impl AsHeaderName) -> impl Iterator<Item = http::HeaderValue> {
60        self.0
61            .get(name.as_str())
62            .into_iter()
63            .map(|value| value.try_into().unwrap())
64    }
65
66    /// Returns true if the map contains a value for the specified name.
67    pub fn has(&self, name: impl AsHeaderName) -> bool {
68        self.0.has(name.as_str())
69    }
70
71    /// Set all of the values for a name. Clears any existing values for that
72    /// name, if they have been set.
73    pub fn set<V: AsHeaderValue>(&mut self, name: impl AsHeaderName, values: impl IntoIterator<Item = V>) {
74        let values = values
75            .into_iter()
76            .map(|value| value.as_bytes().to_vec())
77            .collect::<Vec<_>>();
78        self.0
79            .set(name.as_str(), &values)
80            .expect("We have a mut ref & validated name and values.");
81    }
82
83    /// Removes a name from the map, returning the value associated with the name.
84    /// Returns None if the map does not contain the name. If there are multiple values associated with the name, then the first one is returned.
85    pub fn remove(&mut self, name: impl AsHeaderName) -> Option<http::HeaderValue> {
86        self.0
87            .get_and_delete(name.as_str())
88            .map(|values| values.into_iter().next().map(|value| value.try_into().unwrap()))
89            .expect("We have a mut ref & validated name and values.")
90    }
91
92    /// Append a value for a name. Does not change or delete any existing
93    /// values for that name.
94    pub fn append(&mut self, name: impl AsHeaderName, value: impl AsHeaderValue) {
95        self.0
96            .append(name.as_str(), value.as_bytes())
97            .expect("We have a mut ref & validated name and values.");
98    }
99
100    /// An iterator visiting all name-value pairs.
101    /// The iteration order is arbitrary, but consistent across platforms for the same crate version. Each name will be yielded once per associated value. So, if a name has 3 associated values, it will be yielded 3 times.
102    pub fn iter(&self) -> impl Iterator<Item = (http::HeaderName, http::HeaderValue)> {
103        self.0
104            .entries()
105            .into_iter()
106            .map(|(name, value)| (name.try_into().unwrap(), value.try_into().unwrap()))
107    }
108}
109
110impl From<&Headers> for http::HeaderMap {
111    fn from(headers: &Headers) -> Self {
112        headers.iter().collect()
113    }
114}
115
116/*
117* Imitating the http::HeaderMap API
118*
119* ===== impl IntoHeaderName / AsHeaderName =====
120*/
121
122mod as_header_name {
123    use http::HeaderName;
124
125    /// A marker trait used to identify values that can be used as search keys
126    /// to a `HttpHeaders`.
127    pub trait AsHeaderName: Sealed {}
128
129    // All methods are on this pub(super) trait, instead of `AsHeaderName`,
130    // so that they aren't publicly exposed to the world.
131    //
132    // Being on the `AsHeaderName` trait would mean users could call
133    // `"host".find(&map)`.
134    //
135    // Ultimately, this allows us to adjust the signatures of these methods
136    // without breaking any external crate.
137    pub trait Sealed {
138        #[doc(hidden)]
139        fn as_str(&self) -> &str;
140    }
141
142    // ==== impls ====
143
144    impl Sealed for HeaderName {
145        #[inline]
146        fn as_str(&self) -> &str {
147            HeaderName::as_str(self)
148        }
149    }
150
151    impl AsHeaderName for HeaderName {}
152
153    impl Sealed for &HeaderName {
154        #[inline]
155        fn as_str(&self) -> &str {
156            HeaderName::as_str(self)
157        }
158    }
159
160    impl AsHeaderName for &HeaderName {}
161
162    impl Sealed for &str {
163        #[inline]
164        fn as_str(&self) -> &str {
165            self
166        }
167    }
168
169    impl AsHeaderName for &str {}
170
171    impl Sealed for String {
172        #[inline]
173        fn as_str(&self) -> &str {
174            String::as_str(self)
175        }
176    }
177
178    impl AsHeaderName for String {}
179
180    impl Sealed for &String {
181        #[inline]
182        fn as_str(&self) -> &str {
183            String::as_str(self)
184        }
185    }
186
187    impl AsHeaderName for &String {}
188}
189
190mod as_header_value {
191    use http::HeaderValue;
192
193    /// A marker trait used to identify values that can be used as search keys
194    /// to a `HttpHeaders`.
195    pub trait AsHeaderValue: Sealed {}
196
197    // All methods are on this pub(super) trait, instead of `AsHeaderValue`,
198    // so that they aren't publicly exposed to the world.
199    //
200    // Being on the `AsHeaderValue` trait would mean users could call
201    // `"host".find(&map)`.
202    //
203    // Ultimately, this allows us to adjust the signatures of these methods
204    // without breaking any external crate.
205    pub trait Sealed: Sized {
206        #[doc(hidden)]
207        fn as_bytes(&self) -> &[u8];
208        fn into_bytes(self) -> Vec<u8> {
209            self.as_bytes().to_vec()
210        }
211    }
212
213    // ==== impls ====
214
215    impl Sealed for HeaderValue {
216        #[inline]
217        fn as_bytes(&self) -> &[u8] {
218            HeaderValue::as_bytes(self)
219        }
220    }
221
222    impl AsHeaderValue for HeaderValue {}
223
224    impl Sealed for &HeaderValue {
225        #[inline]
226        fn as_bytes(&self) -> &[u8] {
227            HeaderValue::as_bytes(self)
228        }
229    }
230
231    impl AsHeaderValue for &HeaderValue {}
232
233    impl Sealed for &[u8] {
234        #[inline]
235        fn as_bytes(&self) -> &[u8] {
236            self
237        }
238    }
239
240    impl AsHeaderValue for &[u8] {}
241
242    impl Sealed for &str {
243        #[inline]
244        fn as_bytes(&self) -> &[u8] {
245            str::as_bytes(self)
246        }
247    }
248
249    impl AsHeaderValue for &str {}
250
251    impl Sealed for String {
252        #[inline]
253        fn as_bytes(&self) -> &[u8] {
254            String::as_bytes(self)
255        }
256        fn into_bytes(self) -> Vec<u8> {
257            String::into_bytes(self)
258        }
259    }
260
261    impl AsHeaderValue for String {}
262
263    impl Sealed for &String {
264        #[inline]
265        fn as_bytes(&self) -> &[u8] {
266            String::as_bytes(self)
267        }
268    }
269
270    impl AsHeaderValue for &String {}
271
272    impl Sealed for Vec<u8> {
273        #[inline]
274        fn as_bytes(&self) -> &[u8] {
275            Vec::<u8>::as_ref(self)
276        }
277        fn into_bytes(self) -> Vec<u8> {
278            self
279        }
280    }
281
282    impl AsHeaderValue for Vec<u8> {}
283
284    impl Sealed for &Vec<u8> {
285        #[inline]
286        fn as_bytes(&self) -> &[u8] {
287            Vec::<u8>::as_ref(self)
288        }
289    }
290
291    impl AsHeaderValue for &Vec<u8> {}
292}