apollo_router/
http_ext.rs1use std::cmp::PartialEq;
6use std::hash::Hash;
7use std::ops::Deref;
8use std::ops::DerefMut;
9
10use axum::response::IntoResponse;
11use bytes::Bytes;
12use http::HeaderValue;
13use http::header;
14use http::header::HeaderName;
15use multimap::MultiMap;
16
17use crate::graphql;
18use crate::services::APPLICATION_JSON_HEADER_VALUE;
19
20pub struct TryIntoHeaderName {
43 result: Result<header::HeaderName, header::InvalidHeaderName>,
45}
46
47pub struct TryIntoHeaderValue {
70 result: Result<header::HeaderValue, header::InvalidHeaderValue>,
72}
73
74impl TryFrom<TryIntoHeaderName> for header::HeaderName {
75 type Error = header::InvalidHeaderName;
76
77 fn try_from(value: TryIntoHeaderName) -> Result<Self, Self::Error> {
78 value.result
79 }
80}
81
82impl TryFrom<TryIntoHeaderValue> for header::HeaderValue {
83 type Error = header::InvalidHeaderValue;
84
85 fn try_from(value: TryIntoHeaderValue) -> Result<Self, Self::Error> {
86 value.result
87 }
88}
89
90impl From<header::HeaderName> for TryIntoHeaderName {
91 fn from(value: header::HeaderName) -> Self {
92 Self { result: Ok(value) }
93 }
94}
95
96impl From<&'_ header::HeaderName> for TryIntoHeaderName {
97 fn from(value: &'_ header::HeaderName) -> Self {
98 Self {
99 result: Ok(value.clone()),
100 }
101 }
102}
103
104impl From<&'_ [u8]> for TryIntoHeaderName {
105 fn from(value: &'_ [u8]) -> Self {
106 Self {
107 result: value.try_into(),
108 }
109 }
110}
111
112impl From<&'_ str> for TryIntoHeaderName {
113 fn from(value: &'_ str) -> Self {
114 Self {
115 result: value.try_into(),
116 }
117 }
118}
119
120impl From<Vec<u8>> for TryIntoHeaderName {
121 fn from(value: Vec<u8>) -> Self {
122 Self {
123 result: value.try_into(),
124 }
125 }
126}
127
128impl From<String> for TryIntoHeaderName {
129 fn from(value: String) -> Self {
130 Self {
131 result: value.try_into(),
132 }
133 }
134}
135
136impl From<header::HeaderValue> for TryIntoHeaderValue {
137 fn from(value: header::HeaderValue) -> Self {
138 Self { result: Ok(value) }
139 }
140}
141
142impl From<&'_ header::HeaderValue> for TryIntoHeaderValue {
143 fn from(value: &'_ header::HeaderValue) -> Self {
144 Self {
145 result: Ok(value.clone()),
146 }
147 }
148}
149
150impl From<&'_ [u8]> for TryIntoHeaderValue {
151 fn from(value: &'_ [u8]) -> Self {
152 Self {
153 result: value.try_into(),
154 }
155 }
156}
157
158impl From<&'_ str> for TryIntoHeaderValue {
159 fn from(value: &'_ str) -> Self {
160 Self {
161 result: value.try_into(),
162 }
163 }
164}
165
166impl From<Vec<u8>> for TryIntoHeaderValue {
167 fn from(value: Vec<u8>) -> Self {
168 Self {
169 result: value.try_into(),
170 }
171 }
172}
173
174impl From<String> for TryIntoHeaderValue {
175 fn from(value: String) -> Self {
176 Self {
177 result: value.try_into(),
178 }
179 }
180}
181
182impl Eq for TryIntoHeaderName {}
183
184impl PartialEq for TryIntoHeaderName {
185 fn eq(&self, other: &Self) -> bool {
186 match (&self.result, &other.result) {
187 (Ok(a), Ok(b)) => a == b,
188 (Err(_), Err(_)) => true,
189 _ => false,
190 }
191 }
192}
193
194impl Hash for TryIntoHeaderName {
195 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
196 if let Ok(value) = &self.result {
197 value.hash(state)
198 }
199 }
200}
201
202pub(crate) fn header_map(
203 from: MultiMap<TryIntoHeaderName, TryIntoHeaderValue>,
204) -> Result<http::HeaderMap<http::HeaderValue>, http::Error> {
205 let mut http = http::HeaderMap::new();
206 for (key, values) in from {
207 let name = key.result?;
208 let mut values = values.into_iter();
209 if let Some(last) = values.next_back() {
210 for value in values {
211 http.append(name.clone(), value.result?);
212 }
213 http.append(name, last.result?);
214 }
215 }
216 Ok(http)
217}
218
219pub(crate) fn clone_http_request<B: Clone>(request: &http::Request<B>) -> http::Request<B> {
225 request.clone()
226}
227
228pub(crate) fn clone_http_response<B: Clone>(response: &http::Response<B>) -> http::Response<B> {
234 response.clone()
235}
236
237#[derive(Debug)]
239pub(crate) struct Request<T> {
240 pub(crate) inner: http::Request<T>,
241}
242
243#[buildstructor::buildstructor]
245impl<T> Request<T> {
246 #[builder]
250 pub(crate) fn new(
251 headers: MultiMap<TryIntoHeaderName, TryIntoHeaderValue>,
252 uri: http::Uri,
253 method: http::Method,
254 body: T,
255 ) -> http::Result<Request<T>> {
256 let mut builder = http::request::Builder::new().method(method).uri(uri);
257 for (key, values) in headers {
258 let header_name: HeaderName = key.try_into()?;
259 for value in values {
260 let header_value: HeaderValue = value.try_into()?;
261 builder = builder.header(header_name.clone(), header_value);
262 }
263 }
264 let req = builder.body(body)?;
265 Ok(Self { inner: req })
266 }
267}
268
269#[cfg(test)]
270#[buildstructor::buildstructor]
271impl<T> Request<T> {
272 #[builder]
280 pub(crate) fn fake_new(
281 headers: MultiMap<TryIntoHeaderName, TryIntoHeaderValue>,
282 uri: Option<http::Uri>,
283 method: Option<http::Method>,
284 body: T,
285 ) -> http::Result<Request<T>> {
286 Self::new(
287 headers,
288 uri.unwrap_or_default(),
289 method.unwrap_or(http::Method::GET),
290 body,
291 )
292 }
293}
294
295impl<T> Deref for Request<T> {
296 type Target = http::Request<T>;
297
298 fn deref(&self) -> &Self::Target {
299 &self.inner
300 }
301}
302
303impl<T> DerefMut for Request<T> {
304 fn deref_mut(&mut self) -> &mut Self::Target {
305 &mut self.inner
306 }
307}
308
309impl<T> From<http::Request<T>> for Request<T> {
310 fn from(inner: http::Request<T>) -> Self {
311 Request { inner }
312 }
313}
314
315impl<T: Clone> From<&'_ http::Request<T>> for Request<T> {
316 fn from(req: &'_ http::Request<T>) -> Self {
317 Request {
318 inner: clone_http_request(req),
319 }
320 }
321}
322
323impl<T> From<Request<T>> for http::Request<T> {
324 fn from(request: Request<T>) -> http::Request<T> {
325 request.inner
326 }
327}
328
329impl<T: Clone> Clone for Request<T> {
330 fn clone(&self) -> Self {
331 Self {
332 inner: clone_http_request(&self.inner),
333 }
334 }
335}
336
337impl<T: Hash> Hash for Request<T> {
338 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
339 self.inner.method().hash(state);
340 self.inner.version().hash(state);
341 self.inner.uri().hash(state);
342 for (name, value) in self.inner.headers() {
344 name.hash(state);
345 value.hash(state);
346 }
347 self.inner.body().hash(state);
348 }
349}
350
351impl<T: PartialEq> PartialEq for Request<T> {
352 fn eq(&self, other: &Self) -> bool {
353 let mut res = self.inner.method().eq(other.inner.method())
354 && self.inner.version().eq(&other.inner.version())
355 && self.inner.uri().eq(other.inner.uri());
356
357 if !res {
358 return false;
359 }
360 if self.inner.headers().len() != other.inner.headers().len() {
361 return false;
362 }
363
364 for ((name, value), (other_name, other_value)) in self
366 .inner
367 .headers()
368 .iter()
369 .zip(other.inner.headers().iter())
370 {
371 res = name.eq(other_name) && value.eq(other_value);
372 if !res {
373 return false;
374 }
375 }
376
377 self.inner.body().eq(other.inner.body())
378 }
379}
380
381impl<T: Eq> Eq for Request<T> {}
382
383#[derive(Debug, Default)]
385pub(crate) struct Response<T> {
386 pub(crate) inner: http::Response<T>,
387}
388
389impl<T> Deref for Response<T> {
390 type Target = http::Response<T>;
391
392 fn deref(&self) -> &Self::Target {
393 &self.inner
394 }
395}
396
397impl<T> DerefMut for Response<T> {
398 fn deref_mut(&mut self) -> &mut Self::Target {
399 &mut self.inner
400 }
401}
402
403impl<T> From<http::Response<T>> for Response<T> {
404 fn from(inner: http::Response<T>) -> Self {
405 Response { inner }
406 }
407}
408
409impl<T: Clone> From<&'_ http::Response<T>> for Response<T> {
410 fn from(req: &'_ http::Response<T>) -> Self {
411 Response {
412 inner: clone_http_response(req),
413 }
414 }
415}
416
417impl<T> From<Response<T>> for http::Response<T> {
418 fn from(response: Response<T>) -> http::Response<T> {
419 response.inner
420 }
421}
422
423impl<T: Clone> Clone for Response<T> {
424 fn clone(&self) -> Self {
425 Self {
426 inner: clone_http_response(&self.inner),
427 }
428 }
429}
430
431impl IntoResponse for Response<graphql::Response> {
432 fn into_response(self) -> axum::response::Response {
433 let (mut parts, body) = http::Response::from(self).into_parts();
435 let json_body_bytes =
436 Bytes::from(serde_json::to_vec(&body).expect("body should be serializable; qed"));
437 parts
438 .headers
439 .insert(header::CONTENT_TYPE, APPLICATION_JSON_HEADER_VALUE.clone());
440
441 axum::response::Response::from_parts(parts, axum::body::Body::from(json_body_bytes))
442 }
443}
444
445impl IntoResponse for Response<Bytes> {
446 fn into_response(self) -> axum::response::Response {
447 let (parts, body) = http::Response::from(self).into_parts();
449
450 axum::response::Response::from_parts(parts, axum::body::Body::from(body))
451 }
452}
453
454#[cfg(test)]
455mod test {
456 use http::HeaderValue;
457 use http::Method;
458 use http::Uri;
459
460 use super::clone_http_request;
461 use super::clone_http_response;
462 use crate::http_ext::Request;
463
464 #[test]
465 fn builder() {
466 let request = Request::builder()
467 .header("a", "b")
468 .header("a", "c")
469 .uri(Uri::from_static("http://example.com"))
470 .method(Method::POST)
471 .body("test")
472 .build()
473 .unwrap();
474 assert_eq!(
475 request
476 .headers()
477 .get_all("a")
478 .into_iter()
479 .collect::<Vec<_>>(),
480 vec![HeaderValue::from_static("b"), HeaderValue::from_static("c")]
481 );
482 assert_eq!(request.uri(), &Uri::from_static("http://example.com"));
483 assert_eq!(request.method(), Method::POST);
484 assert_eq!(request.body(), &"test");
485 }
486
487 #[test]
488 fn cloning_an_http_request_includes_extensions() {
489 let mut request = http::Request::new("body".to_string());
490 request.extensions_mut().insert::<usize>(6);
491 let cloned_request = clone_http_request(&request);
492
493 assert_eq!(
494 *cloned_request
495 .extensions()
496 .get::<usize>()
497 .expect("it has the usize extension"),
498 6
499 );
500 }
501
502 #[test]
503 fn cloning_an_http_response_includes_extensions() {
504 let mut response = http::Response::new("body".to_string());
505 response.extensions_mut().insert::<usize>(6);
506 let cloned_response = clone_http_response(&response);
507
508 assert_eq!(
509 *cloned_response
510 .extensions()
511 .get::<usize>()
512 .expect("it has the usize extension"),
513 6
514 );
515 }
516}