Revert "Replace time with std::time in components/net (#31079)" (#31120)

This reverts commit 580062228b.
This commit is contained in:
Martin Robinson 2024-01-18 16:10:48 +01:00 committed by GitHub
parent c3fd27c225
commit 8e5f28839c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 123 additions and 161 deletions

1
Cargo.lock generated
View file

@ -2802,7 +2802,6 @@ dependencies = [
name = "hyper_serde" name = "hyper_serde"
version = "0.13.2" version = "0.13.2"
dependencies = [ dependencies = [
"chrono",
"cookie 0.12.0", "cookie 0.12.0",
"headers", "headers",
"http", "http",

View file

@ -9,7 +9,7 @@
use std::net::TcpStream; use std::net::TcpStream;
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
use chrono::{DateTime, Local}; use chrono::{Local, LocalResult, TimeZone};
use devtools_traits::{HttpRequest as DevtoolsHttpRequest, HttpResponse as DevtoolsHttpResponse}; use devtools_traits::{HttpRequest as DevtoolsHttpRequest, HttpResponse as DevtoolsHttpResponse};
use headers::{ContentType, Cookie, HeaderMapExt}; use headers::{ContentType, Cookie, HeaderMapExt};
use http::{header, HeaderMap, Method, StatusCode}; use http::{header, HeaderMap, Method, StatusCode};
@ -371,13 +371,23 @@ impl NetworkEventActor {
pub fn event_actor(&self) -> EventActor { pub fn event_actor(&self) -> EventActor {
// TODO: Send the correct values for startedDateTime, isXHR, private // TODO: Send the correct values for startedDateTime, isXHR, private
let date_time: DateTime<Local> = self.request.startedDateTime.clone().into(); let started_datetime_rfc3339 = match Local.timestamp_millis_opt(
self.request
.startedDateTime
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as i64,
) {
LocalResult::None => "".to_owned(),
LocalResult::Single(dateTime) => format!("{}", dateTime.to_rfc3339()),
LocalResult::Ambiguous(dateTime, _) => format!("{}", dateTime.to_rfc3339()),
};
EventActor { EventActor {
actor: self.name(), actor: self.name(),
url: self.request.url.clone(), url: self.request.url.clone(),
method: format!("{}", self.request.method), method: format!("{}", self.request.method),
startedDateTime: date_time.to_rfc3339(), startedDateTime: started_datetime_rfc3339,
timeStamp: self.request.timeStamp, timeStamp: self.request.timeStamp,
isXHR: self.is_xhr, isXHR: self.is_xhr,
private: false, private: false,

View file

@ -16,7 +16,6 @@ doctest = false
test = false test = false
[dependencies] [dependencies]
chrono = "0.4"
cookie = { workspace = true } cookie = { workspace = true }
headers = { workspace = true } headers = { workspace = true }
http = { workspace = true } http = { workspace = true }
@ -24,7 +23,7 @@ hyper = { workspace = true }
mime = { workspace = true } mime = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_bytes = { workspace = true } serde_bytes = { workspace = true }
time = { workspace = true }
[dev-dependencies] [dev-dependencies]
serde_test = "1.0" serde_test = "1.0"
time = { workspace = true }

View file

@ -20,7 +20,7 @@
//! * `hyper::Method` //! * `hyper::Method`
//! * `hyper::Uri` //! * `hyper::Uri`
//! * `mime::Mime` //! * `mime::Mime`
//! * `std::time::SystemTime` //! * `time::Tm`
//! //!
//! # How do I use a data type with a `HeaderMap` member with Serde? //! # How do I use a data type with a `HeaderMap` member with Serde?
//! //!
@ -66,10 +66,8 @@
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::str::FromStr; use std::str::FromStr;
use std::time::SystemTime;
use std::{cmp, fmt, str}; use std::{cmp, fmt, str};
use chrono::{DateTime, SecondsFormat, Utc};
use cookie::Cookie; use cookie::Cookie;
use headers::ContentType; use headers::ContentType;
use http::HeaderMap; use http::HeaderMap;
@ -80,6 +78,7 @@ use serde::de::{self, Error, MapAccess, SeqAccess, Visitor};
use serde::ser::{SerializeMap, SerializeSeq}; use serde::ser::{SerializeMap, SerializeSeq};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_bytes::{ByteBuf, Bytes}; use serde_bytes::{ByteBuf, Bytes};
use time::{strptime, Tm};
/// Deserialises a `T` value with a given deserializer. /// Deserialises a `T` value with a given deserializer.
/// ///
@ -605,15 +604,15 @@ impl<'de> Visitor<'de> for StatusVisitor {
} }
} }
impl<'de> Deserialize<'de> for De<SystemTime> { impl<'de> Deserialize<'de> for De<Tm> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: Deserializer<'de>, D: Deserializer<'de>,
{ {
struct SystemTimeVisitor; struct TmVisitor;
impl<'de> Visitor<'de> for SystemTimeVisitor { impl<'de> Visitor<'de> for TmVisitor {
type Value = De<SystemTime>; type Value = De<Tm>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a date and time according to RFC 3339") write!(formatter, "a date and time according to RFC 3339")
@ -623,23 +622,22 @@ impl<'de> Deserialize<'de> for De<SystemTime> {
where where
E: de::Error, E: de::Error,
{ {
DateTime::parse_from_rfc3339(v) strptime(v, "%Y-%m-%dT%H:%M:%SZ")
.map(|t| De::new(SystemTime::from(t))) .map(De::new)
.map_err(|e| E::custom(e.to_string())) .map_err(|e| E::custom(e.to_string()))
} }
} }
deserializer.deserialize_string(SystemTimeVisitor) deserializer.deserialize_string(TmVisitor)
} }
} }
impl<'a> Serialize for Ser<'a, SystemTime> { impl<'a> Serialize for Ser<'a, Tm> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where where
S: Serializer, S: Serializer,
{ {
let date_time: DateTime<Utc> = self.v.clone().into(); serializer.serialize_str(&self.v.rfc3339().to_string())
serializer.serialize_str(&date_time.to_rfc3339_opts(SecondsFormat::Secs, true))
} }
} }

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use std::time::SystemTime;
use cookie::Cookie; use cookie::Cookie;
use headers::ContentType; use headers::ContentType;
use http::header::HeaderMap; use http::header::HeaderMap;
@ -17,6 +15,7 @@ use hyper::{Method, StatusCode, Uri};
use hyper_serde::{De, Ser, Serde}; use hyper_serde::{De, Ser, Serde};
use mime::Mime; use mime::Mime;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use time::Tm;
fn is_supported<T>() fn is_supported<T>()
where where
@ -34,6 +33,6 @@ fn supported() {
is_supported::<Method>(); is_supported::<Method>();
is_supported::<Mime>(); is_supported::<Mime>();
is_supported::<StatusCode>(); is_supported::<StatusCode>();
is_supported::<SystemTime>(); is_supported::<Tm>();
is_supported::<Uri>(); is_supported::<Uri>();
} }

View file

@ -15,6 +15,7 @@ use http::StatusCode;
use hyper::{Method, Uri}; use hyper::{Method, Uri};
use hyper_serde::{De, Ser}; use hyper_serde::{De, Ser};
use serde_test::{assert_de_tokens, assert_ser_tokens, Token}; use serde_test::{assert_de_tokens, assert_ser_tokens, Token};
use time::Duration;
#[test] #[test]
fn test_content_type() { fn test_content_type() {
@ -31,7 +32,7 @@ fn test_cookie() {
// string with a bunch of indices in it which apparently is different from the exact same // string with a bunch of indices in it which apparently is different from the exact same
// cookie but parsed as a bunch of strings. // cookie but parsed as a bunch of strings.
let cookie: Cookie = Cookie::build("Hello", "World!") let cookie: Cookie = Cookie::build("Hello", "World!")
.max_age(time::Duration::seconds(42)) .max_age(Duration::seconds(42))
.domain("servo.org") .domain("servo.org")
.path("/") .path("/")
.secure(true) .secure(true)
@ -111,18 +112,14 @@ fn test_raw_status() {
} }
#[test] #[test]
fn test_system_time_serialization() { fn test_tm() {
use std::time::SystemTime; use time::strptime;
use chrono::{NaiveDateTime, TimeZone, Utc}; let time = strptime("2017-02-22T12:03:31Z", "%Y-%m-%dT%H:%M:%SZ").unwrap();
let tokens = &[Token::Str("2017-02-22T12:03:31Z")];
let time = SystemTime::from(Utc.from_utc_datetime(
&NaiveDateTime::parse_from_str("2023-01-15T12:53:31Z", "%Y-%m-%dT%H:%M:%SZ").unwrap(),
));
let tokens = &[Token::Str("2023-01-15T12:53:31Z")];
assert_de_tokens(&De::new(time), tokens);
assert_ser_tokens(&Ser::new(&time), tokens); assert_ser_tokens(&Ser::new(&time), tokens);
assert_de_tokens(&De::new(time), tokens);
} }
#[test] #[test]

View file

@ -7,13 +7,13 @@
use std::borrow::ToOwned; use std::borrow::ToOwned;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use hyper_serde::Serde; use hyper_serde::Serde;
use net_traits::pub_domains::is_pub_domain; use net_traits::pub_domains::is_pub_domain;
use net_traits::CookieSource; use net_traits::CookieSource;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use time::{at, now, Duration, Tm};
/// A stored cookie that wraps the definition in cookie-rs. This is used to implement /// A stored cookie that wraps the definition in cookie-rs. This is used to implement
/// various behaviours defined in the spec that rely on an associated request URL, /// various behaviours defined in the spec that rely on an associated request URL,
@ -31,13 +31,13 @@ pub struct Cookie {
deserialize_with = "hyper_serde::deserialize", deserialize_with = "hyper_serde::deserialize",
serialize_with = "hyper_serde::serialize" serialize_with = "hyper_serde::serialize"
)] )]
pub creation_time: SystemTime, pub creation_time: Tm,
#[serde( #[serde(
deserialize_with = "hyper_serde::deserialize", deserialize_with = "hyper_serde::deserialize",
serialize_with = "hyper_serde::serialize" serialize_with = "hyper_serde::serialize"
)] )]
pub last_access: SystemTime, pub last_access: Tm,
pub expiry_time: Option<Serde<SystemTime>>, pub expiry_time: Option<Serde<Tm>>,
} }
impl Cookie { impl Cookie {
@ -62,16 +62,11 @@ impl Cookie {
let (persistent, expiry_time) = match (cookie.max_age(), cookie.expires()) { let (persistent, expiry_time) = match (cookie.max_age(), cookie.expires()) {
(Some(max_age), _) => ( (Some(max_age), _) => (
true, true,
Some(SystemTime::now() + Duration::from_secs(max_age.num_seconds() as u64)), Some(at(
), now().to_timespec() + Duration::seconds(max_age.num_seconds())
(_, Some(expires)) => ( )),
true,
Some(
UNIX_EPOCH +
Duration::from_secs(expires.to_timespec().sec as u64) +
Duration::from_nanos(expires.to_timespec().nsec as u64),
),
), ),
(_, Some(expires)) => (true, Some(expires)),
_ => (false, None), _ => (false, None),
}; };
@ -140,18 +135,18 @@ impl Cookie {
cookie, cookie,
host_only, host_only,
persistent, persistent,
creation_time: SystemTime::now(), creation_time: now(),
last_access: SystemTime::now(), last_access: now(),
expiry_time: expiry_time.map(Serde), expiry_time: expiry_time.map(Serde),
}) })
} }
pub fn touch(&mut self) { pub fn touch(&mut self) {
self.last_access = SystemTime::now(); self.last_access = now();
} }
pub fn set_expiry_time_negative(&mut self) { pub fn set_expiry_time_negative(&mut self) {
self.expiry_time = Some(Serde(SystemTime::now() - Duration::from_secs(1))); self.expiry_time = Some(Serde(now() - Duration::seconds(1)));
} }
// http://tools.ietf.org/html/rfc6265#section-5.1.4 // http://tools.ietf.org/html/rfc6265#section-5.1.4

View file

@ -8,13 +8,13 @@
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{SystemTime, UNIX_EPOCH};
use log::{debug, info}; use log::{debug, info};
use net_traits::pub_domains::reg_suffix; use net_traits::pub_domains::reg_suffix;
use net_traits::CookieSource; use net_traits::CookieSource;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use time::{self, Tm};
use crate::cookie::Cookie; use crate::cookie::Cookie;
@ -139,17 +139,8 @@ impl CookieStorage {
let b_path_len = b.cookie.path().as_ref().map_or(0, |p| p.len()); let b_path_len = b.cookie.path().as_ref().map_or(0, |p| p.len());
match a_path_len.cmp(&b_path_len) { match a_path_len.cmp(&b_path_len) {
Ordering::Equal => { Ordering::Equal => {
let a_creation_time = a let a_creation_time = a.creation_time.to_timespec();
.creation_time let b_creation_time = b.creation_time.to_timespec();
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
let b_creation_time = b
.creation_time
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos();
a_creation_time.cmp(&b_creation_time) a_creation_time.cmp(&b_creation_time)
}, },
// Ensure that longer paths are sorted earlier than shorter paths // Ensure that longer paths are sorted earlier than shorter paths
@ -238,14 +229,14 @@ fn reg_host<'a>(url: &'a str) -> String {
fn is_cookie_expired(cookie: &Cookie) -> bool { fn is_cookie_expired(cookie: &Cookie) -> bool {
match cookie.expiry_time { match cookie.expiry_time {
Some(ref t) => t.0 <= SystemTime::now(), Some(ref t) => t.to_timespec() <= time::get_time(),
None => false, None => false,
} }
} }
fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool { fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
// Remove non-secure cookie with oldest access time // Remove non-secure cookie with oldest access time
let oldest_accessed = get_oldest_accessed(false, cookies); let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(false, cookies);
if let Some((index, _)) = oldest_accessed { if let Some((index, _)) = oldest_accessed {
cookies.remove(index); cookies.remove(index);
@ -254,7 +245,7 @@ fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
if !is_secure_cookie { if !is_secure_cookie {
return false; return false;
} }
let oldest_accessed: Option<(usize, SystemTime)> = get_oldest_accessed(true, cookies); let oldest_accessed: Option<(usize, Tm)> = get_oldest_accessed(true, cookies);
if let Some((index, _)) = oldest_accessed { if let Some((index, _)) = oldest_accessed {
cookies.remove(index); cookies.remove(index);
} }
@ -262,11 +253,8 @@ fn evict_one_cookie(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> bool {
return true; return true;
} }
fn get_oldest_accessed( fn get_oldest_accessed(is_secure_cookie: bool, cookies: &mut Vec<Cookie>) -> Option<(usize, Tm)> {
is_secure_cookie: bool, let mut oldest_accessed: Option<(usize, Tm)> = None;
cookies: &mut Vec<Cookie>,
) -> Option<(usize, SystemTime)> {
let mut oldest_accessed: Option<(usize, SystemTime)> = None;
for (i, c) in cookies.iter().enumerate() { for (i, c) in cookies.iter().enumerate() {
if (c.cookie.secure().unwrap_or(false) == is_secure_cookie) && if (c.cookie.secure().unwrap_or(false) == is_secure_cookie) &&
oldest_accessed oldest_accessed

View file

@ -9,12 +9,11 @@
//! This library will eventually become the core of the Fetch crate //! This library will eventually become the core of the Fetch crate
//! with CORSRequest being expanded into FetchRequest (etc) //! with CORSRequest being expanded into FetchRequest (etc)
use std::time::{Duration, SystemTime};
use http::header::HeaderName; use http::header::HeaderName;
use http::Method; use http::Method;
use net_traits::request::{CredentialsMode, Origin, Request}; use net_traits::request::{CredentialsMode, Origin, Request};
use servo_url::ServoUrl; use servo_url::ServoUrl;
use time::{self, Timespec};
/// Union type for CORS cache entries /// Union type for CORS cache entries
/// ///
@ -46,17 +45,17 @@ impl HeaderOrMethod {
pub struct CorsCacheEntry { pub struct CorsCacheEntry {
pub origin: Origin, pub origin: Origin,
pub url: ServoUrl, pub url: ServoUrl,
pub max_age: Duration, pub max_age: u32,
pub credentials: bool, pub credentials: bool,
pub header_or_method: HeaderOrMethod, pub header_or_method: HeaderOrMethod,
created: SystemTime, created: Timespec,
} }
impl CorsCacheEntry { impl CorsCacheEntry {
fn new( fn new(
origin: Origin, origin: Origin,
url: ServoUrl, url: ServoUrl,
max_age: Duration, max_age: u32,
credentials: bool, credentials: bool,
header_or_method: HeaderOrMethod, header_or_method: HeaderOrMethod,
) -> CorsCacheEntry { ) -> CorsCacheEntry {
@ -66,7 +65,7 @@ impl CorsCacheEntry {
max_age: max_age, max_age: max_age,
credentials: credentials, credentials: credentials,
header_or_method: header_or_method, header_or_method: header_or_method,
created: SystemTime::now(), created: time::now().to_timespec(),
} }
} }
} }
@ -112,11 +111,10 @@ impl CorsCache {
/// Remove old entries /// Remove old entries
pub fn cleanup(&mut self) { pub fn cleanup(&mut self) {
let CorsCache(buf) = self.clone(); let CorsCache(buf) = self.clone();
let now = SystemTime::now(); let now = time::now().to_timespec();
let new_buf: Vec<CorsCacheEntry> = buf let new_buf: Vec<CorsCacheEntry> = buf
.into_iter() .into_iter()
.filter(|e| now < e.created + e.max_age) .filter(|e| now.sec < e.created.sec + e.max_age as i64)
.collect(); .collect();
*self = CorsCache(new_buf); *self = CorsCache(new_buf);
} }
@ -135,7 +133,7 @@ impl CorsCache {
&mut self, &mut self,
request: &Request, request: &Request,
header_name: &HeaderName, header_name: &HeaderName,
new_max_age: Duration, new_max_age: u32,
) -> bool { ) -> bool {
match self match self
.find_entry_by_header(&request, header_name) .find_entry_by_header(&request, header_name)
@ -169,7 +167,7 @@ impl CorsCache {
&mut self, &mut self,
request: &Request, request: &Request,
method: Method, method: Method,
new_max_age: Duration, new_max_age: u32,
) -> bool { ) -> bool {
match self match self
.find_entry_by_method(&request, method.clone()) .find_entry_by_method(&request, method.clone())

View file

@ -4,7 +4,6 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr}; use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use embedder_traits::resources::{self, Resource}; use embedder_traits::resources::{self, Resource};
use headers::{HeaderMapExt, StrictTransportSecurity}; use headers::{HeaderMapExt, StrictTransportSecurity};
@ -20,7 +19,7 @@ use servo_url::{Host, ServoUrl};
pub struct HstsEntry { pub struct HstsEntry {
pub host: String, pub host: String,
pub include_subdomains: bool, pub include_subdomains: bool,
pub max_age: Option<Duration>, pub max_age: Option<u64>,
pub timestamp: Option<u64>, pub timestamp: Option<u64>,
} }
@ -28,7 +27,7 @@ impl HstsEntry {
pub fn new( pub fn new(
host: String, host: String,
subdomains: IncludeSubdomains, subdomains: IncludeSubdomains,
max_age: Option<Duration>, max_age: Option<u64>,
) -> Option<HstsEntry> { ) -> Option<HstsEntry> {
if host.parse::<Ipv4Addr>().is_ok() || host.parse::<Ipv6Addr>().is_ok() { if host.parse::<Ipv4Addr>().is_ok() || host.parse::<Ipv6Addr>().is_ok() {
None None
@ -37,12 +36,7 @@ impl HstsEntry {
host: host, host: host,
include_subdomains: (subdomains == IncludeSubdomains::Included), include_subdomains: (subdomains == IncludeSubdomains::Included),
max_age: max_age, max_age: max_age,
timestamp: Some( timestamp: Some(time::get_time().sec as u64),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
),
}) })
} }
} }
@ -50,11 +44,7 @@ impl HstsEntry {
pub fn is_expired(&self) -> bool { pub fn is_expired(&self) -> bool {
match (self.max_age, self.timestamp) { match (self.max_age, self.timestamp) {
(Some(max_age), Some(timestamp)) => { (Some(max_age), Some(timestamp)) => {
SystemTime::now() (time::get_time().sec as u64) - timestamp >= max_age
.duration_since(UNIX_EPOCH)
.unwrap_or_default() -
Duration::from_secs(timestamp) >=
max_age
}, },
_ => false, _ => false,
@ -206,9 +196,11 @@ impl HstsList {
IncludeSubdomains::NotIncluded IncludeSubdomains::NotIncluded
}; };
if let Some(entry) = if let Some(entry) = HstsEntry::new(
HstsEntry::new(host.to_owned(), include_subdomains, Some(header.max_age())) host.to_owned(),
{ include_subdomains,
Some(header.max_age().as_secs()),
) {
info!("adding host {} to the strict transport security list", host); info!("adding host {} to the strict transport security list", host);
info!("- max-age {}", header.max_age().as_secs()); info!("- max-age {}", header.max_age().as_secs());
if header.include_subdomains() { if header.include_subdomains() {

View file

@ -11,7 +11,7 @@ use std::collections::HashMap;
use std::ops::Bound; use std::ops::Bound;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Mutex; use std::sync::Mutex;
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::SystemTime;
use headers::{ use headers::{
CacheControl, ContentRange, Expires, HeaderMapExt, LastModified, Pragma, Range, Vary, CacheControl, ContentRange, Expires, HeaderMapExt, LastModified, Pragma, Range, Vary,
@ -30,6 +30,7 @@ use net_traits::{FetchMetadata, Metadata, ResourceFetchTiming};
use servo_arc::Arc; use servo_arc::Arc;
use servo_config::pref; use servo_config::pref;
use servo_url::ServoUrl; use servo_url::ServoUrl;
use time::{Duration, Timespec, Tm};
use tokio::sync::mpsc::{unbounded_channel as unbounded, UnboundedSender as TokioSender}; use tokio::sync::mpsc::{unbounded_channel as unbounded, UnboundedSender as TokioSender};
use crate::fetch::methods::{Data, DoneChannel}; use crate::fetch::methods::{Data, DoneChannel};
@ -74,7 +75,7 @@ struct MeasurableCachedResource {
raw_status: Option<(u16, Vec<u8>)>, raw_status: Option<(u16, Vec<u8>)>,
url_list: Vec<ServoUrl>, url_list: Vec<ServoUrl>,
expires: Duration, expires: Duration,
last_validated: SystemTime, last_validated: Tm,
} }
impl MallocSizeOf for CachedResource { impl MallocSizeOf for CachedResource {
@ -180,11 +181,11 @@ fn calculate_response_age(response: &Response) -> Duration {
if let Some(secs) = response.headers.get(header::AGE) { if let Some(secs) = response.headers.get(header::AGE) {
if let Ok(seconds_string) = secs.to_str() { if let Ok(seconds_string) = secs.to_str() {
if let Ok(secs) = seconds_string.parse::<i64>() { if let Ok(secs) = seconds_string.parse::<i64>() {
return Duration::from_secs(secs as u64); return Duration::seconds(secs);
} }
} }
} }
Duration::ZERO Duration::seconds(0i64)
} }
/// Determine the expiry date from relevant headers, /// Determine the expiry date from relevant headers,
@ -195,10 +196,14 @@ fn get_response_expiry(response: &Response) -> Duration {
if let Some(directives) = response.headers.typed_get::<CacheControl>() { if let Some(directives) = response.headers.typed_get::<CacheControl>() {
if directives.no_cache() { if directives.no_cache() {
// Requires validation on first use. // Requires validation on first use.
return Duration::ZERO; return Duration::seconds(0i64);
} else { } else {
if let Some(max_age) = directives.max_age().or(directives.s_max_age()) { if let Some(secs) = directives.max_age().or(directives.s_max_age()) {
return max_age.checked_sub(age).unwrap_or(Duration::ZERO); let max_age = Duration::from_std(secs).unwrap();
if max_age < age {
return Duration::seconds(0i64);
}
return max_age - age;
} }
} }
} }
@ -206,15 +211,18 @@ fn get_response_expiry(response: &Response) -> Duration {
Some(t) => { Some(t) => {
// store the period of time from now until expiry // store the period of time from now until expiry
let t: SystemTime = t.into(); let t: SystemTime = t.into();
let desired = t.duration_since(UNIX_EPOCH).unwrap_or_default(); let t = t.duration_since(SystemTime::UNIX_EPOCH).unwrap();
let current = SystemTime::now() let desired = Timespec::new(t.as_secs() as i64, 0);
.duration_since(UNIX_EPOCH) let current = time::now().to_timespec();
.unwrap_or_default();
return desired.checked_sub(current).unwrap_or(Duration::ZERO); if desired > current {
return desired - current;
} else {
return Duration::seconds(0i64);
}
}, },
// Malformed Expires header, shouldn't be used to construct a valid response. // Malformed Expires header, shouldn't be used to construct a valid response.
None if response.headers.contains_key(header::EXPIRES) => return Duration::ZERO, None if response.headers.contains_key(header::EXPIRES) => return Duration::seconds(0i64),
_ => {}, _ => {},
} }
// Calculating Heuristic Freshness // Calculating Heuristic Freshness
@ -223,18 +231,19 @@ fn get_response_expiry(response: &Response) -> Duration {
// <https://tools.ietf.org/html/rfc7234#section-5.5.4> // <https://tools.ietf.org/html/rfc7234#section-5.5.4>
// Since presently we do not generate a Warning header field with a 113 warn-code, // Since presently we do not generate a Warning header field with a 113 warn-code,
// 24 hours minus response age is the max for heuristic calculation. // 24 hours minus response age is the max for heuristic calculation.
let max_heuristic = Duration::from_secs(24 * 3600) - age; let max_heuristic = Duration::hours(24) - age;
let heuristic_freshness = if let Some(last_modified) = let heuristic_freshness = if let Some(last_modified) =
// If the response has a Last-Modified header field, // If the response has a Last-Modified header field,
// caches are encouraged to use a heuristic expiration value // caches are encouraged to use a heuristic expiration value
// that is no more than some fraction of the interval since that time. // that is no more than some fraction of the interval since that time.
response.headers.typed_get::<LastModified>() response.headers.typed_get::<LastModified>()
{ {
let current = SystemTime::now() let current = time::now().to_timespec();
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let last_modified: SystemTime = last_modified.into(); let last_modified: SystemTime = last_modified.into();
let last_modified = last_modified.duration_since(UNIX_EPOCH).unwrap(); let last_modified = last_modified
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap();
let last_modified = Timespec::new(last_modified.as_secs() as i64, 0);
// A typical setting of this fraction might be 10%. // A typical setting of this fraction might be 10%.
let raw_heuristic_calc = (current - last_modified) / 10; let raw_heuristic_calc = (current - last_modified) / 10;
let result = if raw_heuristic_calc < max_heuristic { let result = if raw_heuristic_calc < max_heuristic {
@ -259,7 +268,7 @@ fn get_response_expiry(response: &Response) -> Duration {
} }
} }
// Requires validation upon first use as default. // Requires validation upon first use as default.
Duration::ZERO Duration::seconds(0i64)
} }
/// Request Cache-Control Directives /// Request Cache-Control Directives
@ -271,19 +280,24 @@ fn get_expiry_adjustment_from_request_headers(request: &Request, expires: Durati
}; };
if let Some(max_age) = directive.max_stale() { if let Some(max_age) = directive.max_stale() {
return expires + max_age; return expires + Duration::from_std(max_age).unwrap();
} }
if let Some(max_age) = directive.max_age() { if let Some(max_age) = directive.max_age() {
let max_age = Duration::from_std(max_age).unwrap();
if expires > max_age { if expires > max_age {
return Duration::ZERO; return Duration::min_value();
} }
return expires - max_age; return expires - max_age;
} }
if let Some(min_fresh) = directive.min_fresh() { if let Some(min_fresh) = directive.min_fresh() {
return expires.checked_sub(min_fresh).unwrap_or(Duration::ZERO); let min_fresh = Duration::from_std(min_fresh).unwrap();
if expires < min_fresh {
return Duration::min_value();
}
return expires - min_fresh;
} }
if directive.no_cache() || directive.no_store() { if directive.no_cache() || directive.no_store() {
return Duration::ZERO; return Duration::min_value();
} }
expires expires
@ -327,15 +341,8 @@ fn create_cached_response(
response.aborted = cached_resource.aborted.clone(); response.aborted = cached_resource.aborted.clone();
let expires = cached_resource.data.expires; let expires = cached_resource.data.expires;
let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires); let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires);
let now = SystemTime::now() let now = Duration::seconds(time::now().to_timespec().sec);
.duration_since(UNIX_EPOCH) let last_validated = Duration::seconds(cached_resource.data.last_validated.to_timespec().sec);
.unwrap_or_default();
let last_validated = cached_resource
.data
.last_validated
.duration_since(UNIX_EPOCH)
.unwrap_or_default();
let time_since_validated = now - last_validated; let time_since_validated = now - last_validated;
// TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1> // TODO: take must-revalidate into account <https://tools.ietf.org/html/rfc7234#section-5.2.2.1>
// TODO: if this cache is to be considered shared, take proxy-revalidate into account // TODO: if this cache is to be considered shared, take proxy-revalidate into account
@ -806,7 +813,7 @@ impl HttpCache {
let entry_key = CacheKey::from_servo_url(url); let entry_key = CacheKey::from_servo_url(url);
if let Some(cached_resources) = self.entries.get_mut(&entry_key) { if let Some(cached_resources) = self.entries.get_mut(&entry_key) {
for cached_resource in cached_resources.iter_mut() { for cached_resource in cached_resources.iter_mut() {
cached_resource.data.expires = Duration::ZERO; cached_resource.data.expires = Duration::seconds(0i64);
} }
} }
} }
@ -890,7 +897,7 @@ impl HttpCache {
raw_status: response.raw_status.clone(), raw_status: response.raw_status.clone(),
url_list: response.url_list.clone(), url_list: response.url_list.clone(),
expires: expiry, expires: expiry,
last_validated: SystemTime::now(), last_validated: time::now(),
}), }),
}; };
let entry = self.entries.entry(entry_key).or_insert_with(|| vec![]); let entry = self.entries.entry(entry_key).or_insert_with(|| vec![]);

View file

@ -122,10 +122,7 @@ impl HttpState {
} }
fn precise_time_ms() -> u64 { fn precise_time_ms() -> u64 {
SystemTime::now() time::precise_time_ns() / (1000 * 1000)
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_millis() as u64
} }
// Step 3 of https://fetch.spec.whatwg.org/#concept-fetch. // Step 3 of https://fetch.spec.whatwg.org/#concept-fetch.
@ -2111,6 +2108,7 @@ async fn cors_preflight_fetch(
.typed_get::<AccessControlMaxAge>() .typed_get::<AccessControlMaxAge>()
.map(|acma| acma.into()) .map(|acma| acma.into())
.unwrap_or(Duration::from_secs(5)); .unwrap_or(Duration::from_secs(5));
let max_age = max_age.as_secs() as u32;
// Substep 10 // Substep 10
// TODO: Need to define what an imposed limit on max-age is // TODO: Need to define what an imposed limit on max-age is

View file

@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::collections::HashMap; use std::collections::HashMap;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use net::hsts::{HstsEntry, HstsList}; use net::hsts::{HstsEntry, HstsList};
use net_traits::IncludeSubdomains; use net_traits::IncludeSubdomains;
@ -13,7 +12,7 @@ fn test_hsts_entry_is_not_expired_when_it_has_no_timestamp() {
let entry = HstsEntry { let entry = HstsEntry {
host: "mozilla.org".to_owned(), host: "mozilla.org".to_owned(),
include_subdomains: false, include_subdomains: false,
max_age: Some(Duration::from_secs(20)), max_age: Some(20),
timestamp: None, timestamp: None,
}; };
@ -26,12 +25,7 @@ fn test_hsts_entry_is_not_expired_when_it_has_no_max_age() {
host: "mozilla.org".to_owned(), host: "mozilla.org".to_owned(),
include_subdomains: false, include_subdomains: false,
max_age: None, max_age: None,
timestamp: Some( timestamp: Some(time::get_time().sec as u64),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs(),
),
}; };
assert!(!entry.is_expired()); assert!(!entry.is_expired());
@ -42,14 +36,8 @@ fn test_hsts_entry_is_expired_when_it_has_reached_its_max_age() {
let entry = HstsEntry { let entry = HstsEntry {
host: "mozilla.org".to_owned(), host: "mozilla.org".to_owned(),
include_subdomains: false, include_subdomains: false,
max_age: Some(Duration::from_secs(10)), max_age: Some(10),
timestamp: Some( timestamp: Some(time::get_time().sec as u64 - 20u64),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() -
20u64,
),
}; };
assert!(entry.is_expired()); assert!(entry.is_expired());
@ -118,7 +106,7 @@ fn test_push_entry_with_0_max_age_evicts_entry_from_list() {
vec![HstsEntry::new( vec![HstsEntry::new(
"mozilla.org".to_owned(), "mozilla.org".to_owned(),
IncludeSubdomains::NotIncluded, IncludeSubdomains::NotIncluded,
Some(Duration::from_secs(500000u64)), Some(500000u64),
) )
.unwrap()], .unwrap()],
); );
@ -130,7 +118,7 @@ fn test_push_entry_with_0_max_age_evicts_entry_from_list() {
HstsEntry::new( HstsEntry::new(
"mozilla.org".to_owned(), "mozilla.org".to_owned(),
IncludeSubdomains::NotIncluded, IncludeSubdomains::NotIncluded,
Some(Duration::ZERO), Some(0),
) )
.unwrap(), .unwrap(),
); );
@ -379,14 +367,8 @@ fn test_hsts_list_with_expired_entry_is_not_is_host_secure() {
vec![HstsEntry { vec![HstsEntry {
host: "mozilla.org".to_owned(), host: "mozilla.org".to_owned(),
include_subdomains: false, include_subdomains: false,
max_age: Some(Duration::from_secs(20)), max_age: Some(20),
timestamp: Some( timestamp: Some(time::get_time().sec as u64 - 100u64),
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() -
100u64,
),
}], }],
); );
let hsts_list = HstsList { let hsts_list = HstsList {