Skip to content

Commit

Permalink
Make invalidating responses at the metastore a bit cleaner
Browse files Browse the repository at this point in the history
  • Loading branch information
rtomayko committed Mar 8, 2009
1 parent 362aed3 commit 3ebd1a3
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
6 changes: 6 additions & 0 deletions lib/rack/cache/headers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ def must_revalidate?
cache_control.must_revalidate || cache_control.proxy_revalidate
end

# Mark the response stale by setting the Age header to be equal to the
# maximum age of the response.
def expire!
headers['Age'] = max_age.to_s if fresh?
end

# The date, as specified by the Date header. When no Date header is present,
# set the Date header to Time.now and return.
def date
Expand Down
25 changes: 18 additions & 7 deletions lib/rack/cache/metastore.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ def lookup(request, entity_store)

req, res = match
if body = entity_store.open(res['X-Content-Digest'])
status = res.delete('X-Status').to_i
response = Rack::Cache::Response.new(status, res, body)
response
restore_response(res, body)
else
# TODO the metastore referenced an entity that doesn't exist in
# the entitystore. we definitely want to return nil but we should
Expand Down Expand Up @@ -73,7 +71,7 @@ def store(request, response, entity_store)
requests_match?(vary, env, stored_env)
end

headers = {'X-Status' => response.status.to_s}.update(response.headers)
headers = persist_response(response)
headers.delete 'Age'

entries.unshift [stored_env, headers]
Expand All @@ -93,11 +91,11 @@ def invalidate(request, entity_store)
key = cache_key(request)
entries =
read(key).map do |req, res|
response = Rack::Cache::Response.new(0, res, nil) # XXX
response = restore_response(res)
if response.fresh?
response.headers['Age'] = (response.max_age + 1).to_s
response.expire!
modified = true
[req, response.headers.to_hash]
[req, persist_response(response)]
else
[req, res]
end
Expand All @@ -116,6 +114,19 @@ def persist_request(request)
env
end

# Converts a stored response hash into a Response object. The caller
# is responsible for loading and passing the body if needed.
def restore_response(hash, body=nil)
status = hash.delete('X-Status').to_i
Rack::Cache::Response.new(status, hash, body)
end

def persist_response(response)
hash = response.headers.to_hash
hash['X-Status'] = response.status.to_s
hash
end

# Determine whether the two environment hashes are non-varying based on
# the vary response header value provided.
def requests_match?(vary, env1, env2)
Expand Down
23 changes: 23 additions & 0 deletions test/headers_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,29 @@ def initialize(*args)
end
end

describe '#expire!' do
it 'sets the Age to be equal to the max-age' do
@res.headers['Cache-Control'] = 'max-age=100'
@res.expire!
@res.headers['Age'].should.equal '100'
end
it 'sets the Age to be equal to the s-maxage when both max-age and s-maxage present' do
@res.headers['Cache-Control'] = 'max-age=100, s-maxage=500'
@res.expire!
@res.headers['Age'].should.equal '500'
end
it 'does nothing when the response is already stale/expired' do
@res.headers['Cache-Control'] = 'max-age=5, s-maxage=500'
@res.headers['Age'] = '1000'
@res.expire!
@res.headers['Age'].should.equal '1000'
end
it 'does nothing when the response does not include freshness information' do
@res.expire!
@res.headers.should.not.include 'Age'
end
end

describe '#ttl' do
it 'is nil when no Expires or Cache-Control headers present' do
@res.ttl.should.be.nil
Expand Down

0 comments on commit 3ebd1a3

Please sign in to comment.