Skip to content

Commit 923857b

Browse files
authored
Merge pull request #853 from puhrez/origin-0.9.x
feat(headers): Origin Header 0.9.x
2 parents b47affd + 64881ae commit 923857b

File tree

3 files changed

+146
-38
lines changed

3 files changed

+146
-38
lines changed

src/header/common/host.rs

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use header::{Header, HeaderFormat};
22
use std::fmt;
3+
use std::str::FromStr;
34
use header::parsing::from_one_raw_str;
5+
use url::idna::domain_to_unicode;
46

57
/// The `Host` header.
68
///
@@ -47,44 +49,7 @@ impl Header for Host {
4749
}
4850

4951
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Host> {
50-
from_one_raw_str(raw).and_then(|mut s: String| {
51-
// FIXME: use rust-url to parse this
52-
// https://github.com/servo/rust-url/issues/42
53-
let idx = {
54-
let slice = &s[..];
55-
let mut chars = slice.chars();
56-
chars.next();
57-
if chars.next().unwrap() == '[' {
58-
match slice.rfind(']') {
59-
Some(idx) => {
60-
if slice.len() > idx + 2 {
61-
Some(idx + 1)
62-
} else {
63-
None
64-
}
65-
}
66-
None => return Err(::Error::Header) // this is a bad ipv6 address...
67-
}
68-
} else {
69-
slice.rfind(':')
70-
}
71-
};
72-
73-
let port = match idx {
74-
Some(idx) => s[idx + 1..].parse().ok(),
75-
None => None
76-
};
77-
78-
match idx {
79-
Some(idx) => s.truncate(idx),
80-
None => ()
81-
}
82-
83-
Ok(Host {
84-
hostname: s,
85-
port: port
86-
})
87-
})
52+
from_one_raw_str(raw)
8853
}
8954
}
9055

@@ -97,6 +62,35 @@ impl HeaderFormat for Host {
9762
}
9863
}
9964

65+
impl fmt::Display for Host {
66+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67+
self.fmt_header(f)
68+
}
69+
}
70+
71+
impl FromStr for Host {
72+
type Err = ::Error;
73+
74+
fn from_str(s: &str) -> ::Result<Host> {
75+
let (host_port, res) = domain_to_unicode(s);
76+
if res.is_err() {
77+
return Err(::Error::Header)
78+
}
79+
let idx = host_port.rfind(':');
80+
let port = idx.and_then(
81+
|idx| s[idx + 1..].parse().ok()
82+
);
83+
let hostname = match idx {
84+
None => host_port,
85+
Some(idx) => host_port[..idx].to_owned()
86+
};
87+
Ok(Host {
88+
hostname: hostname,
89+
port: port
90+
})
91+
}
92+
}
93+
10094
#[cfg(test)]
10195
mod tests {
10296
use super::Host;

src/header/common/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ pub use self::if_unmodified_since::IfUnmodifiedSince;
4343
pub use self::if_range::IfRange;
4444
pub use self::last_modified::LastModified;
4545
pub use self::location::Location;
46+
pub use self::origin::Origin;
4647
pub use self::pragma::Pragma;
4748
pub use self::prefer::{Prefer, Preference};
4849
pub use self::preference_applied::PreferenceApplied;
@@ -406,6 +407,7 @@ mod if_range;
406407
mod if_unmodified_since;
407408
mod last_modified;
408409
mod location;
410+
mod origin;
409411
mod pragma;
410412
mod prefer;
411413
mod preference_applied;

src/header/common/origin.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use header::{Header, Host, HeaderFormat};
2+
use std::fmt;
3+
use std::str::FromStr;
4+
use header::parsing::from_one_raw_str;
5+
6+
/// The `Origin` header.
7+
///
8+
/// The `Origin` header is a version of the `Referer` header that is used for all HTTP fetches and `POST`s whose CORS flag is set.
9+
/// This header is often used to inform recipients of the security context of where the request was initiated.
10+
///
11+
///
12+
/// Following the spec, https://fetch.spec.whatwg.org/#origin-header, the value of this header is composed of
13+
/// a String (scheme), header::Host (host/port)
14+
///
15+
/// # Examples
16+
/// ```
17+
/// use hyper::header::{Headers, Origin};
18+
///
19+
/// let mut headers = Headers::new();
20+
/// headers.set(
21+
/// Origin::new("http", "hyper.rs", None)
22+
/// );
23+
/// ```
24+
/// ```
25+
/// use hyper::header::{Headers, Origin};
26+
///
27+
/// let mut headers = Headers::new();
28+
/// headers.set(
29+
/// Origin::new("https", "wikipedia.org", Some(443))
30+
/// );
31+
/// ```
32+
33+
#[derive(Clone, Debug)]
34+
pub struct Origin {
35+
/// The scheme, such as http or https
36+
pub scheme: String,
37+
/// The host, such as Host{hostname: "hyper.rs".to_owned(), port: None}
38+
pub host: Host,
39+
}
40+
41+
impl Origin {
42+
pub fn new<S: Into<String>, H: Into<String>>(scheme: S, hostname: H, port: Option<u16>) -> Origin{
43+
Origin {
44+
scheme: scheme.into(),
45+
host: Host {
46+
hostname: hostname.into(),
47+
port: port
48+
}
49+
}
50+
}
51+
}
52+
53+
impl Header for Origin {
54+
fn header_name() -> &'static str {
55+
static NAME: &'static str = "Origin";
56+
NAME
57+
}
58+
59+
fn parse_header(raw: &[Vec<u8>]) -> ::Result<Origin> {
60+
from_one_raw_str(raw)
61+
}
62+
}
63+
64+
impl FromStr for Origin {
65+
type Err = ::Error;
66+
67+
fn from_str(s: &str) -> ::Result<Origin> {
68+
let idx = match s.find("://") {
69+
Some(idx) => idx,
70+
None => return Err(::Error::Header)
71+
};
72+
// idx + 3 because thats how long "://" is
73+
let (scheme, etc) = (&s[..idx], &s[idx + 3..]);
74+
let host = try!(Host::from_str(etc));
75+
76+
77+
Ok(Origin{
78+
scheme: scheme.to_owned(),
79+
host: host
80+
})
81+
}
82+
}
83+
84+
impl HeaderFormat for Origin {
85+
fn fmt_header(&self, f: &mut fmt::Formatter) -> fmt::Result {
86+
write!(f, "{}://{}", self.scheme, self.host)
87+
}
88+
}
89+
90+
impl PartialEq for Origin {
91+
fn eq(&self, other: &Origin) -> bool {
92+
self.scheme == other.scheme && self.host == other.host
93+
}
94+
}
95+
96+
97+
#[cfg(test)]
98+
mod tests {
99+
use super::Origin;
100+
use header::Header;
101+
102+
#[test]
103+
fn test_origin() {
104+
let origin = Header::parse_header([b"http://foo.com".to_vec()].as_ref());
105+
assert_eq!(origin.ok(), Some(Origin::new("http", "foo.com", None)));
106+
107+
let origin = Header::parse_header([b"https://foo.com:443".to_vec()].as_ref());
108+
assert_eq!(origin.ok(), Some(Origin::new("https", "foo.com", Some(443))));
109+
}
110+
}
111+
112+
bench_header!(bench, Origin, { vec![b"https://foo.com".to_vec()] });

0 commit comments

Comments
 (0)