1 use super::origin::Origin; 2 use util::{IterExt, TryFromValues}; 3 use HeaderValue; 4 5 /// The `Access-Control-Allow-Origin` response header, 6 /// part of [CORS](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header) 7 /// 8 /// The `Access-Control-Allow-Origin` header indicates whether a resource 9 /// can be shared based by returning the value of the Origin request header, 10 /// `*`, or `null` in the response. 11 /// 12 /// ## ABNF 13 /// 14 /// ```text 15 /// Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" origin-list-or-null | "*" 16 /// ``` 17 /// 18 /// ## Example values 19 /// * `null` 20 /// * `*` 21 /// * `http://google.com/` 22 /// 23 /// # Examples 24 /// 25 /// ``` 26 /// # extern crate headers; 27 /// use headers::AccessControlAllowOrigin; 28 /// 29 /// let any_origin = AccessControlAllowOrigin::ANY; 30 /// let null_origin = AccessControlAllowOrigin::NULL; 31 /// ``` 32 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 33 pub struct AccessControlAllowOrigin(OriginOrAny); 34 35 derive_header! { 36 AccessControlAllowOrigin(_), 37 name: ACCESS_CONTROL_ALLOW_ORIGIN 38 } 39 40 #[derive(Clone, Debug, PartialEq, Eq, Hash)] 41 enum OriginOrAny { 42 Origin(Origin), 43 /// Allow all origins 44 Any, 45 } 46 47 impl AccessControlAllowOrigin { 48 /// `Access-Control-Allow-Origin: *` 49 pub const ANY: AccessControlAllowOrigin = AccessControlAllowOrigin(OriginOrAny::Any); 50 /// `Access-Control-Allow-Origin: null` 51 pub const NULL: AccessControlAllowOrigin = 52 AccessControlAllowOrigin(OriginOrAny::Origin(Origin::NULL)); 53 54 /// Returns the origin if there's one specified. origin(&self) -> Option<&Origin>55 pub fn origin(&self) -> Option<&Origin> { 56 match self.0 { 57 OriginOrAny::Origin(ref origin) => Some(origin), 58 _ => None, 59 } 60 } 61 } 62 63 impl TryFromValues for OriginOrAny { try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error> where I: Iterator<Item = &'i HeaderValue>,64 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error> 65 where 66 I: Iterator<Item = &'i HeaderValue>, 67 { 68 values 69 .just_one() 70 .and_then(|value| { 71 if value == "*" { 72 return Some(OriginOrAny::Any); 73 } 74 75 Origin::try_from_value(value).map(OriginOrAny::Origin) 76 }) 77 .ok_or_else(::Error::invalid) 78 } 79 } 80 81 impl<'a> From<&'a OriginOrAny> for HeaderValue { from(origin: &'a OriginOrAny) -> HeaderValue82 fn from(origin: &'a OriginOrAny) -> HeaderValue { 83 match origin { 84 OriginOrAny::Origin(ref origin) => origin.into_value(), 85 OriginOrAny::Any => HeaderValue::from_static("*"), 86 } 87 } 88 } 89 90 #[cfg(test)] 91 mod tests { 92 use super::super::{test_decode, test_encode}; 93 use super::*; 94 95 #[test] origin()96 fn origin() { 97 let s = "http://web-platform.test:8000"; 98 let allow_origin = test_decode::<AccessControlAllowOrigin>(&[s]).unwrap(); 99 { 100 let origin = allow_origin.origin().unwrap(); 101 assert_eq!(origin.scheme(), "http"); 102 assert_eq!(origin.hostname(), "web-platform.test"); 103 assert_eq!(origin.port(), Some(8000)); 104 } 105 106 let headers = test_encode(allow_origin); 107 assert_eq!(headers["access-control-allow-origin"], s); 108 } 109 110 #[test] any()111 fn any() { 112 let allow_origin = test_decode::<AccessControlAllowOrigin>(&["*"]).unwrap(); 113 assert_eq!(allow_origin, AccessControlAllowOrigin::ANY); 114 115 let headers = test_encode(allow_origin); 116 assert_eq!(headers["access-control-allow-origin"], "*"); 117 } 118 119 #[test] null()120 fn null() { 121 let allow_origin = test_decode::<AccessControlAllowOrigin>(&["null"]).unwrap(); 122 assert_eq!(allow_origin, AccessControlAllowOrigin::NULL); 123 124 let headers = test_encode(allow_origin); 125 assert_eq!(headers["access-control-allow-origin"], "null"); 126 } 127 } 128