From c93cdb290875cb86900e84c333725aefa4d7fad5 Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Wed, 6 Dec 2017 16:09:00 -0800 Subject: [PATCH] feat(headers): Implement ProxyAuthorization (#1394) --- src/header/common/mod.rs | 2 + src/header/common/proxy_authorization.rs | 191 +++++++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 src/header/common/proxy_authorization.rs diff --git a/src/header/common/mod.rs b/src/header/common/mod.rs index 5718f5b97f..bcedeae7a2 100644 --- a/src/header/common/mod.rs +++ b/src/header/common/mod.rs @@ -50,6 +50,7 @@ pub use self::origin::Origin; pub use self::pragma::Pragma; pub use self::prefer::{Prefer, Preference}; pub use self::preference_applied::PreferenceApplied; +pub use self::proxy_authorization::ProxyAuthorization; pub use self::range::{Range, ByteRangeSpec}; pub use self::referer::Referer; pub use self::referrer_policy::ReferrerPolicy; @@ -485,6 +486,7 @@ mod origin; mod pragma; mod prefer; mod preference_applied; +mod proxy_authorization; mod range; mod referer; mod referrer_policy; diff --git a/src/header/common/proxy_authorization.rs b/src/header/common/proxy_authorization.rs new file mode 100644 index 0000000000..32c0bdfc08 --- /dev/null +++ b/src/header/common/proxy_authorization.rs @@ -0,0 +1,191 @@ +use std::any::Any; +use std::fmt; +use std::str::{FromStr, from_utf8}; +use std::ops::{Deref, DerefMut}; +use header::{Header, Raw, Scheme}; + +/// `Proxy-Authorization` header, defined in [RFC7235](https://tools.ietf.org/html/rfc7235#section-4.4) +/// +/// The `Proxy-Authorization` header field allows a user agent to authenticate +/// itself with an HTTP proxy -- usually, but not necessarily, after +/// receiving a 407 (Proxy Authentication Required) response and the +/// `Proxy-Authenticate` header. Its value consists of credentials containing +/// the authentication information of the user agent for the realm of the +/// resource being requested. +/// +/// # ABNF +/// +/// ```text +/// Authorization = credentials +/// ``` +/// +/// # Example values +/// * `Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==` +/// * `Bearer fpKL54jvWmEGVoRdCNjG` +/// +/// # Examples +/// +/// ``` +/// use hyper::header::{Headers, ProxyAuthorization}; +/// +/// let mut headers = Headers::new(); +/// headers.set(ProxyAuthorization("let me in".to_owned())); +/// ``` +/// ``` +/// use hyper::header::{Headers, ProxyAuthorization, Basic}; +/// +/// let mut headers = Headers::new(); +/// headers.set( +/// ProxyAuthorization( +/// Basic { +/// username: "Aladdin".to_owned(), +/// password: Some("open sesame".to_owned()) +/// } +/// ) +/// ); +/// ``` +/// +/// ``` +/// use hyper::header::{Headers, ProxyAuthorization, Bearer}; +/// +/// let mut headers = Headers::new(); +/// headers.set( +/// ProxyAuthorization( +/// Bearer { +/// token: "QWxhZGRpbjpvcGVuIHNlc2FtZQ".to_owned() +/// } +/// ) +/// ); +/// ``` +#[derive(Clone, PartialEq, Debug)] +pub struct ProxyAuthorization(pub S); + +impl Deref for ProxyAuthorization { + type Target = S; + + fn deref(&self) -> &S { + &self.0 + } +} + +impl DerefMut for ProxyAuthorization { + fn deref_mut(&mut self) -> &mut S { + &mut self.0 + } +} + +impl Header for ProxyAuthorization where ::Err: 'static { + fn header_name() -> &'static str { + static NAME: &'static str = "Proxy-Authorization"; + NAME + } + + fn parse_header(raw: &Raw) -> ::Result> { + if let Some(line) = raw.one() { + let header = try!(from_utf8(line)); + if let Some(scheme) = ::scheme() { + if header.starts_with(scheme) && header.len() > scheme.len() + 1 { + match header[scheme.len() + 1..].parse::().map(ProxyAuthorization) { + Ok(h) => Ok(h), + Err(_) => Err(::Error::Header) + } + } else { + Err(::Error::Header) + } + } else { + match header.parse::().map(ProxyAuthorization) { + Ok(h) => Ok(h), + Err(_) => Err(::Error::Header) + } + } + } else { + Err(::Error::Header) + } + } + + fn fmt_header(&self, f: &mut ::header::Formatter) -> fmt::Result { + f.fmt_line(self) + } +} + +impl fmt::Display for ProxyAuthorization { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some(scheme) = ::scheme() { + try!(write!(f, "{} ", scheme)) + }; + self.0.fmt_scheme(f) + } +} + +#[cfg(test)] +mod tests { + use super::ProxyAuthorization; + use super::super::super::{Headers, Header, Basic, Bearer}; + + #[test] + fn test_raw_auth() { + let mut headers = Headers::new(); + headers.set(ProxyAuthorization("foo bar baz".to_owned())); + assert_eq!(headers.to_string(), "Proxy-Authorization: foo bar baz\r\n".to_owned()); + } + + #[test] + fn test_raw_auth_parse() { + let header: ProxyAuthorization = Header::parse_header(&b"foo bar baz".as_ref().into()).unwrap(); + assert_eq!(header.0, "foo bar baz"); + } + + #[test] + fn test_basic_auth() { + let mut headers = Headers::new(); + headers.set(ProxyAuthorization( + Basic { username: "Aladdin".to_owned(), password: Some("open sesame".to_owned()) })); + assert_eq!( + headers.to_string(), + "Proxy-Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==\r\n".to_owned()); + } + + #[test] + fn test_basic_auth_no_password() { + let mut headers = Headers::new(); + headers.set(ProxyAuthorization(Basic { username: "Aladdin".to_owned(), password: None })); + assert_eq!(headers.to_string(), "Proxy-Authorization: Basic QWxhZGRpbjo=\r\n".to_owned()); + } + + #[test] + fn test_basic_auth_parse() { + let auth: ProxyAuthorization = Header::parse_header( + &b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==".as_ref().into()).unwrap(); + assert_eq!(auth.0.username, "Aladdin"); + assert_eq!(auth.0.password, Some("open sesame".to_owned())); + } + + #[test] + fn test_basic_auth_parse_no_password() { + let auth: ProxyAuthorization = Header::parse_header( + &b"Basic QWxhZGRpbjo=".as_ref().into()).unwrap(); + assert_eq!(auth.0.username, "Aladdin"); + assert_eq!(auth.0.password, Some("".to_owned())); + } + + #[test] + fn test_bearer_auth() { + let mut headers = Headers::new(); + headers.set(ProxyAuthorization( + Bearer { token: "fpKL54jvWmEGVoRdCNjG".to_owned() })); + assert_eq!( + headers.to_string(), + "Proxy-Authorization: Bearer fpKL54jvWmEGVoRdCNjG\r\n".to_owned()); + } + + #[test] + fn test_bearer_auth_parse() { + let auth: ProxyAuthorization = Header::parse_header( + &b"Bearer fpKL54jvWmEGVoRdCNjG".as_ref().into()).unwrap(); + assert_eq!(auth.0.token, "fpKL54jvWmEGVoRdCNjG"); + } +} + +bench_header!(raw, ProxyAuthorization, { vec![b"foo bar baz".to_vec()] }); +bench_header!(basic, ProxyAuthorization, { vec![b"Basic QWxhZGRpbjpuIHNlc2FtZQ==".to_vec()] }); +bench_header!(bearer, ProxyAuthorization, { vec![b"Bearer fpKL54jvWmEGVoRdCNjG".to_vec()] });