rama_http/layer/cors/mod.rs
1//! Middleware which adds headers for [CORS][mdn].
2//!
3//! # Example
4//!
5//! ```
6//! use std::convert::Infallible;
7//! use bytes::Bytes;
8//!
9//! use rama_http::{Body, Request, Response, Method, header};
10//! use rama_http::layer::cors::{Any, CorsLayer};
11//! use rama_core::service::service_fn;
12//! use rama_core::{Context, Service, Layer};
13//!
14//! async fn handle(request: Request) -> Result<Response, Infallible> {
15//! Ok(Response::new(Body::default()))
16//! }
17//!
18//! # #[tokio::main]
19//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
20//! let cors = CorsLayer::new()
21//! // allow `GET` and `POST` when accessing the resource
22//! .allow_methods([Method::GET, Method::POST])
23//! // allow requests from any origin
24//! .allow_origin(Any);
25//!
26//! let mut service = cors.into_layer(service_fn(handle));
27//!
28//! let request = Request::builder()
29//! .header(header::ORIGIN, "https://example.com")
30//! .body(Body::default())
31//! .unwrap();
32//!
33//! let response = service
34//! .serve(Context::default(), request)
35//! .await?;
36//!
37//! assert_eq!(
38//! response.headers().get(header::ACCESS_CONTROL_ALLOW_ORIGIN).unwrap(),
39//! "*",
40//! );
41//! # Ok(())
42//! # }
43//! ```
44//!
45//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
46
47#![allow(clippy::enum_variant_names)]
48
49use crate::dep::http::{
50 HeaderMap, HeaderValue, Method, Request, Response,
51 header::{self, HeaderName},
52};
53use bytes::{BufMut, BytesMut};
54use rama_core::{Context, Layer, Service};
55use rama_utils::macros::define_inner_service_accessors;
56use std::{array, fmt, mem};
57
58mod allow_credentials;
59mod allow_headers;
60mod allow_methods;
61mod allow_origin;
62mod allow_private_network;
63mod expose_headers;
64mod max_age;
65mod vary;
66
67#[cfg(test)]
68mod tests;
69
70#[doc(inline)]
71pub use self::{
72 allow_credentials::AllowCredentials, allow_headers::AllowHeaders, allow_methods::AllowMethods,
73 allow_origin::AllowOrigin, allow_private_network::AllowPrivateNetwork,
74 expose_headers::ExposeHeaders, max_age::MaxAge, vary::Vary,
75};
76
77/// Layer that applies the [`Cors`] middleware which adds headers for [CORS][mdn].
78///
79/// See the [module docs](crate::layer::cors) for an example.
80///
81/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
82#[derive(Debug, Clone)]
83#[must_use]
84pub struct CorsLayer {
85 allow_credentials: AllowCredentials,
86 allow_headers: AllowHeaders,
87 allow_methods: AllowMethods,
88 allow_origin: AllowOrigin,
89 allow_private_network: AllowPrivateNetwork,
90 expose_headers: ExposeHeaders,
91 max_age: MaxAge,
92 vary: Vary,
93}
94
95#[allow(clippy::declare_interior_mutable_const)]
96const WILDCARD: HeaderValue = HeaderValue::from_static("*");
97
98impl CorsLayer {
99 /// Create a new `CorsLayer`.
100 ///
101 /// No headers are sent by default. Use the builder methods to customize
102 /// the behavior.
103 ///
104 /// You need to set at least an allowed origin for browsers to make
105 /// successful cross-origin requests to your service.
106 pub fn new() -> Self {
107 Self {
108 allow_credentials: Default::default(),
109 allow_headers: Default::default(),
110 allow_methods: Default::default(),
111 allow_origin: Default::default(),
112 allow_private_network: Default::default(),
113 expose_headers: Default::default(),
114 max_age: Default::default(),
115 vary: Default::default(),
116 }
117 }
118
119 /// A permissive configuration:
120 ///
121 /// - All request headers allowed.
122 /// - All methods allowed.
123 /// - All origins allowed.
124 /// - All headers exposed.
125 pub fn permissive() -> Self {
126 Self::new()
127 .allow_headers(Any)
128 .allow_methods(Any)
129 .allow_origin(Any)
130 .expose_headers(Any)
131 }
132
133 /// A very permissive configuration:
134 ///
135 /// - **Credentials allowed.**
136 /// - The method received in `Access-Control-Request-Method` is sent back
137 /// as an allowed method.
138 /// - The origin of the preflight request is sent back as an allowed origin.
139 /// - The header names received in `Access-Control-Request-Headers` are sent
140 /// back as allowed headers.
141 /// - No headers are currently exposed, but this may change in the future.
142 pub fn very_permissive() -> Self {
143 Self::new()
144 .allow_credentials(true)
145 .allow_headers(AllowHeaders::mirror_request())
146 .allow_methods(AllowMethods::mirror_request())
147 .allow_origin(AllowOrigin::mirror_request())
148 }
149
150 /// Set the [`Access-Control-Allow-Credentials`][mdn] header.
151 ///
152 /// ```
153 /// use rama_http::layer::cors::CorsLayer;
154 ///
155 /// let layer = CorsLayer::new().allow_credentials(true);
156 /// ```
157 ///
158 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
159 pub fn allow_credentials<T>(mut self, allow_credentials: T) -> Self
160 where
161 T: Into<AllowCredentials>,
162 {
163 self.allow_credentials = allow_credentials.into();
164 self
165 }
166
167 /// Set the value of the [`Access-Control-Allow-Headers`][mdn] header.
168 ///
169 /// ```
170 /// use rama_http::layer::cors::CorsLayer;
171 /// use rama_http::header::{AUTHORIZATION, ACCEPT};
172 ///
173 /// let layer = CorsLayer::new().allow_headers([AUTHORIZATION, ACCEPT]);
174 /// ```
175 ///
176 /// All headers can be allowed with
177 ///
178 /// ```
179 /// use rama_http::layer::cors::{Any, CorsLayer};
180 ///
181 /// let layer = CorsLayer::new().allow_headers(Any);
182 /// ```
183 ///
184 /// You can also use an async closure:
185 ///
186 /// ```
187 /// # #[derive(Clone)]
188 /// # struct Client;
189 /// # fn get_api_client() -> Client {
190 /// # Client
191 /// # }
192 /// # impl Client {
193 /// # async fn fetch_allowed_origins(&self) -> Vec<HeaderValue> {
194 /// # vec![HeaderValue::from_static("http://example.com")]
195 /// # }
196 /// # async fn fetch_allowed_origins_for_path(&self, _path: String) -> Vec<HeaderValue> {
197 /// # vec![HeaderValue::from_static("http://example.com")]
198 /// # }
199 /// # }
200 /// use rama_http::layer::cors::{CorsLayer, AllowOrigin};
201 /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue};
202 ///
203 /// let client = get_api_client();
204 ///
205 /// let layer = CorsLayer::new().allow_origin(AllowOrigin::async_predicate(
206 /// |origin: HeaderValue, _request_parts: &RequestParts| async move {
207 /// // fetch list of origins that are allowed
208 /// let origins = client.fetch_allowed_origins().await;
209 /// origins.contains(&origin)
210 /// },
211 /// ));
212 ///
213 /// let client = get_api_client();
214 ///
215 /// // if using &RequestParts, make sure all the values are owned
216 /// // before passing into the future
217 /// let layer = CorsLayer::new().allow_origin(AllowOrigin::async_predicate(
218 /// |origin: HeaderValue, parts: &RequestParts| {
219 /// let path = parts.uri.path().to_owned();
220 ///
221 /// async move {
222 /// // fetch list of origins that are allowed for this path
223 /// let origins = client.fetch_allowed_origins_for_path(path).await;
224 /// origins.contains(&origin)
225 /// }
226 /// },
227 /// ));
228 /// ```
229 ///
230 /// Note that multiple calls to this method will override any previous
231 /// calls.
232 ///
233 /// Also note that `Access-Control-Allow-Headers` is required for requests that have
234 /// `Access-Control-Request-Headers`.
235 ///
236 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
237 pub fn allow_headers<T>(mut self, headers: T) -> Self
238 where
239 T: Into<AllowHeaders>,
240 {
241 self.allow_headers = headers.into();
242 self
243 }
244
245 /// Set the value of the [`Access-Control-Max-Age`][mdn] header.
246 ///
247 /// ```
248 /// use std::time::Duration;
249 /// use rama_http::layer::cors::CorsLayer;
250 ///
251 /// let layer = CorsLayer::new().max_age(Duration::from_secs(60) * 10);
252 /// ```
253 ///
254 /// By default the header will not be set which disables caching and will
255 /// require a preflight call for all requests.
256 ///
257 /// Note that each browser has a maximum internal value that takes
258 /// precedence when the Access-Control-Max-Age is greater. For more details
259 /// see [mdn].
260 ///
261 /// If you need more flexibility, you can use supply a function which can
262 /// dynamically decide the max-age based on the origin and other parts of
263 /// each preflight request:
264 ///
265 /// ```
266 /// # struct MyServerConfig { cors_max_age: Duration }
267 /// use std::time::Duration;
268 ///
269 /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue};
270 /// use rama_http::layer::cors::{CorsLayer, MaxAge};
271 ///
272 /// let layer = CorsLayer::new().max_age(MaxAge::dynamic(
273 /// |_origin: &HeaderValue, parts: &RequestParts| -> Duration {
274 /// // Let's say you want to be able to reload your config at
275 /// // runtime and have another middleware that always inserts
276 /// // the current config into the request extensions
277 /// let config = parts.extensions.get::<MyServerConfig>().unwrap();
278 /// config.cors_max_age
279 /// },
280 /// ));
281 /// ```
282 ///
283 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
284 pub fn max_age<T>(mut self, max_age: T) -> Self
285 where
286 T: Into<MaxAge>,
287 {
288 self.max_age = max_age.into();
289 self
290 }
291
292 /// Set the value of the [`Access-Control-Allow-Methods`][mdn] header.
293 ///
294 /// ```
295 /// use rama_http::layer::cors::CorsLayer;
296 /// use rama_http::Method;
297 ///
298 /// let layer = CorsLayer::new().allow_methods([Method::GET, Method::POST]);
299 /// ```
300 ///
301 /// All methods can be allowed with
302 ///
303 /// ```
304 /// use rama_http::layer::cors::{Any, CorsLayer};
305 ///
306 /// let layer = CorsLayer::new().allow_methods(Any);
307 /// ```
308 ///
309 /// Note that multiple calls to this method will override any previous
310 /// calls.
311 ///
312 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
313 pub fn allow_methods<T>(mut self, methods: T) -> Self
314 where
315 T: Into<AllowMethods>,
316 {
317 self.allow_methods = methods.into();
318 self
319 }
320
321 /// Set the value of the [`Access-Control-Allow-Origin`][mdn] header.
322 ///
323 /// ```
324 /// use rama_http::HeaderValue;
325 /// use rama_http::layer::cors::CorsLayer;
326 ///
327 /// let layer = CorsLayer::new().allow_origin(
328 /// "http://example.com".parse::<HeaderValue>().unwrap(),
329 /// );
330 /// ```
331 ///
332 /// Multiple origins can be allowed with
333 ///
334 /// ```
335 /// use rama_http::layer::cors::CorsLayer;
336 ///
337 /// let origins = [
338 /// "http://example.com".parse().unwrap(),
339 /// "http://api.example.com".parse().unwrap(),
340 /// ];
341 ///
342 /// let layer = CorsLayer::new().allow_origin(origins);
343 /// ```
344 ///
345 /// All origins can be allowed with
346 ///
347 /// ```
348 /// use rama_http::layer::cors::{Any, CorsLayer};
349 ///
350 /// let layer = CorsLayer::new().allow_origin(Any);
351 /// ```
352 ///
353 /// You can also use a closure
354 ///
355 /// ```
356 /// use rama_http::layer::cors::{CorsLayer, AllowOrigin};
357 /// use rama_http::dep::http::{request::Parts as RequestParts, HeaderValue};
358 ///
359 /// let layer = CorsLayer::new().allow_origin(AllowOrigin::predicate(
360 /// |origin: &HeaderValue, _request_parts: &RequestParts| {
361 /// origin.as_bytes().ends_with(b".rust-lang.org")
362 /// },
363 /// ));
364 /// ```
365 ///
366 /// Note that multiple calls to this method will override any previous
367 /// calls.
368 ///
369 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
370 pub fn allow_origin<T>(mut self, origin: T) -> Self
371 where
372 T: Into<AllowOrigin>,
373 {
374 self.allow_origin = origin.into();
375 self
376 }
377
378 /// Set the value of the [`Access-Control-Expose-Headers`][mdn] header.
379 ///
380 /// ```
381 /// use rama_http::layer::cors::CorsLayer;
382 /// use rama_http::header::CONTENT_ENCODING;
383 ///
384 /// let layer = CorsLayer::new().expose_headers([CONTENT_ENCODING]);
385 /// ```
386 ///
387 /// All headers can be allowed with
388 ///
389 /// ```
390 /// use rama_http::layer::cors::{Any, CorsLayer};
391 ///
392 /// let layer = CorsLayer::new().expose_headers(Any);
393 /// ```
394 ///
395 /// Note that multiple calls to this method will override any previous
396 /// calls.
397 ///
398 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
399 pub fn expose_headers<T>(mut self, headers: T) -> Self
400 where
401 T: Into<ExposeHeaders>,
402 {
403 self.expose_headers = headers.into();
404 self
405 }
406
407 /// Set the value of the [`Access-Control-Allow-Private-Network`][wicg] header.
408 ///
409 /// ```
410 /// use rama_http::layer::cors::CorsLayer;
411 ///
412 /// let layer = CorsLayer::new().allow_private_network(true);
413 /// ```
414 ///
415 /// [wicg]: https://wicg.github.io/private-network-access/
416 pub fn allow_private_network<T>(mut self, allow_private_network: T) -> Self
417 where
418 T: Into<AllowPrivateNetwork>,
419 {
420 self.allow_private_network = allow_private_network.into();
421 self
422 }
423
424 /// Set the value(s) of the [`Vary`][mdn] header.
425 ///
426 /// In contrast to the other headers, this one has a non-empty default of
427 /// [`preflight_request_headers()`].
428 ///
429 /// You only need to set this is you want to remove some of these defaults,
430 /// or if you use a closure for one of the other headers and want to add a
431 /// vary header accordingly.
432 ///
433 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
434 pub fn vary<T>(mut self, headers: T) -> Self
435 where
436 T: Into<Vary>,
437 {
438 self.vary = headers.into();
439 self
440 }
441}
442
443/// Represents a wildcard value (`*`) used with some CORS headers such as
444/// [`CorsLayer::allow_methods`].
445#[derive(Debug, Clone, Copy)]
446#[must_use]
447pub struct Any;
448
449/// Represents a wildcard value (`*`) used with some CORS headers such as
450/// [`CorsLayer::allow_methods`].
451#[deprecated = "Use Any as a unit struct literal instead"]
452pub fn any() -> Any {
453 Any
454}
455
456fn separated_by_commas<I>(mut iter: I) -> Option<HeaderValue>
457where
458 I: Iterator<Item = HeaderValue>,
459{
460 match iter.next() {
461 Some(fst) => {
462 let mut result = BytesMut::from(fst.as_bytes());
463 for val in iter {
464 result.reserve(val.len() + 1);
465 result.put_u8(b',');
466 result.extend_from_slice(val.as_bytes());
467 }
468
469 Some(HeaderValue::from_maybe_shared(result.freeze()).unwrap())
470 }
471 None => None,
472 }
473}
474
475impl Default for CorsLayer {
476 fn default() -> Self {
477 Self::new()
478 }
479}
480
481impl<S> Layer<S> for CorsLayer {
482 type Service = Cors<S>;
483
484 fn layer(&self, inner: S) -> Self::Service {
485 ensure_usable_cors_rules(self);
486 Cors {
487 inner,
488 layer: self.clone(),
489 }
490 }
491
492 fn into_layer(self, inner: S) -> Self::Service {
493 ensure_usable_cors_rules(&self);
494 Cors { inner, layer: self }
495 }
496}
497
498/// Middleware which adds headers for [CORS][mdn].
499///
500/// See the [module docs](crate::layer::cors) for an example.
501///
502/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
503pub struct Cors<S> {
504 inner: S,
505 layer: CorsLayer,
506}
507
508impl<S: fmt::Debug> fmt::Debug for Cors<S> {
509 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
510 f.debug_struct("Cors")
511 .field("inner", &self.inner)
512 .field("layer", &self.layer)
513 .finish()
514 }
515}
516
517impl<S: Clone> Clone for Cors<S> {
518 fn clone(&self) -> Self {
519 Self {
520 inner: self.inner.clone(),
521 layer: self.layer.clone(),
522 }
523 }
524}
525
526impl<S> Cors<S> {
527 /// Create a new `Cors`.
528 ///
529 /// See [`CorsLayer::new`] for more details.
530 pub fn new(inner: S) -> Self {
531 Self {
532 inner,
533 layer: CorsLayer::new(),
534 }
535 }
536
537 /// A permissive configuration.
538 ///
539 /// See [`CorsLayer::permissive`] for more details.
540 pub fn permissive(inner: S) -> Self {
541 Self {
542 inner,
543 layer: CorsLayer::permissive(),
544 }
545 }
546
547 /// A very permissive configuration.
548 ///
549 /// See [`CorsLayer::very_permissive`] for more details.
550 pub fn very_permissive(inner: S) -> Self {
551 Self {
552 inner,
553 layer: CorsLayer::very_permissive(),
554 }
555 }
556
557 define_inner_service_accessors!();
558
559 /// Set the [`Access-Control-Allow-Credentials`][mdn] header.
560 ///
561 /// See [`CorsLayer::allow_credentials`] for more details.
562 ///
563 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
564 pub fn allow_credentials<T>(self, allow_credentials: T) -> Self
565 where
566 T: Into<AllowCredentials>,
567 {
568 self.map_layer(|layer| layer.allow_credentials(allow_credentials))
569 }
570
571 /// Set the value of the [`Access-Control-Allow-Headers`][mdn] header.
572 ///
573 /// See [`CorsLayer::allow_headers`] for more details.
574 ///
575 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
576 pub fn allow_headers<T>(self, headers: T) -> Self
577 where
578 T: Into<AllowHeaders>,
579 {
580 self.map_layer(|layer| layer.allow_headers(headers))
581 }
582
583 /// Set the value of the [`Access-Control-Max-Age`][mdn] header.
584 ///
585 /// See [`CorsLayer::max_age`] for more details.
586 ///
587 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
588 pub fn max_age<T>(self, max_age: T) -> Self
589 where
590 T: Into<MaxAge>,
591 {
592 self.map_layer(|layer| layer.max_age(max_age))
593 }
594
595 /// Set the value of the [`Access-Control-Allow-Methods`][mdn] header.
596 ///
597 /// See [`CorsLayer::allow_methods`] for more details.
598 ///
599 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
600 pub fn allow_methods<T>(self, methods: T) -> Self
601 where
602 T: Into<AllowMethods>,
603 {
604 self.map_layer(|layer| layer.allow_methods(methods))
605 }
606
607 /// Set the value of the [`Access-Control-Allow-Origin`][mdn] header.
608 ///
609 /// See [`CorsLayer::allow_origin`] for more details.
610 ///
611 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
612 pub fn allow_origin<T>(self, origin: T) -> Self
613 where
614 T: Into<AllowOrigin>,
615 {
616 self.map_layer(|layer| layer.allow_origin(origin))
617 }
618
619 /// Set the value of the [`Access-Control-Expose-Headers`][mdn] header.
620 ///
621 /// See [`CorsLayer::expose_headers`] for more details.
622 ///
623 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
624 pub fn expose_headers<T>(self, headers: T) -> Self
625 where
626 T: Into<ExposeHeaders>,
627 {
628 self.map_layer(|layer| layer.expose_headers(headers))
629 }
630
631 /// Set the value of the [`Access-Control-Allow-Private-Network`][wicg] header.
632 ///
633 /// See [`CorsLayer::allow_private_network`] for more details.
634 ///
635 /// [wicg]: https://wicg.github.io/private-network-access/
636 pub fn allow_private_network<T>(self, allow_private_network: T) -> Self
637 where
638 T: Into<AllowPrivateNetwork>,
639 {
640 self.map_layer(|layer| layer.allow_private_network(allow_private_network))
641 }
642
643 fn map_layer<F>(mut self, f: F) -> Self
644 where
645 F: FnOnce(CorsLayer) -> CorsLayer,
646 {
647 self.layer = f(self.layer);
648 self
649 }
650}
651
652impl<S, State, ReqBody, ResBody> Service<State, Request<ReqBody>> for Cors<S>
653where
654 S: Service<State, Request<ReqBody>, Response = Response<ResBody>>,
655 ReqBody: Send + 'static,
656 ResBody: Default + Send + 'static,
657 State: Clone + Send + Sync + 'static,
658{
659 type Response = S::Response;
660 type Error = S::Error;
661
662 async fn serve(
663 &self,
664 ctx: Context<State>,
665 req: Request<ReqBody>,
666 ) -> Result<Self::Response, Self::Error> {
667 let (parts, body) = req.into_parts();
668 let origin = parts.headers.get(&header::ORIGIN);
669
670 let mut headers = HeaderMap::new();
671
672 // These headers are applied to both preflight and subsequent regular CORS requests:
673 // https://fetch.spec.whatwg.org/#http-responses
674 headers.extend(self.layer.allow_credentials.to_header(origin, &parts));
675 headers.extend(self.layer.allow_private_network.to_header(origin, &parts));
676 headers.extend(self.layer.vary.to_header());
677
678 let allow_origin_future = self.layer.allow_origin.to_future(origin, &parts);
679 headers.extend(allow_origin_future.await);
680
681 // Return results immediately upon preflight request
682 if parts.method == Method::OPTIONS {
683 // These headers are applied only to preflight requests
684 headers.extend(self.layer.allow_methods.to_header(&parts));
685 headers.extend(self.layer.allow_headers.to_header(&parts));
686 headers.extend(self.layer.max_age.to_header(origin, &parts));
687
688 let mut response = Response::new(ResBody::default());
689 mem::swap(response.headers_mut(), &mut headers);
690
691 Ok(response)
692 } else {
693 // This header is applied only to non-preflight requests
694 headers.extend(self.layer.expose_headers.to_header(&parts));
695
696 let req = Request::from_parts(parts, body);
697
698 let mut response: Response<ResBody> = self.inner.serve(ctx, req).await?;
699 let response_headers = response.headers_mut();
700
701 // vary header can have multiple values, don't overwrite
702 // previously-set value(s).
703 if let Some(vary) = headers.remove(header::VARY) {
704 response_headers.append(header::VARY, vary);
705 }
706 // extend will overwrite previous headers of remaining names
707 response_headers.extend(headers.drain());
708
709 Ok(response)
710 }
711 }
712}
713
714fn ensure_usable_cors_rules(layer: &CorsLayer) {
715 if layer.allow_credentials.is_true() {
716 assert!(
717 !layer.allow_headers.is_wildcard(),
718 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
719 with `Access-Control-Allow-Headers: *`"
720 );
721
722 assert!(
723 !layer.allow_methods.is_wildcard(),
724 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
725 with `Access-Control-Allow-Methods: *`"
726 );
727
728 assert!(
729 !layer.allow_origin.is_wildcard(),
730 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
731 with `Access-Control-Allow-Origin: *`"
732 );
733
734 assert!(
735 !layer.expose_headers.is_wildcard(),
736 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
737 with `Access-Control-Expose-Headers: *`"
738 );
739 }
740}
741
742/// Returns an iterator over the three request headers that may be involved in a CORS preflight request.
743///
744/// This is the default set of header names returned in the `vary` header
745pub fn preflight_request_headers() -> impl Iterator<Item = HeaderName> {
746 #[allow(deprecated)] // Can be changed when MSRV >= 1.53
747 array::IntoIter::new([
748 header::ORIGIN,
749 header::ACCESS_CONTROL_REQUEST_METHOD,
750 header::ACCESS_CONTROL_REQUEST_HEADERS,
751 ])
752}