Skip to content

Commit

Permalink
feat(headers): Allow null value in Access-Control-Allow-Origin
Browse files Browse the repository at this point in the history
The spec says the header can be either a `*`, `null` or an URL.
Improve docs of header.

BREAKING CHANGE: Add variant to Access-Control-Allow-Origin enum
  • Loading branch information
pyfisch committed May 3, 2015
1 parent b916a7b commit 5e34171
Showing 1 changed file with 36 additions and 21 deletions.
57 changes: 36 additions & 21 deletions src/header/common/access_control_allow_origin.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use std::fmt;
use std::fmt::{self, Display};
use std::str;

use url::Url;
use header;
use header::{Header, HeaderFormat};

/// 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
/// can be shared based by returning the value of the Origin request header,
Expand All @@ -15,45 +15,60 @@ use header;
/// ```plain
/// 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)]
pub enum AccessControlAllowOrigin {
/// Allow all origins
Any,
/// A hidden origin
Null,
/// Allow one particular origin
Value(Url),
}

impl header::Header for AccessControlAllowOrigin {
impl Header for AccessControlAllowOrigin {
fn header_name() -> &'static str {
"Access-Control-Allow-Origin"
}

fn parse_header(raw: &[Vec<u8>]) -> Option<AccessControlAllowOrigin> {
if raw.len() == 1 {
match str::from_utf8(unsafe { &raw.get_unchecked(0)[..] }) {
Ok(s) => {
if s == "*" {
Some(AccessControlAllowOrigin::Any)
} else {
Url::parse(s).ok().map(
|url| AccessControlAllowOrigin::Value(url))
}
},
_ => return None,
match unsafe { &raw.get_unchecked(0)[..] } {
b"*" => Some(AccessControlAllowOrigin::Any),
b"null" => Some(AccessControlAllowOrigin::Null),
r => if let Ok(s) = str::from_utf8(r) {
Url::parse(s).ok().map(|url| AccessControlAllowOrigin::Value(url))
} else { None }
}
} else {
return None;
}
} else { None }
}
}

impl header::HeaderFormat for AccessControlAllowOrigin {
impl HeaderFormat for AccessControlAllowOrigin {
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
AccessControlAllowOrigin::Any => f.write_str("*"),
AccessControlAllowOrigin::Value(ref url) => fmt::Display::fmt(url, f)
AccessControlAllowOrigin::Null => f.write_str("null"),
AccessControlAllowOrigin::Value(ref url) => Display::fmt(url, f),
}
}
}

impl Display for AccessControlAllowOrigin {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
self.fmt_header(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/"]);
}

0 comments on commit 5e34171

Please sign in to comment.