Skip to content

Commit e634e64

Browse files
kevinpoitrajhpratt
authored andcommitted
Upgrade time to 0.2.5 (actix#1254)
* 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]>
1 parent cdba30d commit e634e64

File tree

23 files changed

+178
-135
lines changed

23 files changed

+178
-135
lines changed

CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Changes
22

3+
34
## [2.0.NEXT] - 2020-01-xx
45

56
### Changed
@@ -8,6 +9,8 @@
89

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

12+
* Update the `time` dependency to 0.2.5
13+
1114
## [2.0.0] - 2019-12-25
1215

1316
### Changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ regex = "1.3"
8787
serde = { version = "1.0", features=["derive"] }
8888
serde_json = "1.0"
8989
serde_urlencoded = "0.6.1"
90-
time = "0.1.42"
90+
time = { version = "0.2.5", default-features = false, features = ["std"] }
9191
url = "2.1"
9292
open-ssl = { version="0.10", package = "openssl", optional = true }
9393
rust-tls = { version = "0.16.0", package = "rustls", optional = true }

actix-http/CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
# [Unreleased]
44

5+
### Changed
6+
7+
* Update the `time` dependency to 0.2.5
8+
59
### Fixed
610

711
* Allow `SameSite=None` cookies to be sent in a response.

actix-http/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ base64 = "0.11"
5252
bitflags = "1.2"
5353
bytes = "0.5.3"
5454
copyless = "0.1.4"
55-
chrono = "0.4.6"
5655
derive_more = "0.99.2"
5756
either = "1.5.3"
5857
encoding_rs = "0.8"
@@ -77,7 +76,7 @@ serde_json = "1.0"
7776
sha-1 = "0.8"
7877
slab = "0.4"
7978
serde_urlencoded = "0.6.1"
80-
time = "0.1.42"
79+
time = { version = "0.2.5", default-features = false, features = ["std"] }
8180

8281
# for secure cookie
8382
ring = { version = "0.16.9", optional = true }

actix-http/src/config.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::{fmt, net};
77
use actix_rt::time::{delay_for, delay_until, Delay, Instant};
88
use bytes::BytesMut;
99
use futures_util::{future, FutureExt};
10-
use time;
10+
use time::OffsetDateTime;
1111

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

actix-http/src/cookie/builder.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::borrow::Cow;
22

3-
use chrono::Duration;
4-
use time::Tm;
3+
use time::{Duration, OffsetDateTime};
54

65
use super::{Cookie, SameSite};
76

@@ -64,13 +63,13 @@ impl CookieBuilder {
6463
/// use actix_http::cookie::Cookie;
6564
///
6665
/// let c = Cookie::build("foo", "bar")
67-
/// .expires(time::now())
66+
/// .expires(time::OffsetDateTime::now())
6867
/// .finish();
6968
///
7069
/// assert!(c.expires().is_some());
7170
/// ```
7271
#[inline]
73-
pub fn expires(mut self, when: Tm) -> CookieBuilder {
72+
pub fn expires(mut self, when: OffsetDateTime) -> CookieBuilder {
7473
self.cookie.set_expires(when);
7574
self
7675
}
@@ -108,7 +107,9 @@ impl CookieBuilder {
108107
/// ```
109108
#[inline]
110109
pub fn max_age_time(mut self, value: Duration) -> CookieBuilder {
111-
self.cookie.set_max_age(value);
110+
// Truncate any nanoseconds from the Duration, as they aren't represented within `Max-Age`
111+
// and would cause two otherwise identical `Cookie` instances to not be equivalent to one another.
112+
self.cookie.set_max_age(Duration::seconds(value.whole_seconds()));
112113
self
113114
}
114115

@@ -212,7 +213,7 @@ impl CookieBuilder {
212213
///
213214
/// ```rust
214215
/// use actix_http::cookie::Cookie;
215-
/// use chrono::Duration;
216+
/// use time::Duration;
216217
///
217218
/// let c = Cookie::build("foo", "bar")
218219
/// .permanent()

actix-http/src/cookie/jar.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std::collections::HashSet;
22
use std::mem::replace;
33

4-
use chrono::Duration;
4+
use time::{Duration, OffsetDateTime};
55

66
use super::delta::DeltaCookie;
77
use super::Cookie;
@@ -188,7 +188,7 @@ impl CookieJar {
188188
///
189189
/// ```rust
190190
/// use actix_http::cookie::{CookieJar, Cookie};
191-
/// use chrono::Duration;
191+
/// use time::Duration;
192192
///
193193
/// let mut jar = CookieJar::new();
194194
///
@@ -202,7 +202,7 @@ impl CookieJar {
202202
/// let delta: Vec<_> = jar.delta().collect();
203203
/// assert_eq!(delta.len(), 1);
204204
/// assert_eq!(delta[0].name(), "name");
205-
/// assert_eq!(delta[0].max_age(), Some(Duration::seconds(0)));
205+
/// assert_eq!(delta[0].max_age(), Some(Duration::zero()));
206206
/// ```
207207
///
208208
/// Removing a new cookie does not result in a _removal_ cookie:
@@ -220,8 +220,8 @@ impl CookieJar {
220220
pub fn remove(&mut self, mut cookie: Cookie<'static>) {
221221
if self.original_cookies.contains(cookie.name()) {
222222
cookie.set_value("");
223-
cookie.set_max_age(Duration::seconds(0));
224-
cookie.set_expires(time::now() - Duration::days(365));
223+
cookie.set_max_age(Duration::zero());
224+
cookie.set_expires(OffsetDateTime::now() - Duration::days(365));
225225
self.delta_cookies.replace(DeltaCookie::removed(cookie));
226226
} else {
227227
self.delta_cookies.remove(cookie.name());
@@ -239,7 +239,7 @@ impl CookieJar {
239239
///
240240
/// ```rust
241241
/// use actix_http::cookie::{CookieJar, Cookie};
242-
/// use chrono::Duration;
242+
/// use time::Duration;
243243
///
244244
/// let mut jar = CookieJar::new();
245245
///
@@ -533,7 +533,7 @@ mod test {
533533
#[test]
534534
#[cfg(feature = "secure-cookies")]
535535
fn delta() {
536-
use chrono::Duration;
536+
use time::Duration;
537537
use std::collections::HashMap;
538538

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

562562
#[test]

actix-http/src/cookie/mod.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,8 @@ use std::borrow::Cow;
6565
use std::fmt;
6666
use std::str::FromStr;
6767

68-
use chrono::Duration;
6968
use percent_encoding::{percent_encode, AsciiSet, CONTROLS};
70-
use time::Tm;
69+
use time::{Duration, OffsetDateTime};
7170

7271
pub use self::builder::CookieBuilder;
7372
pub use self::draft::*;
@@ -172,7 +171,7 @@ pub struct Cookie<'c> {
172171
/// The cookie's value.
173172
value: CookieStr,
174173
/// The cookie's expiration, if any.
175-
expires: Option<Tm>,
174+
expires: Option<OffsetDateTime>,
176175
/// The cookie's maximum age, if any.
177176
max_age: Option<Duration>,
178177
/// The cookie's domain, if any.
@@ -479,7 +478,7 @@ impl<'c> Cookie<'c> {
479478
/// assert_eq!(c.max_age(), None);
480479
///
481480
/// let c = Cookie::parse("name=value; Max-Age=3600").unwrap();
482-
/// assert_eq!(c.max_age().map(|age| age.num_hours()), Some(1));
481+
/// assert_eq!(c.max_age().map(|age| age.whole_hours()), Some(1));
483482
/// ```
484483
#[inline]
485484
pub fn max_age(&self) -> Option<Duration> {
@@ -544,10 +543,10 @@ impl<'c> Cookie<'c> {
544543
/// let expire_time = "Wed, 21 Oct 2017 07:28:00 GMT";
545544
/// let cookie_str = format!("name=value; Expires={}", expire_time);
546545
/// let c = Cookie::parse(cookie_str).unwrap();
547-
/// assert_eq!(c.expires().map(|t| t.tm_year), Some(117));
546+
/// assert_eq!(c.expires().map(|t| t.year()), Some(2017));
548547
/// ```
549548
#[inline]
550-
pub fn expires(&self) -> Option<Tm> {
549+
pub fn expires(&self) -> Option<OffsetDateTime> {
551550
self.expires
552551
}
553552

@@ -645,7 +644,7 @@ impl<'c> Cookie<'c> {
645644
///
646645
/// ```rust
647646
/// use actix_http::cookie::Cookie;
648-
/// use chrono::Duration;
647+
/// use time::Duration;
649648
///
650649
/// let mut c = Cookie::new("name", "value");
651650
/// assert_eq!(c.max_age(), None);
@@ -698,18 +697,19 @@ impl<'c> Cookie<'c> {
698697
///
699698
/// ```rust
700699
/// use actix_http::cookie::Cookie;
700+
/// use time::{Duration, OffsetDateTime};
701701
///
702702
/// let mut c = Cookie::new("name", "value");
703703
/// assert_eq!(c.expires(), None);
704704
///
705-
/// let mut now = time::now();
706-
/// now.tm_year += 1;
705+
/// let mut now = OffsetDateTime::now();
706+
/// now += Duration::week();
707707
///
708708
/// c.set_expires(now);
709709
/// assert!(c.expires().is_some())
710710
/// ```
711711
#[inline]
712-
pub fn set_expires(&mut self, time: Tm) {
712+
pub fn set_expires(&mut self, time: OffsetDateTime) {
713713
self.expires = Some(time);
714714
}
715715

@@ -720,7 +720,7 @@ impl<'c> Cookie<'c> {
720720
///
721721
/// ```rust
722722
/// use actix_http::cookie::Cookie;
723-
/// use chrono::Duration;
723+
/// use time::Duration;
724724
///
725725
/// let mut c = Cookie::new("foo", "bar");
726726
/// assert!(c.expires().is_none());
@@ -733,7 +733,7 @@ impl<'c> Cookie<'c> {
733733
pub fn make_permanent(&mut self) {
734734
let twenty_years = Duration::days(365 * 20);
735735
self.set_max_age(twenty_years);
736-
self.set_expires(time::now() + twenty_years);
736+
self.set_expires(OffsetDateTime::now() + twenty_years);
737737
}
738738

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

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

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

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

995995
#[test]
996996
fn format() {
@@ -1015,7 +1015,7 @@ mod tests {
10151015
assert_eq!(&cookie.to_string(), "foo=bar; Domain=www.rust-lang.org");
10161016

10171017
let time_str = "Wed, 21 Oct 2015 07:28:00 GMT";
1018-
let expires = strptime(time_str, "%a, %d %b %Y %H:%M:%S %Z").unwrap();
1018+
let expires = PrimitiveDateTime::parse(time_str, "%a, %d %b %Y %H:%M:%S").unwrap().using_offset(offset!(UTC));
10191019
let cookie = Cookie::build("foo", "bar").expires(expires).finish();
10201020
assert_eq!(
10211021
&cookie.to_string(),

actix-http/src/cookie/parse.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use std::error::Error;
55
use std::fmt;
66
use std::str::Utf8Error;
77

8-
use chrono::Duration;
98
use percent_encoding::percent_decode;
9+
use time::{Duration, offset};
1010

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

13+
use crate::time_parser;
14+
1315
/// Enum corresponding to a parsing error.
1416
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
1517
pub enum ParseError {
@@ -147,7 +149,7 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
147149
Ok(val) => {
148150
// Don't panic if the max age seconds is greater than what's supported by
149151
// `Duration`.
150-
let val = cmp::min(val, Duration::max_value().num_seconds());
152+
let val = cmp::min(val, Duration::max_value().whole_seconds());
151153
Some(Duration::seconds(val))
152154
}
153155
Err(_) => continue,
@@ -179,16 +181,14 @@ fn parse_inner<'c>(s: &str, decode: bool) -> Result<Cookie<'c>, ParseError> {
179181
}
180182
}
181183
("expires", Some(v)) => {
182-
// Try strptime with three date formats according to
184+
// Try parsing with three date formats according to
183185
// http://tools.ietf.org/html/rfc2616#section-3.3.1. Try
184186
// additional ones as encountered in the real world.
185-
let tm = time::strptime(v, "%a, %d %b %Y %H:%M:%S %Z")
186-
.or_else(|_| time::strptime(v, "%A, %d-%b-%y %H:%M:%S %Z"))
187-
.or_else(|_| time::strptime(v, "%a, %d-%b-%Y %H:%M:%S %Z"))
188-
.or_else(|_| time::strptime(v, "%a %b %d %H:%M:%S %Y"));
187+
let tm = time_parser::parse_http_date(v)
188+
.or_else(|| time::parse(v, "%a, %d-%b-%Y %H:%M:%S").ok());
189189

190-
if let Ok(time) = tm {
191-
cookie.expires = Some(time)
190+
if let Some(time) = tm {
191+
cookie.expires = Some(time.using_offset(offset!(UTC)))
192192
}
193193
}
194194
_ => {
@@ -216,8 +216,7 @@ where
216216
#[cfg(test)]
217217
mod tests {
218218
use super::{Cookie, SameSite};
219-
use chrono::Duration;
220-
use time::strptime;
219+
use time::{offset, Duration, PrimitiveDateTime};
221220

222221
macro_rules! assert_eq_parse {
223222
($string:expr, $expected:expr) => {
@@ -377,7 +376,7 @@ mod tests {
377376
);
378377

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

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

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

0 commit comments

Comments
 (0)