diff --git a/components/net/fetch/cors_cache.rs b/components/net/fetch/cors_cache.rs index f7798b79501..246be69b351 100644 --- a/components/net/fetch/cors_cache.rs +++ b/components/net/fetch/cors_cache.rs @@ -9,11 +9,12 @@ //! This library will eventually become the core of the Fetch crate //! with CORSRequest being expanded into FetchRequest (etc) +use std::time::{Duration, Instant}; + use http::header::HeaderName; use http::Method; use net_traits::request::{CredentialsMode, Origin, Request}; use servo_url::ServoUrl; -use time::{self, Timespec}; /// Union type for CORS cache entries /// @@ -45,17 +46,17 @@ impl HeaderOrMethod { pub struct CorsCacheEntry { pub origin: Origin, pub url: ServoUrl, - pub max_age: u32, + pub max_age: Duration, pub credentials: bool, pub header_or_method: HeaderOrMethod, - created: Timespec, + created: Instant, } impl CorsCacheEntry { fn new( origin: Origin, url: ServoUrl, - max_age: u32, + max_age: Duration, credentials: bool, header_or_method: HeaderOrMethod, ) -> CorsCacheEntry { @@ -65,7 +66,7 @@ impl CorsCacheEntry { max_age, credentials, header_or_method, - created: time::now().to_timespec(), + created: Instant::now(), } } } @@ -107,10 +108,10 @@ impl CorsCache { /// Remove old entries pub fn cleanup(&mut self) { let CorsCache(buf) = self.clone(); - let now = time::now().to_timespec(); + let now = Instant::now(); let new_buf: Vec = buf .into_iter() - .filter(|e| now.sec < e.created.sec + e.max_age as i64) + .filter(|e| now < e.created + e.max_age) .collect(); *self = CorsCache(new_buf); } @@ -129,7 +130,7 @@ impl CorsCache { &mut self, request: &Request, header_name: &HeaderName, - new_max_age: u32, + new_max_age: Duration, ) -> bool { match self .find_entry_by_header(request, header_name) @@ -163,7 +164,7 @@ impl CorsCache { &mut self, request: &Request, method: Method, - new_max_age: u32, + new_max_age: Duration, ) -> bool { match self .find_entry_by_method(request, method.clone()) diff --git a/components/net/http_cache.rs b/components/net/http_cache.rs index e9719f4cff0..7558e82abcf 100644 --- a/components/net/http_cache.rs +++ b/components/net/http_cache.rs @@ -11,7 +11,7 @@ use std::collections::HashMap; use std::ops::Bound; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Mutex; -use std::time::SystemTime; +use std::time::{Duration, Instant, SystemTime}; use headers::{ CacheControl, ContentRange, Expires, HeaderMapExt, LastModified, Pragma, Range, Vary, @@ -30,7 +30,6 @@ use net_traits::{FetchMetadata, Metadata, ResourceFetchTiming}; use servo_arc::Arc; use servo_config::pref; use servo_url::ServoUrl; -use time::{Duration, Timespec, Tm}; use tokio::sync::mpsc::{unbounded_channel as unbounded, UnboundedSender as TokioSender}; use crate::fetch::methods::{Data, DoneChannel}; @@ -75,7 +74,7 @@ struct MeasurableCachedResource { raw_status: Option<(u16, Vec)>, url_list: Vec, expires: Duration, - last_validated: Tm, + last_validated: Instant, } impl MallocSizeOf for CachedResource { @@ -178,14 +177,13 @@ fn response_is_cacheable(metadata: &Metadata) -> bool { /// fn calculate_response_age(response: &Response) -> Duration { // TODO: follow the spec more closely (Date headers, request/response lag, ...) - if let Some(secs) = response.headers.get(header::AGE) { - if let Ok(seconds_string) = secs.to_str() { - if let Ok(secs) = seconds_string.parse::() { - return Duration::seconds(secs); - } - } - } - Duration::seconds(0i64) + response + .headers + .get(header::AGE) + .and_then(|age_header| age_header.to_str().ok()) + .and_then(|age_string| age_string.parse::().ok()) + .map(|seconds| Duration::from_secs(seconds)) + .unwrap_or_default() } /// Determine the expiry date from relevant headers, @@ -193,34 +191,28 @@ fn calculate_response_age(response: &Response) -> Duration { fn get_response_expiry(response: &Response) -> Duration { // Calculating Freshness Lifetime let age = calculate_response_age(response); + let now = SystemTime::now(); if let Some(directives) = response.headers.typed_get::() { if directives.no_cache() { // Requires validation on first use. - return Duration::seconds(0i64); + return Duration::ZERO; } - if let Some(secs) = directives.max_age().or(directives.s_max_age()) { - let max_age = Duration::from_std(secs).unwrap(); + if let Some(max_age) = directives.max_age().or(directives.s_max_age()) { if max_age < age { - return Duration::seconds(0i64); + return Duration::ZERO; } return max_age - age; } } match response.headers.typed_get::() { - Some(t) => { - // store the period of time from now until expiry - let t: SystemTime = t.into(); - let t = t.duration_since(SystemTime::UNIX_EPOCH).unwrap(); - let desired = Timespec::new(t.as_secs() as i64, 0); - let current = time::now().to_timespec(); - - if desired > current { - return desired - current; - } - return Duration::seconds(0i64); + Some(expiry) => { + // `duration_since` fails if `now` is later than `expiry_time` in which case, + // this whole thing return `Duration::ZERO`. + let expiry_time: SystemTime = expiry.into(); + return expiry_time.duration_since(now).unwrap_or(Duration::ZERO); }, // Malformed Expires header, shouldn't be used to construct a valid response. - None if response.headers.contains_key(header::EXPIRES) => return Duration::seconds(0i64), + None if response.headers.contains_key(header::EXPIRES) => return Duration::ZERO, _ => {}, } // Calculating Heuristic Freshness @@ -229,22 +221,20 @@ fn get_response_expiry(response: &Response) -> Duration { // // 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. - let max_heuristic = Duration::hours(24) - age; + let max_heuristic = Duration::from_secs(24 * 60 * 60) - age; let heuristic_freshness = if let Some(last_modified) = // If the response has a Last-Modified header field, // caches are encouraged to use a heuristic expiration value // that is no more than some fraction of the interval since that time. response.headers.typed_get::() { - let current = time::now().to_timespec(); + // `time_since_last_modified` will be `Duration::ZERO` if `last_modified` is + // after `now`. let last_modified: SystemTime = last_modified.into(); - 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%. - let raw_heuristic_calc = (current - last_modified) / 10; + let time_since_last_modified = now.duration_since(last_modified).unwrap_or_default(); + // A typical setting of this fraction might be 10%. + let raw_heuristic_calc = time_since_last_modified / 10; if raw_heuristic_calc < max_heuristic { raw_heuristic_calc } else { @@ -265,36 +255,35 @@ fn get_response_expiry(response: &Response) -> Duration { } } // Requires validation upon first use as default. - Duration::seconds(0i64) + Duration::ZERO } /// Request Cache-Control Directives /// fn get_expiry_adjustment_from_request_headers(request: &Request, expires: Duration) -> Duration { - let directive = match request.headers.typed_get::() { - Some(data) => data, - None => return expires, + let Some(directive) = request.headers.typed_get::() else { + return expires; }; if let Some(max_age) = directive.max_stale() { - return expires + Duration::from_std(max_age).unwrap(); - } - if let Some(max_age) = directive.max_age() { - let max_age = Duration::from_std(max_age).unwrap(); - if expires > max_age { - return Duration::min_value(); - } - return expires - max_age; + return expires + max_age; } + + match directive.max_age() { + Some(max_age) if expires > max_age => return Duration::ZERO, + Some(max_age) => return expires - max_age, + None => {}, + }; + if let Some(min_fresh) = directive.min_fresh() { - let min_fresh = Duration::from_std(min_fresh).unwrap(); if expires < min_fresh { - return Duration::min_value(); + return Duration::ZERO; } return expires - min_fresh; } + if directive.no_cache() || directive.no_store() { - return Duration::min_value(); + return Duration::ZERO; } expires @@ -343,9 +332,8 @@ fn create_cached_response( let expires = cached_resource.data.expires; let adjusted_expires = get_expiry_adjustment_from_request_headers(request, expires); - let now = Duration::seconds(time::now().to_timespec().sec); - let last_validated = Duration::seconds(cached_resource.data.last_validated.to_timespec().sec); - let time_since_validated = now - last_validated; + let time_since_validated = Instant::now() - cached_resource.data.last_validated; + // TODO: take must-revalidate into account // TODO: if this cache is to be considered shared, take proxy-revalidate into account // @@ -808,7 +796,7 @@ impl HttpCache { let entry_key = CacheKey::from_servo_url(url); if let Some(cached_resources) = self.entries.get_mut(&entry_key) { for cached_resource in cached_resources.iter_mut() { - cached_resource.data.expires = Duration::seconds(0i64); + cached_resource.data.expires = Duration::ZERO; } } } @@ -892,7 +880,7 @@ impl HttpCache { raw_status: response.raw_status.clone(), url_list: response.url_list.clone(), expires: expiry, - last_validated: time::now(), + last_validated: Instant::now(), }), }; let entry = self.entries.entry(entry_key).or_default(); diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index ea13b966123..ce74fdaba78 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -2097,7 +2097,6 @@ async fn cors_preflight_fetch( .typed_get::() .map(|acma| acma.into()) .unwrap_or(Duration::from_secs(5)); - let max_age = max_age.as_secs() as u32; // Substep 10 // TODO: Need to define what an imposed limit on max-age is