Merge pull request #502 from pyfisch/accesscontrolalloworigin

feat(headers): Allow `null` value in Access-Control-Allow-Origin
This commit is contained in:
Sean McArthur
2015-05-04 11:13:43 -07:00

View File

@@ -1,11 +1,11 @@
use std::fmt; use std::fmt::{self, Display};
use std::str; use std::str;
use url::Url; use url::Url;
use header; use header::{Header, HeaderFormat};
/// The `Access-Control-Allow-Origin` response header, /// The `Access-Control-Allow-Origin` response header,
/// part of [CORS](www.w3.org/TR/cors/#access-control-allow-origin-response-header) /// part of [CORS](http://www.w3.org/TR/cors/#access-control-allow-origin-response-header)
/// ///
/// The `Access-Control-Allow-Origin` header indicates whether a resource /// The `Access-Control-Allow-Origin` header indicates whether a resource
/// can be shared based by returning the value of the Origin request header, /// can be shared based by returning the value of the Origin request header,
@@ -15,45 +15,60 @@ use header;
/// ```plain /// ```plain
/// Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" origin-list-or-null | "*" /// Access-Control-Allow-Origin = "Access-Control-Allow-Origin" ":" origin-list-or-null | "*"
/// ``` /// ```
// FIXME: The documentation says differently (missing "null" value, "*" not used in practice, ///
// orgin list no list but single value) /// # Example values
/// * `null`
/// * `*`
/// * `http://google.com/`
#[derive(Clone, PartialEq, Debug)] #[derive(Clone, PartialEq, Debug)]
pub enum AccessControlAllowOrigin { pub enum AccessControlAllowOrigin {
/// Allow all origins /// Allow all origins
Any, Any,
/// A hidden origin
Null,
/// Allow one particular origin /// Allow one particular origin
Value(Url), Value(Url),
} }
impl header::Header for AccessControlAllowOrigin { impl Header for AccessControlAllowOrigin {
fn header_name() -> &'static str { fn header_name() -> &'static str {
"Access-Control-Allow-Origin" "Access-Control-Allow-Origin"
} }
fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> { fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> {
if raw.len() == 1 { if raw.len() == 1 {
match str::from_utf8(unsafe { &raw.get_unchecked(0)[..] }) { match unsafe { &raw.get_unchecked(0)[..] } {
Ok(s) => { b"*" => Some(AccessControlAllowOrigin::Any),
if s == "*" { b"null" => Some(AccessControlAllowOrigin::Null),
Some(AccessControlAllowOrigin::Any) r => if let Ok(s) = str::from_utf8(r) {
} else { Url::parse(s).ok().map(|url| AccessControlAllowOrigin::Value(url))
Url::parse(s).ok().map( } else { None }
|url| AccessControlAllowOrigin::Value(url))
}
},
_ => return None,
} }
} else { } else { None }
return None; }
}
impl HeaderFormat for AccessControlAllowOrigin {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AccessControlAllowOrigin::Any => f.write_str("*"),
AccessControlAllowOrigin::Null => f.write_str("null"),
AccessControlAllowOrigin::Value(ref url) => Display::fmt(url, f),
} }
} }
} }
impl header::HeaderFormat for AccessControlAllowOrigin { impl Display for AccessControlAllowOrigin {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self { self.fmt_header(f)
AccessControlAllowOrigin::Any => f.write_str("*"),
AccessControlAllowOrigin::Value(ref url) => fmt::Display::fmt(url, f)
}
} }
} }
#[cfg(test)]
mod test_access_control_allow_orgin {
use header::*;
use super::AccessControlAllowOrigin as HeaderField;
test_header!(test1, vec![b"null"]);
test_header!(test2, vec![b"*"]);
test_header!(test3, vec![b"http://google.com/"]);
}