Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

adds support for r-maxage

r-maxage is a new directive that takes precendence over s-maxage and
max-age.

While s-maxage is honored by any shared cache, r-maxage is only taken
into account by reverse proxy caches, and thus ignored by proxy and
private caches. Setting r-maxage allows applications to ensure the
response is only cached by their reverse cache, and thus are able in
particular to purge the cache knowing that it will not remain stale in
intermediate proxy servers.
  • Loading branch information...
commit 1804e30690aca9e4264962e1263e4eb3302fe94f 1 parent 5104c34
@fxn authored
View
14 lib/rack/cache/cachecontrol.rb
@@ -125,6 +125,20 @@ def shared_max_age
end
alias_method :s_maxage, :shared_max_age
+ # If a response includes a r-maxage directive, then for a reverse cache
+ # (but not for a private or proxy cache), the maximum age specified by
+ # this directive overrides the maximum age specified by either the max-age
+ # directive, the s-maxage directive, or the Expires header. The r-maxage
+ # directive also implies the semantics of the proxy-revalidate directive.
+ # i.e., that the reverse cache must not use the entry after it becomes
+ # stale to respond to a subsequent request without first revalidating it
+ # with the origin server. The r-maxage directive is always ignored by
+ # private and proxy caches.
+ def reverse_max_age
+ self['r-maxage'].to_i if key?('r-maxage')
+ end
+ alias_method :r_maxage, :reverse_max_age
+
# Because a cache MAY be configured to ignore a server's specified
# expiration time, and because a client request MAY include a max-
# stale directive (which has a similar effect), the protocol also
View
19 lib/rack/cache/response.rb
@@ -151,13 +151,14 @@ def age
# The number of seconds after the time specified in the response's Date
# header when the the response should no longer be considered fresh. First
- # check for a s-maxage directive, then a max-age directive, and then fall
- # back on an expires header; return nil when no maximum age can be
- # established.
+ # check for a r-maxage directive, then a s-maxage directive, then a max-age
+ # directive, and then fall back on an expires header; return nil when no
+ # maximum age can be established.
def max_age
- cache_control.shared_max_age ||
- cache_control.max_age ||
- (expires && (expires - date))
+ cache_control.reverse_max_age ||
+ cache_control.shared_max_age ||
+ cache_control.max_age ||
+ (expires && (expires - date))
end
# The value of the Expires header as a Time object.
@@ -177,6 +178,12 @@ def shared_max_age=(value)
self.cache_control = cache_control.merge('s-maxage' => value.to_s)
end
+ # Like #shared_max_age= but sets the r-maxage directive, which applies only
+ # to reverse caches.
+ def reverse_max_age=(value)
+ self.cache_control = cache_control.merge('r-maxage' => value.to_s)
+ end
+
# The response's time-to-live in seconds, or nil when no freshness
# information is present in the response. When the responses #ttl
# is <= 0, the response may not be served from cache without first
View
10 test/cachecontrol_test.rb
@@ -93,6 +93,16 @@
cache_control.shared_max_age.should.be.nil
end
+ it 'responds to #reverse_max_age with an integer when r-maxage directive present' do
+ cache_control = Rack::Cache::CacheControl.new('public, r-maxage=600')
+ cache_control.reverse_max_age.should.equal 600
+ end
+
+ it 'responds to #reverse_max_age with nil when no r-maxage directive present' do
+ cache_control = Rack::Cache::CacheControl.new('public')
+ cache_control.reverse_max_age.should.be.nil
+ end
+
it 'responds to #public? truthfully when public directive present' do
cache_control = Rack::Cache::CacheControl.new('public')
cache_control.should.be.public
View
15 test/response_test.rb
@@ -71,15 +71,19 @@
end
describe '#max_age' do
- it 'uses s-maxage cache control directive when present' do
+ it 'uses r-maxage cache control directive when present' do
+ @res.headers['Cache-Control'] = 's-maxage=600, max-age=0, r-maxage=100'
+ @res.max_age.should.equal 100
+ end
+ it 'uses s-maxage cache control when no r-maxage directive present' do
@res.headers['Cache-Control'] = 's-maxage=600, max-age=0'
@res.max_age.should.equal 600
end
- it 'falls back to max-age when no s-maxage directive present' do
+ it 'falls back to max-age when no r/s-maxage directive present' do
@res.headers['Cache-Control'] = 'max-age=600'
@res.max_age.should.equal 600
end
- it 'falls back to Expires when no max-age or s-maxage directive present' do
+ it 'falls back to Expires when no max-age or r/s-maxage directive present' do
@res.headers['Cache-Control'] = 'must-revalidate'
@res.headers['Expires'] = @one_hour_later.httpdate
@res.max_age.should.equal 60 ** 2
@@ -110,6 +114,11 @@
@res.expire!
@res.headers['Age'].should.equal '100'
end
+ it 'sets the Age to be equal to the r-maxage when the three max-age and r/s-maxage present' do
+ @res.headers['Cache-Control'] = 'max-age=100, s-maxage=500, r-maxage=900'
+ @res.expire!
+ @res.headers['Age'].should.equal '900'
+ 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!

0 comments on commit 1804e30

Please sign in to comment.
Something went wrong with that request. Please try again.