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.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 header::{self, HeaderName},
51 HeaderMap, HeaderValue, Method, Request, Response,
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
487 Cors {
488 inner,
489 layer: self.clone(),
490 }
491 }
492}
493
494/// Middleware which adds headers for [CORS][mdn].
495///
496/// See the [module docs](crate::layer::cors) for an example.
497///
498/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
499pub struct Cors<S> {
500 inner: S,
501 layer: CorsLayer,
502}
503
504impl<S: fmt::Debug> fmt::Debug for Cors<S> {
505 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
506 f.debug_struct("Cors")
507 .field("inner", &self.inner)
508 .field("layer", &self.layer)
509 .finish()
510 }
511}
512
513impl<S: Clone> Clone for Cors<S> {
514 fn clone(&self) -> Self {
515 Self {
516 inner: self.inner.clone(),
517 layer: self.layer.clone(),
518 }
519 }
520}
521
522impl<S> Cors<S> {
523 /// Create a new `Cors`.
524 ///
525 /// See [`CorsLayer::new`] for more details.
526 pub fn new(inner: S) -> Self {
527 Self {
528 inner,
529 layer: CorsLayer::new(),
530 }
531 }
532
533 /// A permissive configuration.
534 ///
535 /// See [`CorsLayer::permissive`] for more details.
536 pub fn permissive(inner: S) -> Self {
537 Self {
538 inner,
539 layer: CorsLayer::permissive(),
540 }
541 }
542
543 /// A very permissive configuration.
544 ///
545 /// See [`CorsLayer::very_permissive`] for more details.
546 pub fn very_permissive(inner: S) -> Self {
547 Self {
548 inner,
549 layer: CorsLayer::very_permissive(),
550 }
551 }
552
553 define_inner_service_accessors!();
554
555 /// Set the [`Access-Control-Allow-Credentials`][mdn] header.
556 ///
557 /// See [`CorsLayer::allow_credentials`] for more details.
558 ///
559 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials
560 pub fn allow_credentials<T>(self, allow_credentials: T) -> Self
561 where
562 T: Into<AllowCredentials>,
563 {
564 self.map_layer(|layer| layer.allow_credentials(allow_credentials))
565 }
566
567 /// Set the value of the [`Access-Control-Allow-Headers`][mdn] header.
568 ///
569 /// See [`CorsLayer::allow_headers`] for more details.
570 ///
571 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
572 pub fn allow_headers<T>(self, headers: T) -> Self
573 where
574 T: Into<AllowHeaders>,
575 {
576 self.map_layer(|layer| layer.allow_headers(headers))
577 }
578
579 /// Set the value of the [`Access-Control-Max-Age`][mdn] header.
580 ///
581 /// See [`CorsLayer::max_age`] for more details.
582 ///
583 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Max-Age
584 pub fn max_age<T>(self, max_age: T) -> Self
585 where
586 T: Into<MaxAge>,
587 {
588 self.map_layer(|layer| layer.max_age(max_age))
589 }
590
591 /// Set the value of the [`Access-Control-Allow-Methods`][mdn] header.
592 ///
593 /// See [`CorsLayer::allow_methods`] for more details.
594 ///
595 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
596 pub fn allow_methods<T>(self, methods: T) -> Self
597 where
598 T: Into<AllowMethods>,
599 {
600 self.map_layer(|layer| layer.allow_methods(methods))
601 }
602
603 /// Set the value of the [`Access-Control-Allow-Origin`][mdn] header.
604 ///
605 /// See [`CorsLayer::allow_origin`] for more details.
606 ///
607 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
608 pub fn allow_origin<T>(self, origin: T) -> Self
609 where
610 T: Into<AllowOrigin>,
611 {
612 self.map_layer(|layer| layer.allow_origin(origin))
613 }
614
615 /// Set the value of the [`Access-Control-Expose-Headers`][mdn] header.
616 ///
617 /// See [`CorsLayer::expose_headers`] for more details.
618 ///
619 /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers
620 pub fn expose_headers<T>(self, headers: T) -> Self
621 where
622 T: Into<ExposeHeaders>,
623 {
624 self.map_layer(|layer| layer.expose_headers(headers))
625 }
626
627 /// Set the value of the [`Access-Control-Allow-Private-Network`][wicg] header.
628 ///
629 /// See [`CorsLayer::allow_private_network`] for more details.
630 ///
631 /// [wicg]: https://wicg.github.io/private-network-access/
632 pub fn allow_private_network<T>(self, allow_private_network: T) -> Self
633 where
634 T: Into<AllowPrivateNetwork>,
635 {
636 self.map_layer(|layer| layer.allow_private_network(allow_private_network))
637 }
638
639 fn map_layer<F>(mut self, f: F) -> Self
640 where
641 F: FnOnce(CorsLayer) -> CorsLayer,
642 {
643 self.layer = f(self.layer);
644 self
645 }
646}
647
648impl<S, State, ReqBody, ResBody> Service<State, Request<ReqBody>> for Cors<S>
649where
650 S: Service<State, Request<ReqBody>, Response = Response<ResBody>>,
651 ReqBody: Send + 'static,
652 ResBody: Default + Send + 'static,
653 State: Clone + Send + Sync + 'static,
654{
655 type Response = S::Response;
656 type Error = S::Error;
657
658 async fn serve(
659 &self,
660 ctx: Context<State>,
661 req: Request<ReqBody>,
662 ) -> Result<Self::Response, Self::Error> {
663 let (parts, body) = req.into_parts();
664 let origin = parts.headers.get(&header::ORIGIN);
665
666 let mut headers = HeaderMap::new();
667
668 // These headers are applied to both preflight and subsequent regular CORS requests:
669 // https://fetch.spec.whatwg.org/#http-responses
670 headers.extend(self.layer.allow_credentials.to_header(origin, &parts));
671 headers.extend(self.layer.allow_private_network.to_header(origin, &parts));
672 headers.extend(self.layer.vary.to_header());
673
674 let allow_origin_future = self.layer.allow_origin.to_future(origin, &parts);
675 headers.extend(allow_origin_future.await);
676
677 // Return results immediately upon preflight request
678 if parts.method == Method::OPTIONS {
679 // These headers are applied only to preflight requests
680 headers.extend(self.layer.allow_methods.to_header(&parts));
681 headers.extend(self.layer.allow_headers.to_header(&parts));
682 headers.extend(self.layer.max_age.to_header(origin, &parts));
683
684 let mut response = Response::new(ResBody::default());
685 mem::swap(response.headers_mut(), &mut headers);
686
687 Ok(response)
688 } else {
689 // This header is applied only to non-preflight requests
690 headers.extend(self.layer.expose_headers.to_header(&parts));
691
692 let req = Request::from_parts(parts, body);
693
694 let mut response: Response<ResBody> = self.inner.serve(ctx, req).await?;
695 let response_headers = response.headers_mut();
696
697 // vary header can have multiple values, don't overwrite
698 // previously-set value(s).
699 if let Some(vary) = headers.remove(header::VARY) {
700 response_headers.append(header::VARY, vary);
701 }
702 // extend will overwrite previous headers of remaining names
703 response_headers.extend(headers.drain());
704
705 Ok(response)
706 }
707 }
708}
709
710fn ensure_usable_cors_rules(layer: &CorsLayer) {
711 if layer.allow_credentials.is_true() {
712 assert!(
713 !layer.allow_headers.is_wildcard(),
714 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
715 with `Access-Control-Allow-Headers: *`"
716 );
717
718 assert!(
719 !layer.allow_methods.is_wildcard(),
720 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
721 with `Access-Control-Allow-Methods: *`"
722 );
723
724 assert!(
725 !layer.allow_origin.is_wildcard(),
726 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
727 with `Access-Control-Allow-Origin: *`"
728 );
729
730 assert!(
731 !layer.expose_headers.is_wildcard(),
732 "Invalid CORS configuration: Cannot combine `Access-Control-Allow-Credentials: true` \
733 with `Access-Control-Expose-Headers: *`"
734 );
735 }
736}
737
738/// Returns an iterator over the three request headers that may be involved in a CORS preflight request.
739///
740/// This is the default set of header names returned in the `vary` header
741pub fn preflight_request_headers() -> impl Iterator<Item = HeaderName> {
742 #[allow(deprecated)] // Can be changed when MSRV >= 1.53
743 array::IntoIter::new([
744 header::ORIGIN,
745 header::ACCESS_CONTROL_REQUEST_METHOD,
746 header::ACCESS_CONTROL_REQUEST_HEADERS,
747 ])
748}