Files
hyper/src/header/common/connection.rs
Sean McArthur c81edd41d7 refactor(lib): update unicase to 2.0
BREAKING CHANGE: Some headers used `UniCase`, but now use
  `unicase::Ascii`. Upgrade code to `Ascii::new(s)`.
2017-05-10 16:14:59 -07:00

144 lines
4.4 KiB
Rust

use std::fmt::{self, Display};
use std::str::FromStr;
use unicase::Ascii;
pub use self::ConnectionOption::{KeepAlive, Close, ConnectionHeader};
static KEEP_ALIVE: &'static str = "keep-alive";
static CLOSE: &'static str = "close";
/// Values that can be in the `Connection` header.
#[derive(Clone, PartialEq, Debug)]
pub enum ConnectionOption {
/// The `keep-alive` connection value.
KeepAlive,
/// The `close` connection value.
Close,
/// Values in the Connection header that are supposed to be names of other Headers.
///
/// > When a header field aside from Connection is used to supply control
/// > information for or about the current connection, the sender MUST list
/// > the corresponding field-name within the Connection header field.
// TODO: it would be nice if these "Strings" could be stronger types, since
// they are supposed to relate to other Header fields (which we have strong
// types for).
ConnectionHeader(Ascii<String>),
}
impl FromStr for ConnectionOption {
type Err = ();
fn from_str(s: &str) -> Result<ConnectionOption, ()> {
if Ascii::new(s) == KEEP_ALIVE {
Ok(KeepAlive)
} else if Ascii::new(s) == CLOSE {
Ok(Close)
} else {
Ok(ConnectionHeader(Ascii::new(s.to_owned())))
}
}
}
impl Display for ConnectionOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(match *self {
KeepAlive => "keep-alive",
Close => "close",
ConnectionHeader(ref s) => s.as_ref()
})
}
}
header! {
/// `Connection` header, defined in
/// [RFC7230](http://tools.ietf.org/html/rfc7230#section-6.1)
///
/// The `Connection` header field allows the sender to indicate desired
/// control options for the current connection. In order to avoid
/// confusing downstream recipients, a proxy or gateway MUST remove or
/// replace any received connection options before forwarding the
/// message.
///
/// # ABNF
/// ```plain
/// Connection = 1#connection-option
/// connection-option = token
///
/// # Example values
/// * `close`
/// * `keep-alive`
/// * `upgrade`
/// ```
///
/// # Examples
/// ```
/// use hyper::header::{Headers, Connection};
///
/// let mut headers = Headers::new();
/// headers.set(Connection::keep_alive());
/// ```
/// ```
/// # extern crate hyper;
/// # extern crate unicase;
/// # fn main() {
/// // extern crate unicase;
///
/// use hyper::header::{Headers, Connection, ConnectionOption};
/// use unicase::Ascii;
///
/// let mut headers = Headers::new();
/// headers.set(
/// Connection(vec![
/// ConnectionOption::ConnectionHeader(Ascii::new("upgrade".to_owned())),
/// ])
/// );
/// # }
/// ```
(Connection, "Connection") => (ConnectionOption)+
test_connection {
test_header!(test1, vec![b"close"]);
test_header!(test2, vec![b"keep-alive"]);
test_header!(test3, vec![b"upgrade"]);
}
}
impl Connection {
/// A constructor to easily create a `Connection: close` header.
#[inline]
pub fn close() -> Connection {
Connection(vec![ConnectionOption::Close])
}
/// A constructor to easily create a `Connection: keep-alive` header.
#[inline]
pub fn keep_alive() -> Connection {
Connection(vec![ConnectionOption::KeepAlive])
}
}
bench_header!(close, Connection, { vec![b"close".to_vec()] });
bench_header!(keep_alive, Connection, { vec![b"keep-alive".to_vec()] });
bench_header!(header, Connection, { vec![b"authorization".to_vec()] });
#[cfg(test)]
mod tests {
use super::{Connection,ConnectionHeader};
use header::Header;
use unicase::Ascii;
fn parse_option(header: Vec<u8>) -> Connection {
let val = header.into();
let connection: Connection = Header::parse_header(&val).unwrap();
connection
}
#[test]
fn test_parse() {
assert_eq!(Connection::close(),parse_option(b"close".to_vec()));
assert_eq!(Connection::keep_alive(),parse_option(b"keep-alive".to_vec()));
assert_eq!(Connection::keep_alive(),parse_option(b"Keep-Alive".to_vec()));
assert_eq!(Connection(vec![ConnectionHeader(Ascii::new("upgrade".to_owned()))]),
parse_option(b"upgrade".to_vec()));
}
}