1use crate::{Error, Headers, Method, Result};
2
3#[derive(Debug, Clone)]
5pub struct Cors {
6 credentials: bool,
7 max_age: Option<u32>,
8 origins: Vec<String>,
9 methods: Vec<Method>,
10 allowed_headers: Vec<String>,
11 exposed_headers: Vec<String>,
12}
13
14impl Default for Cors {
16 fn default() -> Self {
17 Self {
18 credentials: false,
19 max_age: None,
20 origins: vec![],
21 methods: vec![],
22 allowed_headers: vec![],
23 exposed_headers: vec![],
24 }
25 }
26}
27
28impl Cors {
29 pub fn new() -> Self {
31 Self::default()
32 }
33
34 pub fn with_credentials(mut self, credentials: bool) -> Self {
36 self.credentials = credentials;
37 self
38 }
39
40 pub fn with_max_age(mut self, max_age: u32) -> Self {
42 self.max_age = Some(max_age);
43 self
44 }
45
46 pub fn with_origins<S: Into<String>, V: IntoIterator<Item = S>>(mut self, origins: V) -> Self {
48 self.origins = origins
49 .into_iter()
50 .map(|item| item.into())
51 .collect::<Vec<String>>();
52 self
53 }
54
55 pub fn with_methods<V: IntoIterator<Item = Method>>(mut self, methods: V) -> Self {
57 self.methods = methods.into_iter().collect();
58 self
59 }
60
61 pub fn with_allowed_headers<S: Into<String>, V: IntoIterator<Item = S>>(
63 mut self,
64 headers: V,
65 ) -> Self {
66 self.allowed_headers = headers
67 .into_iter()
68 .map(|item| item.into())
69 .collect::<Vec<String>>();
70 self
71 }
72
73 pub fn with_exposed_headers<S: Into<String>, V: IntoIterator<Item = S>>(
75 mut self,
76 headers: V,
77 ) -> Self {
78 self.exposed_headers = headers
79 .into_iter()
80 .map(|item| item.into())
81 .collect::<Vec<String>>();
82 self
83 }
84
85 pub fn apply_headers(&self, headers: &mut Headers) -> Result<()> {
87 if self.credentials {
88 headers.set("Access-Control-Allow-Credentials", "true")?;
89 }
90 if let Some(ref max_age) = self.max_age {
91 headers.set("Access-Control-Max-Age", format!("{max_age}").as_str())?;
92 }
93 if !self.origins.is_empty() {
94 headers.set(
95 "Access-Control-Allow-Origin",
96 concat_vec_to_string(self.origins.as_slice())?.as_str(),
97 )?;
98 }
99 if !self.methods.is_empty() {
100 headers.set(
101 "Access-Control-Allow-Methods",
102 concat_vec_to_string(self.methods.as_slice())?.as_str(),
103 )?;
104 }
105 if !self.allowed_headers.is_empty() {
106 headers.set(
107 "Access-Control-Allow-Headers",
108 concat_vec_to_string(self.allowed_headers.as_slice())?.as_str(),
109 )?;
110 }
111 if !self.exposed_headers.is_empty() {
112 headers.set(
113 "Access-Control-Expose-headers",
114 concat_vec_to_string(self.exposed_headers.as_slice())?.as_str(),
115 )?;
116 }
117 Ok(())
118 }
119}
120
121fn concat_vec_to_string<S: AsRef<str>>(vec: &[S]) -> Result<String> {
122 let str = vec.iter().fold("".to_owned(), |mut init, item| {
123 init.push(',');
124 init.push_str(item.as_ref());
125 init
126 });
127 if !str.is_empty() {
128 Ok(str[1..].to_string())
129 } else {
130 Err(Error::RustError(
131 "Tried to concat header values without values.".to_string(),
132 ))
133 }
134}