Update to Hyper 0.10. Use cookie crate directly.

A few interesting notes on this breakage:

  * `Cookie` how has a lifetime. It should be `'static'` everywhere.
  * The `SetCookie` header is no longer reexported.
  * Instead, `Cookie` implements `Into<Header>` for Set-Cookie.
This commit is contained in:
Sergio Benitez 2017-01-26 23:08:15 -08:00
parent 8fd19cce4f
commit 06a7317fd9
14 changed files with 144 additions and 77 deletions

View File

@ -6,7 +6,6 @@ workspace = "../../"
[dependencies]
rocket = { path = "../../lib" }
rocket_codegen = { path = "../../codegen" }
lazy_static = "*"
[dependencies.rocket_contrib]
path = "../../contrib"

View File

@ -1,8 +1,6 @@
#![feature(plugin, custom_derive, custom_attribute)]
#![plugin(rocket_codegen)]
#[macro_use]
extern crate lazy_static;
extern crate rocket_contrib;
extern crate rocket;
@ -23,15 +21,16 @@ struct Message {
#[post("/submit", data = "<message>")]
fn submit(cookies: &Cookies, message: Form<Message>) -> Redirect {
cookies.add(Cookie::new("message".into(), message.into_inner().message));
cookies.add(Cookie::new("message", message.into_inner().message));
Redirect::to("/")
}
#[get("/")]
fn index(cookies: &Cookies) -> Template {
let cookie = cookies.find("message");
let mut context = HashMap::new();
if let Some(msg) = cookies.find("message").map(|msg| msg.value) {
context.insert("message", msg);
if let Some(ref cookie) = cookie {
context.insert("message", cookie.value());
}
Template::render("index", &context)

View File

@ -20,7 +20,7 @@ fn test_submit() {
assert_eq!(location_headers, vec!["/".to_string()]);
}
fn test_body(optional_cookie: Option<Cookie>, expected_body: String) {
fn test_body(optional_cookie: Option<Cookie<'static>>, expected_body: String) {
let rocket = rocket::ignite().mount("/", routes![super::index]);
let mut request = MockRequest::new(Method::Get, "/");
@ -47,7 +47,7 @@ fn test_index() {
context.insert("message", "Hello from Rocket!");
// Test the route with the "message" cookie.
let cookie = Cookie::new("message".into(), "Hello from Rocket!".into());
let cookie = Cookie::new("message", "Hello from Rocket!");
let template = Template::render("index", &context);
test_body(Some(cookie), template.to_string());
}

View File

@ -18,11 +18,16 @@ build = "build.rs"
term-painter = "^0.2"
log = "^0.3"
url = "^1"
hyper = { version = "=0.9.14", default-features = false }
hyper = { version = "0.10", default-features = false }
toml = { version = "^0.2", default-features = false }
num_cpus = "1"
state = "^0.2"
# cookie = "^0.3"
time = "^0.1"
[dependencies.cookie]
version = "^0.6"
default-features = false
features = ["percent-encode"]
[dev-dependencies]
lazy_static = "0.2"

View File

@ -36,7 +36,7 @@
//! * **port**: _[integer]_ a port number to listen on
//! * examples: `"8000"`, `"80"`, `"4242"`
//! * **workers**: _[integer]_ the number of concurrent workers to use
//! * examples: `"12"`, `"1"`, `"4"`
//! * examples: `12`, `1`, `4`
//! * **log**: _[string]_ how much information to log; one of `"normal"`,
//! `"debug"`, or `"critical"`
//! * **session_key**: _[string]_ a 192-bit base64 encoded string (32

View File

@ -1,5 +1,17 @@
use http;
use http::Header;
pub use http::hyper::header::CookiePair as Cookie;
pub use cookie::Cookie;
pub use cookie::CookieJar;
pub use cookie::CookieBuilder;
pub type Cookies = http::hyper::header::CookieJar<'static>;
/// Type alias to a `'static` CookieJar.
///
/// A `CookieJar` should never be used without a `'static` lifetime. As a
/// result, you should always use this alias.
pub type Cookies = self::CookieJar<'static>;
impl<'c> From<Cookie<'c>> for Header<'static> {
fn from(cookie: Cookie) -> Header<'static> {
Header::new("Set-Cookie", cookie.encoded().to_string())
}
}

View File

@ -2,7 +2,6 @@ use std::collections::HashMap;
use std::borrow::{Borrow, Cow};
use std::fmt;
use http::hyper::header as hyper;
use http::ascii::{UncasedAscii, UncasedAsciiRef};
/// Simple representation of an HTTP header.
@ -107,13 +106,6 @@ impl<'h> fmt::Display for Header<'h> {
}
}
impl<T> From<T> for Header<'static> where T: hyper::Header + hyper::HeaderFormat {
fn from(hyper_header: T) -> Header<'static> {
let formatter = hyper::HeaderFormatter(&hyper_header);
Header::new(T::header_name(), format!("{}", formatter))
}
}
/// A collection of headers, mapping a header name to its many ordered values.
#[derive(Clone, Debug, PartialEq, Default)]
pub struct HeaderMap<'h> {
@ -345,16 +337,13 @@ impl<'h> HeaderMap<'h> {
///
/// ```rust
/// use rocket::http::{Cookie, HeaderMap};
/// use rocket::http::hyper::header;
///
/// let mut map = HeaderMap::new();
///
/// let cookie = vec![Cookie::new("a".to_string(), "b".to_string())];
/// map.add(header::SetCookie(cookie));
/// map.add(Cookie::new("a", "b"));
/// assert_eq!(map.get("Set-Cookie").count(), 1);
///
/// let cookie = vec![Cookie::new("c".to_string(), "d".to_string())];
/// map.add(header::SetCookie(cookie));
/// map.add(Cookie::new("c", "d"));
/// assert_eq!(map.get("Set-Cookie").count(), 2);
/// ```
#[inline(always)]

View File

@ -1,25 +1,79 @@
//! Re-exported hyper HTTP library types.
//!
//! ## Hyper
//!
//! All types that are re-exported from Hyper resides inside of this module.
//! All types that are re-exported from Hyper reside inside of this module.
//! These types will, with certainty, be removed with time, but they reside here
//! while necessary.
pub use hyper::server::Request as Request;
pub use hyper::server::Response as Response;
pub use hyper::server::Server as Server;
pub use hyper::server::Handler as Handler;
#[doc(hidden)] pub use hyper::server::Request as Request;
#[doc(hidden)] pub use hyper::server::Response as Response;
#[doc(hidden)] pub use hyper::server::Server as Server;
#[doc(hidden)] pub use hyper::server::Handler as Handler;
#[doc(hidden)] pub use hyper::net;
#[doc(hidden)] pub use hyper::method::Method;
#[doc(hidden)] pub use hyper::status::StatusCode;
#[doc(hidden)] pub use hyper::uri::RequestUri;
#[doc(hidden)] pub use hyper::http::h1;
#[doc(hidden)] pub use hyper::buffer;
pub use hyper::header;
pub use hyper::mime;
pub use hyper::net;
pub use hyper::method::Method;
pub use hyper::status::StatusCode;
pub use hyper::uri::RequestUri;
pub use hyper::http::h1;
pub use hyper::buffer;
/// Type alias to `hyper::Response<'a, hyper::net::Fresh>`.
pub type FreshResponse<'a> = self::Response<'a, self::net::Fresh>;
#[doc(hidden)] pub type FreshResponse<'a> = self::Response<'a, self::net::Fresh>;
/// Reexported Hyper header types.
pub mod header {
use http::Header;
use hyper::header::HeaderFormatter;
use hyper::header::Header as HyperHeaderTrait;
macro_rules! import_hyper_items {
($($item:ident),*) => ($(pub use hyper::header::$item;)*)
}
macro_rules! import_hyper_headers {
($($name:ident),*) => ($(
impl ::std::convert::From<self::$name> for Header<'static> {
fn from(header: self::$name) -> Header<'static> {
let formatter = HeaderFormatter(&header);
Header::new($name::header_name(), format!("{}", formatter))
}
}
)*)
}
import_hyper_items! {
Accept, AcceptCharset, AcceptEncoding, AcceptLanguage, AcceptRanges,
AccessControlAllowCredentials, AccessControlAllowHeaders,
AccessControlAllowMethods, AccessControlExposeHeaders,
AccessControlMaxAge, AccessControlRequestHeaders,
AccessControlRequestMethod, Allow, Authorization, Basic, Bearer,
CacheControl, Connection, ContentDisposition, ContentEncoding,
ContentLanguage, ContentLength, ContentRange, ContentType, Date, ETag,
EntityTag, Expires, From, Headers, Host, HttpDate, IfModifiedSince,
IfUnmodifiedSince, LastModified, Location, Origin, Prefer,
PreferenceApplied, Protocol, Quality, QualityItem, Referer,
StrictTransportSecurity, TransferEncoding, Upgrade, UserAgent,
AccessControlAllowOrigin, ByteRangeSpec, CacheDirective, Charset,
ConnectionOption, ContentRangeSpec, DispositionParam, DispositionType,
Encoding, Expect, IfMatch, IfNoneMatch, IfRange, Pragma, Preference,
ProtocolName, Range, RangeUnit, ReferrerPolicy, Vary, Scheme, q, qitem
}
import_hyper_headers! {
Accept, AccessControlAllowCredentials, AccessControlAllowHeaders,
AccessControlAllowMethods, AccessControlAllowOrigin,
AccessControlExposeHeaders, AccessControlMaxAge,
AccessControlRequestHeaders, AccessControlRequestMethod, AcceptCharset,
AcceptEncoding, AcceptLanguage, AcceptRanges, Allow, CacheControl,
Connection, ContentDisposition, ContentEncoding, ContentLanguage,
ContentLength, ContentRange, Date, ETag, Expect, Expires, Host, IfMatch,
IfModifiedSince, IfNoneMatch, IfRange, IfUnmodifiedSince, LastModified,
Location, Origin, Pragma, Prefer, PreferenceApplied, Range, Referer,
ReferrerPolicy, StrictTransportSecurity, TransferEncoding, Upgrade,
UserAgent, Vary
}
}

View File

@ -23,4 +23,4 @@ pub use self::content_type::ContentType;
pub use self::status::{Status, StatusClass};
pub use self::header::{Header, HeaderMap};
pub use self::cookies::{Cookie, Cookies};
pub use self::cookies::{Cookie, Cookies, CookieJar, CookieBuilder};

View File

@ -97,6 +97,8 @@ extern crate url;
extern crate toml;
extern crate num_cpus;
extern crate state;
extern crate cookie;
extern crate time;
#[cfg(test)] #[macro_use] extern crate lazy_static;

View File

@ -12,7 +12,7 @@ use super::{FromParam, FromSegments};
use router::Route;
use http::uri::{URI, Segments};
use http::{Method, ContentType, Header, HeaderMap, Cookies};
use http::{Method, ContentType, Header, HeaderMap, Cookie, Cookies};
use http::hyper;
@ -247,7 +247,8 @@ impl<'r> Request<'r> {
/// use rocket::http::{Cookie, Method, ContentType};
///
/// let mut request = Request::new(Method::Get, "/uri");
/// request.cookies().add(Cookie::new("key".into(), "val".into()))
/// request.cookies().add(Cookie::new("key", "val"));
/// request.cookies().add(Cookie::new("ans", format!("life: {}", 38 + 4)));
/// ```
#[inline(always)]
pub fn cookies(&self) -> &Cookies {
@ -255,18 +256,6 @@ impl<'r> Request<'r> {
}
/// Replace all of the cookies in `self` with `cookies`.
///
/// # Example
///
/// Add a new cookie to a request's cookies:
///
/// ```rust
/// use rocket::Request;
/// use rocket::http::{Cookie, Method, ContentType};
///
/// let mut request = Request::new(Method::Get, "/uri");
/// request.cookies().add(Cookie::new("key".into(), "val".into()))
/// ```
#[doc(hidden)]
#[inline(always)]
pub fn set_cookies(&mut self, cookies: Cookies) {
@ -430,8 +419,25 @@ impl<'r> Request<'r> {
let mut request = Request::new(method, uri);
// Set the request cookies, if they exist. TODO: Use session key.
if let Some(cookies) = h_headers.get::<hyper::header::Cookie>() {
request.set_cookies(cookies.to_cookie_jar(&[]));
if let Some(cookie_headers) = h_headers.get_raw("Cookie") {
let mut cookies = Cookies::new(&[]);
for header in cookie_headers {
let raw_str = match ::std::str::from_utf8(header) {
Ok(string) => string,
Err(_) => continue
};
for cookie_str in raw_str.split(";") {
let cookie = match Cookie::parse_encoded(cookie_str.to_string()) {
Ok(cookie) => cookie,
Err(_) => continue
};
cookies.add_original(cookie);
}
}
request.set_cookies(cookies);
}
// Set the rest of the headers.

View File

@ -1,10 +1,11 @@
use std::convert::AsRef;
use time::Duration;
use outcome::IntoOutcome;
use response::{Response, Responder};
use request::{self, Request, FromRequest};
use http::hyper::header;
use http::Status;
use http::{Status, Cookie};
// The name of the actual flash cookie.
const FLASH_COOKIE_NAME: &'static str = "_flash";
@ -161,12 +162,12 @@ impl<'r, R: Responder<'r>> Flash<R> {
Flash::new(responder, "error", msg)
}
fn cookie_pair(&self) -> header::CookiePair {
fn cookie(&self) -> Cookie<'static> {
let content = format!("{}{}{}", self.name.len(), self.name, self.message);
let mut pair = header::CookiePair::new(FLASH_COOKIE_NAME.to_string(), content);
pair.path = Some("/".to_string());
pair.max_age = Some(300);
pair
Cookie::build(FLASH_COOKIE_NAME, content)
.max_age(Duration::minutes(5))
.path("/")
.finish()
}
}
@ -177,9 +178,9 @@ impl<'r, R: Responder<'r>> Flash<R> {
impl<'r, R: Responder<'r>> Responder<'r> for Flash<R> {
fn respond(self) -> Result<Response<'r>, Status> {
trace_!("Flash: setting message: {}:{}", self.name, self.message);
let cookie = vec![self.cookie_pair()];
let cookie = self.cookie();
Response::build_from(self.responder.respond()?)
.header_adjoin(header::SetCookie(cookie))
.header_adjoin(cookie)
.ok()
}
}
@ -221,7 +222,7 @@ impl<'a, 'r> FromRequest<'a, 'r> for Flash<()> {
request.cookies().remove(FLASH_COOKIE_NAME);
// Parse the flash.
let content = cookie.pair().1;
let content = cookie.value();
let (len_str, rest) = match content.find(|c: char| !c.is_digit(10)) {
Some(i) => (&content[..i], &content[i..]),
None => (content, ""),

View File

@ -20,7 +20,7 @@ use catcher::{self, Catcher};
use outcome::Outcome;
use error::Error;
use http::{Method, Status};
use http::{Method, Status, Header};
use http::hyper::{self, header};
use http::uri::URI;
@ -79,7 +79,7 @@ impl Rocket {
fn issue_response(&self, mut response: Response, hyp_res: hyper::FreshResponse) {
// Add the 'rocket' server header, and write out the response.
// TODO: If removing Hyper, write out `Date` header too.
response.set_header(header::Server("rocket".to_string()));
response.set_header(Header::new("Server", "rocket"));
match self.write_response(response, hyp_res) {
Ok(_) => info_!("{}", Green.paint("Response succeeded.")),
@ -192,9 +192,8 @@ impl Rocket {
match self.route(request, data) {
Outcome::Success(mut response) => {
// A user's route responded!
let cookie_delta = request.cookies().delta();
if !cookie_delta.is_empty() {
response.adjoin_header(header::SetCookie(cookie_delta));
for cookie in request.cookies().delta() {
response.adjoin_header(cookie);
}
response

View File

@ -195,10 +195,11 @@ impl<'r> MockRequest<'r> {
/// use rocket::http::Cookie;
///
/// let req = MockRequest::new(Get, "/")
/// .cookie(Cookie::new("user_id".into(), "12".into()));
/// .cookie(Cookie::new("username", "sb"))
/// .cookie(Cookie::new("user_id", format!("{}", 12)));
/// ```
#[inline]
pub fn cookie(self, cookie: Cookie) -> Self {
pub fn cookie(self, cookie: Cookie<'static>) -> Self {
self.request.cookies().add(cookie);
self
}