Skip to content

Commit

Permalink
Upgrade time to 0.2.5 (#1254)
Browse files Browse the repository at this point in the history
* Use `OffsetDateTime` instead of `PrimitiveDateTime`

* Parse time strings with `PrimitiveDateTime::parse` instead of `OffsetDateTime::parse`

* Remove unused `time` dependency from actix-multipart

* Fix a few errors with time related tests from the `time` upgrade

* Implement logic to convert a RFC 850 two-digit year into a full length year, and organize time parsing related functions

* Upgrade `time` to 0.2.2

* Correctly parse C's asctime time format using time 0.2's new format patterns

* Update CHANGES.md

* Use `time` without any of its deprecated functions

* Enforce a UTC time offset when converting an `OffsetDateTime` into a Header value

* Use the more readable version of `Duration::seconds(0)`, `Duration::zero()`

* Remove unneeded conversion of time::Duration to std::time::Duration

* Use `OffsetDateTime::as_seconds_f64` instead of manually calculating the amount of seconds from nanoseconds

* Replace a few additional instances of `Duration::seconds(0)` with `Duration::zero()`

* Truncate any nanoseconds from a supplied `Duration` within `Cookie::set_max_age` to ensure two Cookies with the same amount whole seconds equate to one another

* Fix the actix-http::cookie::do_not_panic_on_large_max_ages test

* Convert `Cookie::max_age` and `Cookie::expires` examples to `time` 0.2

Mainly minor  changes. Type inference can be used alongside the new
`time::parse` method, such that the type doesn't need to be specified.
This will be useful if a refactoring takes place that changes the type.
There are also new macros, which are used where possible.

One change that is not immediately obvious, in `HttpDate`, there was an
unnecessary conditional. As the time crate allows for negative durations
(and can perform arithmetic with such), the if/else can be removed
entirely.

Time v0.2.3 also has some bug fixes, which is why I am not using a more
general v0.2 in Cargo.toml.

v0.2.3 has been yanked, as it was backwards imcompatible. This version
reverts the breaking change, while still supporting rustc back to
1.34.0.

* Add missing `time::offset` macro import

* Fix type confusion when using `time::parse` followed by `using_offset`

* Update `time` to 0.2.5

* Update CHANGES.md

Co-authored-by: Jacob Pratt <[email protected]>
  • Loading branch information
2 people authored and JohnTitor committed Jan 28, 2020
1 parent cdba30d commit e634e64
Show file tree
Hide file tree
Showing 23 changed files with 178 additions and 135 deletions.
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Changes


## [2.0.NEXT] - 2020-01-xx

### Changed
Expand All @@ -8,6 +9,8 @@

* Skip empty chunks when returning response from a `Stream` #1308

* Update the `time` dependency to 0.2.5

## [2.0.0] - 2019-12-25

### Changed
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ regex = "1.3"
serde = { version = "1.0", features=["derive"] }
serde_json = "1.0"
serde_urlencoded = "0.6.1"
time = "0.1.42"
time = { version = "0.2.5", default-features = false, features = ["std"] }
url = "2.1"
open-ssl = { version="0.10", package = "openssl", optional = true }
rust-tls = { version = "0.16.0", package = "rustls", optional = true }
Expand Down
4 changes: 4 additions & 0 deletions actix-http/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

# [Unreleased]

### Changed

* Update the `time` dependency to 0.2.5

### Fixed

* Allow `SameSite=None` cookies to be sent in a response.
Expand Down
3 changes: 1 addition & 2 deletions actix-http/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ base64 = "0.11"
bitflags = "1.2"
bytes = "0.5.3"
copyless = "0.1.4"
chrono = "0.4.6"
derive_more = "0.99.2"
either = "1.5.3"
encoding_rs = "0.8"
Expand All @@ -77,7 +76,7 @@ serde_json = "1.0"
sha-1 = "0.8"
slab = "0.4"
serde_urlencoded = "0.6.1"
time = "0.1.42"
time = { version = "0.2.5", default-features = false, features = ["std"] }

# for secure cookie
ring = { version = "0.16.9", optional = true }
Expand Down
4 changes: 2 additions & 2 deletions actix-http/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use std::{fmt, net};
use actix_rt::time::{delay_for, delay_until, Delay, Instant};
use bytes::BytesMut;
use futures_util::{future, FutureExt};
use time;
use time::OffsetDateTime;

// "Sun, 06 Nov 1994 08:49:37 GMT".len()
const DATE_VALUE_LENGTH: usize = 29;
Expand Down Expand Up @@ -211,7 +211,7 @@ impl Date {
}
fn update(&mut self) {
self.pos = 0;
write!(self, "{}", time::at_utc(time::get_time()).rfc822()).unwrap();
write!(self, "{}", OffsetDateTime::now().format("%a, %d %b %Y %H:%M:%S GMT")).unwrap();
}
}

Expand Down
13 changes: 7 additions & 6 deletions actix-http/src/cookie/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::borrow::Cow;

use chrono::Duration;
use time::Tm;
use time::{Duration, OffsetDateTime};

use super::{Cookie, SameSite};

Expand Down Expand Up @@ -64,13 +63,13 @@ impl CookieBuilder {
/// use actix_http::cookie::Cookie;
///
/// let c = Cookie::build("foo", "bar")
/// .expires(time::now())
/// .expires(time::OffsetDateTime::now())
/// .finish();
///
/// assert!(c.expires().is_some());
/// ```
#[inline]
pub fn expires(mut self, when: Tm) -> CookieBuilder {
pub fn expires(mut self, when: OffsetDateTime) -> CookieBuilder {
self.cookie.set_expires(when);
self
}
Expand Down Expand Up @@ -108,7 +107,9 @@ impl CookieBuilder {
/// ```
#[inline]
pub fn max_age_time(mut self, value: Duration) -> CookieBuilder {
self.cookie.set_max_age(value);
// Truncate any nanoseconds from the Duration, as they aren't represented within `Max-Age`
// and would cause two otherwise identical `Cookie` instances to not be equivalent to one another.
self.cookie.set_max_age(Duration::seconds(value.whole_seconds()));
self
}

Expand Down Expand Up @@ -212,7 +213,7 @@ impl CookieBuilder {
///
/// ```rust
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
/// use time::Duration;
///
/// let c = Cookie::build("foo", "bar")
/// .permanent()
Expand Down
16 changes: 8 additions & 8 deletions actix-http/src/cookie/jar.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashSet;
use std::mem::replace;

use chrono::Duration;
use time::{Duration, OffsetDateTime};

use super::delta::DeltaCookie;
use super::Cookie;
Expand Down Expand Up @@ -188,7 +188,7 @@ impl CookieJar {
///
/// ```rust
/// use actix_http::cookie::{CookieJar, Cookie};
/// use chrono::Duration;
/// use time::Duration;
///
/// let mut jar = CookieJar::new();
///
Expand All @@ -202,7 +202,7 @@ impl CookieJar {
/// let delta: Vec<_> = jar.delta().collect();
/// assert_eq!(delta.len(), 1);
/// assert_eq!(delta[0].name(), "name");
/// assert_eq!(delta[0].max_age(), Some(Duration::seconds(0)));
/// assert_eq!(delta[0].max_age(), Some(Duration::zero()));
/// ```
///
/// Removing a new cookie does not result in a _removal_ cookie:
Expand All @@ -220,8 +220,8 @@ impl CookieJar {
pub fn remove(&mut self, mut cookie: Cookie<'static>) {
if self.original_cookies.contains(cookie.name()) {
cookie.set_value("");
cookie.set_max_age(Duration::seconds(0));
cookie.set_expires(time::now() - Duration::days(365));
cookie.set_max_age(Duration::zero());
cookie.set_expires(OffsetDateTime::now() - Duration::days(365));
self.delta_cookies.replace(DeltaCookie::removed(cookie));
} else {
self.delta_cookies.remove(cookie.name());
Expand All @@ -239,7 +239,7 @@ impl CookieJar {
///
/// ```rust
/// use actix_http::cookie::{CookieJar, Cookie};
/// use chrono::Duration;
/// use time::Duration;
///
/// let mut jar = CookieJar::new();
///
Expand Down Expand Up @@ -533,7 +533,7 @@ mod test {
#[test]
#[cfg(feature = "secure-cookies")]
fn delta() {
use chrono::Duration;
use time::Duration;
use std::collections::HashMap;

let mut c = CookieJar::new();
Expand All @@ -556,7 +556,7 @@ mod test {
assert!(names.get("test2").unwrap().is_none());
assert!(names.get("test3").unwrap().is_none());
assert!(names.get("test4").unwrap().is_none());
assert_eq!(names.get("original").unwrap(), &Some(Duration::seconds(0)));
assert_eq!(names.get("original").unwrap(), &Some(Duration::zero()));
}

#[test]
Expand Down
32 changes: 16 additions & 16 deletions actix-http/src/cookie/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,8 @@ use std::borrow::Cow;
use std::fmt;
use std::str::FromStr;

use chrono::Duration;
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
use time::Tm;
use time::{Duration, OffsetDateTime};

pub use self::builder::CookieBuilder;
pub use self::draft::*;
Expand Down Expand Up @@ -172,7 +171,7 @@ pub struct Cookie<'c> {
/// The cookie's value.
value: CookieStr,
/// The cookie's expiration, if any.
expires: Option<Tm>,
expires: Option<OffsetDateTime>,
/// The cookie's maximum age, if any.
max_age: Option<Duration>,
/// The cookie's domain, if any.
Expand Down Expand Up @@ -479,7 +478,7 @@ impl<'c> Cookie<'c> {
/// assert_eq!(c.max_age(), None);
///
/// let c = Cookie::parse("name=value; Max-Age=3600").unwrap();
/// assert_eq!(c.max_age().map(|age| age.num_hours()), Some(1));
/// assert_eq!(c.max_age().map(|age| age.whole_hours()), Some(1));
/// ```
#[inline]
pub fn max_age(&self) -> Option<Duration> {
Expand Down Expand Up @@ -544,10 +543,10 @@ impl<'c> Cookie<'c> {
/// let expire_time = "Wed, 21 Oct 2017 07:28:00 GMT";
/// let cookie_str = format!("name=value; Expires={}", expire_time);
/// let c = Cookie::parse(cookie_str).unwrap();
/// assert_eq!(c.expires().map(|t| t.tm_year), Some(117));
/// assert_eq!(c.expires().map(|t| t.year()), Some(2017));
/// ```
#[inline]
pub fn expires(&self) -> Option<Tm> {
pub fn expires(&self) -> Option<OffsetDateTime> {
self.expires
}

Expand Down Expand Up @@ -645,7 +644,7 @@ impl<'c> Cookie<'c> {
///
/// ```rust
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
/// use time::Duration;
///
/// let mut c = Cookie::new("name", "value");
/// assert_eq!(c.max_age(), None);
Expand Down Expand Up @@ -698,18 +697,19 @@ impl<'c> Cookie<'c> {
///
/// ```rust
/// use actix_http::cookie::Cookie;
/// use time::{Duration, OffsetDateTime};
///
/// let mut c = Cookie::new("name", "value");
/// assert_eq!(c.expires(), None);
///
/// let mut now = time::now();
/// now.tm_year += 1;
/// let mut now = OffsetDateTime::now();
/// now += Duration::week();
///
/// c.set_expires(now);
/// assert!(c.expires().is_some())
/// ```
#[inline]
pub fn set_expires(&mut self, time: Tm) {
pub fn set_expires(&mut self, time: OffsetDateTime) {
self.expires = Some(time);
}

Expand All @@ -720,7 +720,7 @@ impl<'c> Cookie<'c> {
///
/// ```rust
/// use actix_http::cookie::Cookie;
/// use chrono::Duration;
/// use time::Duration;
///
/// let mut c = Cookie::new("foo", "bar");
/// assert!(c.expires().is_none());
Expand All @@ -733,7 +733,7 @@ impl<'c> Cookie<'c> {
pub fn make_permanent(&mut self) {
let twenty_years = Duration::days(365 * 20);
self.set_max_age(twenty_years);
self.set_expires(time::now() + twenty_years);
self.set_expires(OffsetDateTime::now() + twenty_years);
}

fn fmt_parameters(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
Expand All @@ -758,11 +758,11 @@ impl<'c> Cookie<'c> {
}

if let Some(max_age) = self.max_age() {
write!(f, "; Max-Age={}", max_age.num_seconds())?;
write!(f, "; Max-Age={}", max_age.whole_seconds())?;
}

if let Some(time) = self.expires() {
write!(f, "; Expires={}", time.rfc822())?;
write!(f, "; Expires={}", time.format("%a, %d %b %Y %H:%M:%S GMT"))?;
}

Ok(())
Expand Down Expand Up @@ -990,7 +990,7 @@ impl<'a, 'b> PartialEq<Cookie<'b>> for Cookie<'a> {
#[cfg(test)]
mod tests {
use super::{Cookie, SameSite};
use time::strptime;
use time::{offset, PrimitiveDateTime};

#[test]
fn format() {
Expand All @@ -1015,7 +1015,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 = strptime(time_str, "%a, %d %b %Y %H:%M:%S %Z").unwrap();
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().using_offset(offset!(UTC));
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
assert_eq!(
&cookie.to_string(),
Expand Down
32 changes: 16 additions & 16 deletions actix-http/src/cookie/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ use std::error::Error;
use std::fmt;
use std::str::Utf8Error;

use chrono::Duration;
use percent_encoding::percent_decode;
use time::{Duration, offset};

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

use crate::time_parser;

/// Enum corresponding to a parsing error.
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum ParseError {
Expand Down Expand Up @@ -147,7 +149,7 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
Ok(val) => {
// Don't panic if the max age seconds is greater than what's supported by
// `Duration`.
let val = cmp::min(val, Duration::max_value().num_seconds());
let val = cmp::min(val, Duration::max_value().whole_seconds());
Some(Duration::seconds(val))
}
Err(_) => continue,
Expand Down Expand Up @@ -179,16 +181,14 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
}
}
("expires", Some(v)) => {
// Try strptime with three date formats according to
// Try parsing 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 = time::strptime(v, "%a, %d %b %Y %H:%M:%S %Z")
.or_else(|_| time::strptime(v, "%A, %d-%b-%y %H:%M:%S %Z"))
.or_else(|_| time::strptime(v, "%a, %d-%b-%Y %H:%M:%S %Z"))
.or_else(|_| time::strptime(v, "%a %b %d %H:%M:%S %Y"));
let tm = time_parser::parse_http_date(v)
.or_else(|| time::parse(v, "%a, %d-%b-%Y %H:%M:%S").ok());

if let Ok(time) = tm {
cookie.expires = Some(time)
if let Some(time) = tm {
cookie.expires = Some(time.using_offset(offset!(UTC)))
}
}
_ => {
Expand Down Expand Up @@ -216,8 +216,7 @@ where
#[cfg(test)]
mod tests {
use super::{Cookie, SameSite};
use chrono::Duration;
use time::strptime;
use time::{offset, Duration, PrimitiveDateTime};

macro_rules! assert_eq_parse {
($string:expr, $expected:expr) => {
Expand Down Expand Up @@ -377,7 +376,7 @@ mod tests {
);

let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
let expires = strptime(time_str, "%a, %d %b %Y %H:%M:%S %Z").unwrap();
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().using_offset(offset!(UTC));
expected.set_expires(expires);
assert_eq_parse!(
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
Expand All @@ -386,7 +385,7 @@ mod tests {
);

unexpected.set_domain("foo.com");
let bad_expires = strptime(time_str, "%a, %d %b %Y %H:%S:%M %Z").unwrap();
let bad_expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%S:%M").unwrap().using_offset(offset!(UTC));
expected.set_expires(bad_expires);
assert_ne_parse!(
" foo=bar ;HttpOnly; Secure; Max-Age=4; Path=/foo; \
Expand Down Expand Up @@ -414,8 +413,9 @@ mod tests {

#[test]
fn do_not_panic_on_large_max_ages() {
let max_seconds = Duration::max_value().num_seconds();
let expected = Cookie::build("foo", "bar").max_age(max_seconds).finish();
assert_eq_parse!(format!(" foo=bar; Max-Age={:?}", max_seconds + 1), expected);
let max_duration = Duration::max_value();
let expected = Cookie::build("foo", "bar").max_age_time(max_duration).finish();
let overflow_duration = max_duration.checked_add(Duration::nanoseconds(1)).unwrap_or(max_duration);
assert_eq_parse!(format!(" foo=bar; Max-Age={:?}", overflow_duration.whole_seconds()), expected);
}
}
Loading

0 comments on commit e634e64

Please sign in to comment.