Skip to content

Basic Cookie and Set-Cookie headers implementation. (WIP) #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ name = "hyper"
version = "0.0.1"
authors = ["Sean McArthur <sean.monstar@gmail.com>"]

[features]
cookie_rs = ["cookie"]
default = ["cookie_rs"]

[dependencies.url]
git = "https://github.com/servo/rust-url"

Expand Down Expand Up @@ -31,3 +35,6 @@ git = "https://github.com/carllerche/curl-rust"
[dev-dependencies.http]
git = "https://github.com/chris-morgan/rust-http"

[dependencies.cookie]
git = "https://github.com/alexcrichton/cookie-rs"
optional = true
84 changes: 84 additions & 0 deletions src/header/common/cookie.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use header::Header;
use std::fmt::{mod, Show};
use std::str::from_utf8;
use std::from_str::FromStr;

#[cfg(feature = "cookie_rs")]
use cookie::Cookie as CookieRs;
#[cfg(feature = "cookie_rs")]
use cookie::CookieJar;

/// The `Cookie` header
///
/// If the user agent does attach a Cookie header field to an HTTP
/// request, the user agent must send the cookie-string
/// as the value of the header field.
///
/// When the user agent generates an HTTP request, the user agent MUST NOT
/// attach more than one Cookie header field.
#[deriving(Clone, PartialEq, Show)]
pub struct TypedCookie<T>(pub Vec<T>);

impl<T: FromStr + Show + Clone + Send + Sync> Header for TypedCookie<T> {
fn header_name(_: Option<TypedCookie<T>>) -> &'static str {
"Cookie"
}

fn parse_header(raw: &[Vec<u8>]) -> Option<TypedCookie<T>> {
let mut cookies: Vec<T> = vec![];
for cookies_raw in raw.iter() {
match from_utf8(cookies_raw.as_slice()) {
Some(cookies_str) => {
for cookie_str in cookies_str.split(';') {
match from_str(cookie_str.trim()) {
Some(cookie) => cookies.push(cookie),
None => return None
}
}
},
None => return None
};
}

if !cookies.is_empty() {
Some(TypedCookie(cookies))
} else {
None
}
}

fn fmt_header(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let TypedCookie(ref value) = *self;
let last = value.len() - 1;
for (i, cookie) in value.iter().enumerate() {
try!(cookie.fmt(fmt));
if i < last {
try!("; ".fmt(fmt));
}
}
Ok(())
}
}

#[cfg(not(feature = "cookie_rs"))]
pub type Cookie = TypedCookie<String>;

#[cfg(feature = "cookie_rs")]
pub type Cookie = TypedCookie<CookieRs>;

#[cfg(feature = "cookie_rs")]
impl Cookie {
/// This method can be used to crate CookieJar that can be used
/// to manipulate cookies and create corresponding `SetCookie` header afterwards.
#[allow(dead_code)]
fn to_cookie_jar(&self, key: &[u8]) -> CookieJar {
let mut jar = CookieJar::new(key);
let &TypedCookie(ref cookies) = self;
for cookie in cookies.iter() {
jar.add_original((*cookie).clone());
}

jar
}
}

6 changes: 6 additions & 0 deletions src/header/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ pub mod date;
/// Exposes the Location header.
pub mod location;

/// Exposes the Cookie header.
pub mod cookie;

/// Exposes the Set-Cookie header.
pub mod set_cookie;

fn from_one_raw_str<T: FromStr>(raw: &[Vec<u8>]) -> Option<T> {
if raw.len() != 1 {
return None;
Expand Down
55 changes: 55 additions & 0 deletions src/header/common/set_cookie.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use header::Header;
use std::fmt;
use std::str::from_utf8;

#[cfg(feature = "cookie_rs")]
use cookie::CookieJar;

/// The `Set-Cookie` header
///
/// Informally, the Set-Cookie response header contains the header name
/// "Set-Cookie" followed by a ":" and a cookie. Each cookie begins with
/// a name-value-pair, followed by zero or more attribute-value pairs.
#[deriving(Clone, PartialEq, Show)]
pub struct SetCookie(pub Vec<String>);

impl Header for SetCookie {
fn header_name(_: Option<SetCookie>) -> &'static str {
"Set-Cookie"
}

fn parse_header(raw: &[Vec<u8>]) -> Option<SetCookie> {
let mut set_cookies: Vec<String> = vec![];
for set_cookies_raw in raw.iter() {
match from_utf8(set_cookies_raw.as_slice()) {
Some(set_cookies_str) => {
if !set_cookies_str.is_empty() {
set_cookies.push(set_cookies_str.to_string());
}
},
None => ()
};
}

if !set_cookies.is_empty() {
Some(SetCookie(set_cookies))
} else {
None
}
}

fn fmt_header(&self, _: &mut fmt::Formatter) -> fmt::Result {
unimplemented!()
}
}

impl SetCookie {
/// Use this to crate SetCookie header from CookieJar using
/// calculated delta.
#[allow(dead_code)]
#[cfg(feature = "cookie_rs")]
fn from_cookie_jar(jar: &CookieJar) -> SetCookie {
SetCookie(jar.delta())
}
}

1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ extern crate "unsafe-any" as uany;
extern crate "move-acceptor" as macceptor;
extern crate intertwine;
extern crate typeable;
#[cfg(feature = "cookie_rs")] extern crate cookie;

pub use std::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr, Port};
pub use mimewrapper::mime;
Expand Down