Skip to content
This repository has been archived by the owner on Dec 3, 2019. It is now read-only.

Commit

Permalink
Simplify revalidation table
Browse files Browse the repository at this point in the history
  • Loading branch information
aw committed May 3, 2015
1 parent 2098e94 commit 86213cd
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 60 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

# 0.4.0 (2015-05-03)

* Modify 'revalidation' table so it doesn't check if the response is expired
* Ensure validator matching works with '*'
* Fix tests

# 0.3.0 (2015-05-03)

* Make cache rules consistent based RFC spec
Expand Down
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,19 +66,18 @@ HTTP Caching request.
### Revalidation Table

| Revalidation Conditions | | | | | | |
| :------------------------| :---: | :---: | :---: | :---: | :---: | :---: |
| **Did we get an error or 5xx code?** | 0 | 0 | 1 | 1 | 1 | 0 |
| **Is the cached data expired?** | 0 | 0 | - | - | - | 1 |
| **Is there an if-only-cached header?** | - | - | 0 | 1 | 1 | - |
| **Do Etags/If-None-Match match?** | 0 || - | 0 | 1 | - |
| :------------------------| :---: | :---: | :---: | :---: | :---: |
| **Did we get an error or 5xx code?** | 0 | 0 | 1 | 1 | 1 |
| **Is there an if-only-cached header?** | - | - | 0 | 1 | 1 |
| **Do Etags/If-None-Match match?** | 0 || - | 0 | 1 |
| |
| **Actions** | |
| **Revalidate** | | | | | | |
| **Add Age header (regeneratte**) | 1 | 1 | | 1 | 1 | |
| **Add Cache-Lookup header** | REVALIDATED | REVALIDATED | EXPIRED | STALE | STALE | EXPIRED |
| **Add Warning header** | | | | 111 | 111 | |
| **Return Status Code** | 200 | 304 | 504 | 200 | 304 | 307 |
| **Return Body** | cached | | | stale | | |
| **Revalidate** | | | | | |
| **Add Age header (regeneratte**) | 1 | 1 | | 1 | 1 |
| **Add Cache-Lookup header** | REVALIDATED | REVALIDATED | EXPIRED | STALE | STALE |
| **Add Warning header** | | | | 111 | 111 |
| **Return Status Code** | 200 | 304 | 504 | 200 | 304 |
| **Return Body** | cached | | | stale | |

## RFC compliance

Expand Down
2 changes: 1 addition & 1 deletion cache_rules.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require 'date'

Gem::Specification.new do |s|
s.name = 'cache_rules'
s.version = '0.3.0'
s.version = '0.4.0'

s.date = Date.today.to_s

Expand Down
13 changes: 6 additions & 7 deletions lib/cache_rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,17 @@ module CacheRules
# Decision table for revalidated responses
RESPONSE_TABLE = {
:conditions => {
'is_error' => [0, 0, 1, 1, 1, 0],
'expired' => [0, 0, X, X, X, 1],
'allow_stale' => [X, X, 0, 1, 1, X],
'validator_match' => [0, 1, X, 0, 1, X]
'is_error' => [0, 0, 1, 1, 1],
'allow_stale' => [X, X, 0, 1, 1],
'validator_match' => [0, 1, X, 0, 1]
},
:actions => {
'revalidate' => [],
'add_age' => [1, 1, X, 1, 1],
'add_x_cache' => %w(REVALIDATED REVALIDATED EXPIRED STALE STALE EXPIRED),
'add_x_cache' => %w(REVALIDATED REVALIDATED EXPIRED STALE STALE),
'add_warning' => [X, X, X, '111 - "Revalidation Failed"', '111 - "Revalidation Failed"'],
'add_status' => [200, 304, 504, 200, 304, 307],
'return_body' => ['cached', X, 'Gateway Timeout', 'stale', X]
'add_status' => [200, 304, 504, 200, 304],
'return_body' => ['cached', X, 'Gateway Timeout', 'stale']
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ def validate_is_error?(headers)

def validate_validator_match?(headers)
request, response = headers.values_at :request, :response
to_bit { response['ETag'] && request['If-None-Match'] && request['If-None-Match'].include?(response['ETag']) }
to_bit { response['ETag'] && request['If-None-Match'] && (request['If-None-Match'].include?(response['ETag']) || request['If-None-Match'].include?("*")) }
end

end
39 changes: 12 additions & 27 deletions test/test_cache_rules.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def test_validate_column4

result = CacheRules.validate('http://test.url/test1', request, cached)

assert_equal result[:code], 200
assert_equal 200, result[:code]
assert_equal result[:body], 'stale'
assert_equal result[:headers]['Cache-Lookup'], 'STALE'
assert_equal result[:headers]['Warning'], "110 - \"Response is Stale\""
Expand Down Expand Up @@ -110,29 +110,27 @@ def test_validate_column6
end

def test_validate_column7
request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>"*"}
request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>["*"]}
cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "X-Cache-Req-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "X-Cache-Res-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "ETag" => "\"validEtag\"", "Cache-Control"=>{"max-age"=>{"token"=>"100", "quoted_string" => nil}, "must-revalidate"=>{"token"=>nil, "quoted_string"=>nil}}}

FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
result = CacheRules.validate('http://test.url/test1', request, cached)

assert_equal result[:code], 307
assert_nil result[:body]
assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
assert_equal result[:headers]['Location'], "http://test.url/test1"
assert_equal result[:code], 200
assert_equal result[:body], "cached"
assert_equal result[:headers]['Cache-Lookup'], 'REVALIDATED'
end

def test_validate_column8
request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>"*"}
request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>["*"]}
cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "X-Cache-Req-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "X-Cache-Res-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "ETag" => "\"validEtag\"", "Cache-Control"=>{"max-age"=>{"token"=>"100", "quoted_string" => nil}, "no-cache"=>{"token"=>nil, "quoted_string"=>nil}}}

FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
result = CacheRules.validate('http://test.url/test1', request, cached)
FakeWeb.register_uri(:head, "http://test.url/test2", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
result = CacheRules.validate('http://test.url/test2', request, cached)

assert_equal result[:code], 307
assert_nil result[:body]
assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
assert_equal result[:headers]['Location'], "http://test.url/test1"
assert_equal 200, result[:code]
assert_equal result[:body], "cached"
assert_equal result[:headers]['Cache-Lookup'], 'REVALIDATED'
end

def test_revalidate_response_column0
Expand All @@ -144,7 +142,7 @@ def test_revalidate_response_column0

assert_equal result[:code], 200
assert_equal result[:body], 'cached'
assert_equal result[:headers]['Cache-Lookup'], 'REVALIDATED'
assert_equal 'REVALIDATED', result[:headers]['Cache-Lookup']
assert_equal result[:headers]['Warning'], "299 - \"Hello World\""
end

Expand Down Expand Up @@ -210,19 +208,6 @@ def test_revalidate_response_column4
assert_equal result[:headers]['ETag'], "\"validEtag\""
end

def test_revalidate_response_column5
request = {"Host"=>"test.url", "If-None-Match"=>["*"], "Cache-Control"=>{"max-stale"=>{"token"=>"100000000", "quoted_string"=>nil}}}
cached = {"Date"=>{"httpdate"=>"Thu, 01 Jan 2015 07:03:45 GMT", "timestamp"=>1420095825}, "Cache-Control"=>{"public"=>{"token"=>nil, "quoted_string"=>nil}}, "X-Cache-Req-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "X-Cache-Res-Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}}

FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["200", "OK"])
result = CacheRules.revalidate_response('http://test.url/test1', request, cached)

assert_equal result[:code], 307
assert_nil result[:body]
assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
assert_equal result[:headers]['Location'], "http://test.url/test1"
end

def test_make_http_request_with_entity_tag
result = CacheRules.make_request.call('http://test.url', @request_if_none_match, @cached_headers)
http = eval "http", result.binding
Expand Down
3 changes: 0 additions & 3 deletions test/test_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ def test_response_revalidate
column2 = CacheRules.helper_response url, act, 2, @cached_headers
column3 = CacheRules.helper_response url, act, 3, @cached_headers
column4 = CacheRules.helper_response url, act, 4, @cached_headers
column5 = CacheRules.helper_response url, act, 5, @cached_headers

assert_equal column0[:body], 'cached'
assert_equal column0[:code], 200
Expand Down Expand Up @@ -157,8 +156,6 @@ def test_response_revalidate
assert_equal column4[:headers]['ETag'], "\"validEtag\""
assert_includes column4[:headers], 'Age'

assert_equal column5, {:body=>nil, :code=>307, :headers=>{"Cache-Lookup"=>"EXPIRED", "Location"=>"http://test.url"}}

assert_kind_of String, column0[:headers]['Age']
end

Expand Down
19 changes: 9 additions & 10 deletions test/test_tables.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class TestTables < MiniTest::Test

def setup
@request_map = {"0000000"=>0, "0000001"=>0, "0000010"=>1, "0000011"=>1, "0000100"=>0, "0000101"=>0, "0000110"=>1, "0000111"=>1, "0001000"=>0, "0001001"=>0, "0001010"=>1, "0001011"=>1, "0001100"=>0, "0001101"=>0, "0001110"=>1, "0001111"=>1, "0010000"=>0, "0010001"=>0, "0010010"=>1, "0010011"=>1, "0010100"=>0, "0010101"=>0, "0010110"=>1, "0010111"=>1, "0011000"=>0, "0011001"=>0, "0011010"=>1, "0011011"=>1, "0011100"=>0, "0011101"=>0, "0011110"=>1, "0011111"=>1, "0100000"=>0, "0100001"=>0, "0100010"=>1, "0100011"=>1, "0100100"=>0, "0100101"=>0, "0100110"=>1, "0100111"=>1, "0101000"=>0, "0101001"=>0, "0101010"=>1, "0101011"=>1, "0101100"=>0, "0101101"=>0, "0101110"=>1, "0101111"=>1, "0110000"=>0, "0110001"=>0, "0110010"=>1, "0110011"=>1, "0110100"=>0, "0110101"=>0, "0110110"=>1, "0110111"=>1, "0111000"=>0, "0111001"=>0, "0111010"=>1, "0111011"=>1, "0111100"=>0, "0111101"=>0, "0111110"=>1, "0111111"=>1, "1000000"=>2, "1000001"=>2, "1000010"=>2, "1000011"=>2, "1000100"=>6, "1000101"=>4, "1000110"=>6, "1000111"=>4, "1001000"=>3, "1001001"=>3, "1001010"=>3, "1001011"=>3, "1001100"=>6, "1001101"=>5, "1001110"=>6, "1001111"=>5, "1010000"=>8, "1010001"=>8, "1010010"=>8, "1010011"=>8, "1010100"=>8, "1010101"=>8, "1010110"=>8, "1010111"=>8, "1011000"=>8, "1011001"=>8, "1011010"=>8, "1011011"=>8, "1011100"=>8, "1011101"=>8, "1011110"=>8, "1011111"=>8, "1100000"=>2, "1100001"=>2, "1100010"=>2, "1100011"=>2, "1100100"=>7, "1100101"=>7, "1100110"=>7, "1100111"=>7, "1101000"=>3, "1101001"=>3, "1101010"=>3, "1101011"=>3, "1101100"=>7, "1101101"=>7, "1101110"=>7, "1101111"=>7, "1110000"=>8, "1110001"=>8, "1110010"=>8, "1110011"=>8, "1110100"=>8, "1110101"=>8, "1110110"=>8, "1110111"=>8, "1111000"=>8, "1111001"=>8, "1111010"=>8, "1111011"=>8, "1111100"=>8, "1111101"=>8, "1111110"=>8, "1111111"=>8}
@response_map = {"0000"=>0, "0001"=>1, "0010"=>0, "0011"=>1, "0100"=>5, "0101"=>5, "0110"=>5, "0111"=>5, "1000"=>2, "1001"=>2, "1010"=>3, "1011"=>4, "1100"=>2, "1101"=>2, "1110"=>3, "1111"=>4}
@response_map = {"000"=>0, "001"=>1, "010"=>0, "011"=>1, "100"=>2, "101"=>2, "110"=>3, "111"=>4}
end

def test_x_value
Expand Down Expand Up @@ -32,12 +32,12 @@ def test_response_table
assert_includes CacheRules::RESPONSE_TABLE, :conditions
assert_includes CacheRules::RESPONSE_TABLE, :actions

assert_equal CacheRules::RESPONSE_TABLE[:conditions].length, 4
assert_equal CacheRules::RESPONSE_TABLE[:conditions].length, 3
assert_equal CacheRules::RESPONSE_TABLE[:actions].length, 6

conditions = CacheRules::RESPONSE_TABLE[:conditions].keys
actions = CacheRules::RESPONSE_TABLE[:actions].keys
assert_equal conditions, %w(is_error expired allow_stale validator_match)
assert_equal conditions, %w(is_error allow_stale validator_match)
assert_equal actions, %w(revalidate add_age add_x_cache add_warning add_status return_body)
end

Expand All @@ -61,15 +61,14 @@ def test_request_map_is_correct
def test_response_map_is_correct
assert_kind_of Hash, CacheRules::RESPONSE_MAP

assert_equal CacheRules::RESPONSE_MAP.length, 16
assert_equal CacheRules::RESPONSE_MAP.length, 8
assert_equal CacheRules::RESPONSE_MAP, @response_map

assert_equal CacheRules::RESPONSE_MAP["0000"], 0
assert_equal CacheRules::RESPONSE_MAP["0001"], 1
assert_equal CacheRules::RESPONSE_MAP["1000"], 2
assert_equal CacheRules::RESPONSE_MAP["1010"], 3
assert_equal CacheRules::RESPONSE_MAP["1011"], 4
assert_equal CacheRules::RESPONSE_MAP["0100"], 5
assert_equal CacheRules::RESPONSE_MAP["000"], 0
assert_equal CacheRules::RESPONSE_MAP["001"], 1
assert_equal CacheRules::RESPONSE_MAP["100"], 2
assert_equal CacheRules::RESPONSE_MAP["110"], 3
assert_equal CacheRules::RESPONSE_MAP["111"], 4
end

end
2 changes: 2 additions & 0 deletions test/test_validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -222,9 +222,11 @@ def test_is_error

def test_validator_match
match = CacheRules.validate_validator_match?({:request => {'If-None-Match'=>["\"myetag\""]}, :response => {'ETag'=>"\"myetag\""}})
match1 = CacheRules.validate_validator_match?({:request => {'If-None-Match'=>["*"]}, :response => {'ETag'=>"\"myetag\""}})
nomatch = CacheRules.validate_validator_match?({:request => {'If-None-Match'=>["\"myetag\""]}, :response => {}})

assert_equal match, 1
assert_equal 1, match1
assert_equal nomatch, 0
end

Expand Down

0 comments on commit 86213cd

Please sign in to comment.