Skip to content

Commit

Permalink
Fix 'time' 0.3 update.
Browse files Browse the repository at this point in the history
  • Loading branch information
SergioBenitez committed Aug 18, 2021
1 parent 0a7453c commit 5e616c3
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 81 deletions.
36 changes: 12 additions & 24 deletions src/lib.rs
Expand Up @@ -79,9 +79,6 @@
#![doc(html_root_url = "https://docs.rs/cookie/0.16")]
#![deny(missing_docs)]

#[cfg(feature = "percent-encode")] extern crate percent_encoding;
extern crate time;

mod builder;
mod parse;
mod jar;
Expand All @@ -101,7 +98,7 @@ use std::ascii::AsciiExt;

#[cfg(feature = "percent-encode")]
use percent_encoding::{AsciiSet, percent_encode as encode};
use time::{Duration, OffsetDateTime, UtcOffset};
use time::{Duration, OffsetDateTime, UtcOffset, macros::datetime};

use crate::parse::parse_cookie;
pub use crate::parse::ParseError;
Expand Down Expand Up @@ -826,11 +823,7 @@ impl<'c> Cookie<'c> {
/// assert_eq!(c.expires(), Some(Expiration::Session));
/// ```
pub fn set_expires<T: Into<Expiration>>(&mut self, time: T) {
use time::macros::{date, time, offset};
static MAX_DATETIME: OffsetDateTime = date!(9999-12-31)
.with_time(time!(23:59:59.999_999))
.assume_utc()
.to_offset(offset!(UTC));
static MAX_DATETIME: OffsetDateTime = datetime!(9999-12-31 23:59:59.999_999 UTC);

// RFC 6265 requires dates not to exceed 9999 years.
self.expires = Some(time.into()
Expand Down Expand Up @@ -945,9 +938,7 @@ impl<'c> Cookie<'c> {

if let Some(time) = self.expires_datetime() {
let time = time.to_offset(UtcOffset::UTC);
write!(f, "; Expires={}", time.format(&time::macros::format_description!(
"[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT"
)).unwrap())?;
write!(f, "; Expires={}", time.format(&crate::parse::FMT1).map_err(|_| fmt::Error)?)?;
}

Ok(())
Expand Down Expand Up @@ -1292,10 +1283,8 @@ impl<'a, 'b> PartialEq<Cookie<'b>> for Cookie<'a> {

#[cfg(test)]
mod tests {
use crate::{Cookie, SameSite};
use crate::parse::parse_gmt_date;
use crate::{time::Duration, OffsetDateTime};
use crate::{time::macros::format_description};
use crate::{Cookie, SameSite, parse::parse_date};
use time::{Duration, OffsetDateTime};

#[test]
fn format() {
Expand Down Expand Up @@ -1323,10 +1312,7 @@ mod tests {
assert_eq!(&cookie.to_string(), "foo=bar; Domain=www.rust-lang.org");

let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
let expires = parse_gmt_date(
time_str,
&format_description!("[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT")
).unwrap();
let expires = parse_date(time_str, &crate::parse::FMT1).unwrap();
let cookie = Cookie::build("foo", "bar")
.expires(expires).finish();
assert_eq!(&cookie.to_string(),
Expand Down Expand Up @@ -1360,10 +1346,12 @@ mod tests {
#[ignore]
fn format_date_wraps() {
let expires = OffsetDateTime::UNIX_EPOCH + Duration::MAX;
let cookie = Cookie::build("foo", "bar")
.expires(expires).finish();
assert_eq!(&cookie.to_string(),
"foo=bar; Expires=Fri, 31 Dec 9999 23:59:59 GMT");
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
assert_eq!(&cookie.to_string(), "foo=bar; Expires=Fri, 31 Dec 9999 23:59:59 GMT");

let expires = time::macros::datetime!(9999-01-01 0:00 UTC) + Duration::days(1000);
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
assert_eq!(&cookie.to_string(), "foo=bar; Expires=Fri, 31 Dec 9999 23:59:59 GMT");
}

#[test]
Expand Down
106 changes: 49 additions & 57 deletions src/parse.rs
@@ -1,21 +1,26 @@
use std::borrow::Cow;
use std::error::Error;
use std::convert::{From, TryFrom};
use std::str::Utf8Error;
use std::fmt;
use std::convert::{From, TryFrom};

#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;

#[cfg(feature = "percent-encode")]
use percent_encoding::percent_decode;
use time::{Duration, OffsetDateTime, PrimitiveDateTime, UtcOffset};
use time::error::Parse;
use time::parsing::Parsed;
use time::macros::format_description;
use time::{PrimitiveDateTime, Duration, OffsetDateTime};
use time::{parsing::Parsable, macros::format_description, format_description::FormatItem};

use crate::{Cookie, SameSite, CookieStr};

// The three formats spec'd in http://tools.ietf.org/html/rfc2616#section-3.3.1.
// Additional ones as encountered in the real world.
pub static FMT1: &[FormatItem<'_>] = format_description!("[weekday repr:short], [day] [month repr:short] [year padding:none] [hour]:[minute]:[second] GMT");
pub static FMT2: &[FormatItem<'_>] = format_description!("[weekday], [day]-[month repr:short]-[year repr:last_two] [hour]:[minute]:[second] GMT");
pub static FMT3: &[FormatItem<'_>] = format_description!("[weekday repr:short] [month repr:short] [day padding:space] [hour]:[minute]:[second] [year padding:none]");
pub static FMT4: &[FormatItem<'_>] = format_description!("[weekday repr:short], [day]-[month repr:short]-[year padding:none] [hour]:[minute]:[second] GMT");

/// Enum corresponding to a parsing error.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[non_exhaustive]
Expand Down Expand Up @@ -222,22 +227,11 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
}
}
("expires", Some(v)) => {
// Try strptime with three date formats according to
// http://tools.ietf.org/html/rfc2616#section-3.3.1. Try
// additional ones as encountered in the real world.
let tm = parse_gmt_date(
v,
&format_description!("[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT")
).or_else(|_| parse_gmt_date(
v,
&format_description!("[weekday repr:short], [day]-[month repr:short]-[year repr:last_two] [hour]:[minute]:[second] GMT")
)).or_else(|_| parse_gmt_date(
v,
&format_description!("[weekday repr:short], [day]-[month repr:short]-[year] [hour]:[minute]:[second] GMT")
)).or_else(|_| parse_gmt_date(
v,
&format_description!("[weekday repr:short] [month repr:short] [day] [hour]:[minute]:[second] [year]")
));
let tm = parse_date(v, &FMT1)
.or_else(|_| parse_date(v, &FMT2))
.or_else(|_| parse_date(v, &FMT3))
.or_else(|_| parse_date(v, &FMT4));
// .or_else(|_| parse_date(v, &FMT5));

if let Ok(time) = tm {
cookie.expires = Some(time.into())
Expand All @@ -264,39 +258,27 @@ pub(crate) fn parse_cookie<'c, S>(cow: S, decode: bool) -> Result<Cookie<'c>, Pa
Ok(cookie)
}

pub(crate) fn parse_gmt_date<T>(s: &str, format: &T) -> Result<OffsetDateTime, time::error::Parse>
where
T: time::parsing::Parsable,
{
format.parse(s.as_bytes())
.map(|mut parsed| {
// Handle malformed "abbreviated" dates like Chromium. See cookie#162.
parsed.year_last_two()
.map(|y| {
let y = y as i32;
let offset = match y {
0..=68 => 2000,
69..=99 => 1900,
_ => 0,
};

parsed.set_year(y + offset)
});

parsed
})
.and_then(|parsed| <PrimitiveDateTime as TryFrom<Parsed>>::try_from(parsed)
.map_err(|err| Parse::TryFromParsed(err))
)
.map(|t| t.assume_utc().to_offset(UtcOffset::UTC))
pub(crate) fn parse_date(s: &str, format: &impl Parsable) -> Result<OffsetDateTime, time::Error> {
// Parse. Handle "abbreviated" dates like Chromium. See cookie#162.
let mut date = format.parse(s.as_bytes())?;
if let Some(y) = date.year().or_else(|| date.year_last_two().map(|v| v as i32)) {
let offset = match y {
0..=68 => 2000,
69..=99 => 1900,
_ => 0,
};

date.set_year(y + offset);
}

Ok(PrimitiveDateTime::try_from(date)?.assume_utc())
}

#[cfg(test)]
mod tests {
use super::parse_date;
use crate::{Cookie, SameSite};
use super::parse_gmt_date;
use ::time::Duration;
use ::time::macros::format_description;
use time::Duration;

macro_rules! assert_eq_parse {
($string:expr, $expected:expr) => (
Expand Down Expand Up @@ -468,19 +450,13 @@ mod tests {
Domain=FOO.COM", unexpected);

let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
let expires = parse_gmt_date(
time_str,
&format_description!("[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[second] GMT")
).unwrap();
let expires = parse_date(time_str, &super::FMT1).unwrap();
expected.set_expires(expires);
assert_eq_parse!(" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
Domain=foo.com; Expires=Wed, 21 Oct 2015 07:28:00 GMT", expected);

unexpected.set_domain("foo.com");
let bad_expires = parse_gmt_date(
time_str,
&format_description!("[weekday repr:short], [day] [month repr:short] [year] [hour]:[minute]:[minute] GMT")
).unwrap();
let bad_expires = parse_date(time_str, &super::FMT1).unwrap();
expected.set_expires(bad_expires);
assert_ne_parse!(" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
Domain=foo.com; Expires=Wed, 21 Oct 2015 07:28:00 GMT", unexpected);
Expand All @@ -503,6 +479,22 @@ mod tests {
let cookie_str = "foo=bar; expires=Thu, 10-Sep-99 20:00:00 GMT";
let cookie = Cookie::parse(cookie_str).unwrap();
assert_eq!(cookie.expires_datetime().unwrap().year(), 1999);

let cookie_str = "foo=bar; expires=Thu, 10-Sep-2069 20:00:00 GMT";
let cookie = Cookie::parse(cookie_str).unwrap();
assert_eq!(cookie.expires_datetime().unwrap().year(), 2069);
}

#[test]
fn parse_variant_date_fmts() {
let cookie_str = "foo=bar; expires=Sun, 06 Nov 1994 08:49:37 GMT";
Cookie::parse(cookie_str).unwrap().expires_datetime().unwrap();

let cookie_str = "foo=bar; expires=Sunday, 06-Nov-94 08:49:37 GMT";
Cookie::parse(cookie_str).unwrap().expires_datetime().unwrap();

let cookie_str = "foo=bar; expires=Sun Nov 6 08:49:37 1994";
Cookie::parse(cookie_str).unwrap().expires_datetime().unwrap();
}

#[test]
Expand Down

0 comments on commit 5e616c3

Please sign in to comment.