Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement a basic HTTP memory cache #4117

Closed
wants to merge 15 commits into from
Closed
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Revalidate must-revalidate entries.

  • Loading branch information
jdm committed Nov 27, 2014
commit 2208da36d814482a95a8dbfcce59aef36fa6f59e
@@ -12,6 +12,7 @@ use resource_task::{Metadata, ProgressMsg, LoadResponse, LoadData, Payload, Done

use servo_util::time::parse_http_timestamp;

use http::headers::etag::EntityTag;
use http::headers::HeaderEnum;
use http::headers::response::HeaderCollection as ResponseHeaderCollection;
use http::method::Get;
@@ -79,13 +80,15 @@ struct PendingResource {
consumers: PendingConsumers,
expires: Duration,
doomed: bool,
last_validated: Tm,

This comment has been minimized.

Copy link
@pcwalton

pcwalton Dec 9, 2014

Contributor

nit: if you switch the order of last_validated and doomed you may shave off a few bytes in the struct

}

/// A complete cached resource.
struct CachedResource {
metadata: Metadata,
body: Vec<u8>,
expires: Duration,
last_validated: Tm,
}

/// A memory cache that tracks incomplete and complete responses, differentiated by
@@ -132,7 +135,7 @@ pub enum RevalidationMethod {
/// The result of a stored Last-Modified or Expires header
ExpiryDate(Tm),
/// The result of a stored Etag header
Etag(String),
Etag(EntityTag),
}

/// Tokenize a header value.
@@ -141,6 +144,11 @@ fn split_header(header: &str) -> Map<&str, &str, CharSplits<char>> {
.map(|v| v.trim())
}

/// Match any header value token.
fn any_token_matches(header: &str, tokens: &[&str]) -> bool {
split_header(header).any(|token| tokens.iter().any(|&s| s == token))
}

/// Determine if a given response is cacheable based on the initial metadata received.

This comment has been minimized.

Copy link
@pcwalton

pcwalton Dec 9, 2014

Contributor

What spec are you using here? Might want to cite it for posterity.

This comment has been minimized.

Copy link
@pcwalton

pcwalton Dec 9, 2014

Contributor

(also so that I can review it) :)

fn response_is_cacheable(metadata: &Metadata) -> bool {
if metadata.status != StatusOk {
@@ -151,10 +159,6 @@ fn response_is_cacheable(metadata: &Metadata) -> bool {
return true;
}

fn any_token_matches(header: &str, tokens: &[&str]) -> bool {
split_header(header).any(|token| tokens.iter().any(|&s| s == token))
}

let headers = metadata.headers.as_ref().unwrap();
match headers.cache_control {
Some(ref cache_control) => {
@@ -278,6 +282,7 @@ impl MemoryCache {
}

resource.expires = get_response_expiry(&metadata);
resource.last_validated = time::now();
resource.consumers = AwaitingBody(metadata, vec!(), chans);
}

@@ -327,6 +332,7 @@ impl MemoryCache {
metadata: metadata,
body: body,
expires: resource.expires,
last_validated: resource.last_validated,
};
self.complete_entries.insert(key.clone(), complete);
}
@@ -351,8 +357,21 @@ impl MemoryCache {
return Revalidate(key, ExpiryDate(time::at(self.base_time + resource.expires)));
}

//TODO: Revalidate if Etag present
//TODO: Revalidate if must-revalidate
let must_revalidate = resource.metadata.headers.as_ref().and_then(|headers| {
headers.cache_control.as_ref().map(|header| {
any_token_matches(header[], &["must-revalidate"])
})
}).unwrap_or(false);

if must_revalidate {
return Revalidate(key, ExpiryDate(resource.last_validated));
}

match resource.metadata.headers.as_ref().and_then(|headers| headers.etag.as_ref()) {
Some(etag) => return Revalidate(key, Etag(etag.clone())),
None => ()
}

//TODO: Revalidate once per session for response with no explicit expiry

self.send_complete_entry(key, start_chan);
@@ -382,6 +401,7 @@ impl MemoryCache {
let resource = PendingResource {
consumers: AwaitingHeaders(vec!(start_chan)),
expires: MAX,
last_validated: time::now(),
doomed: false,
};
info!("creating cache entry for {}", key.url);
@@ -81,7 +81,7 @@ fn load(mut load_data: LoadData, start_chan: Sender<LoadResponse>, cache: Arc<Mu
}

Revalidate(ref _key, Etag(ref etag)) => {
load_data.headers.if_none_match = Some(etag.clone());
load_data.headers.if_none_match = Some(etag.opaque_tag.clone());
true
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.