cache_rules 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,111 @@
1
+ # This Source Code Form is subject to the terms of the Mozilla Public
2
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
4
+ #
5
+ # Copyright (c) 2014-2015 Alexander Williams, Unscramble <license@unscramble.jp>
6
+
7
+ module CacheRules
8
+ extend self
9
+
10
+ # HTTP Header Validators
11
+ #
12
+ # Parameters must always be normalized
13
+ #
14
+ # Return must always be 0 or 1
15
+ #
16
+ # The If-Match and If-Unmodified-Since conditional header fields are not applicable to a cache.
17
+ # source: https://tools.ietf.org/html/rfc7234#section-4.3.2
18
+
19
+ def validate_cached?(headers)
20
+ headers[:cached].length > 0 ? 1 : 0
21
+ end
22
+
23
+ # Precedence: If-None-Match (ETag), then If-Modified-Since (Last-Modified)
24
+ # source: https://tools.ietf.org/html/rfc7232#section-6
25
+ def validate_precond_match?(headers)
26
+ request, cached = headers.values_at :request, :cached
27
+ return 0 if cached.length == 0
28
+
29
+ # Return when the If-None-Match header exists, ignore If-Modified-Since
30
+ # source: https://tools.ietf.org/html/rfc7232#section-3.3
31
+ etag_match = helper_etag(request, cached)
32
+ return etag_match ? 1 : 0 unless etag_match.nil?
33
+
34
+ helper_last_modified(request, cached) ? 1 : 0
35
+ end
36
+
37
+ # Compare headers to see if the cached request is expired (Freshness)
38
+ # source: https://tools.ietf.org/html/rfc7234#section-4.2
39
+ def validate_expired?(headers)
40
+ return 0 if headers[:cached].length == 0
41
+
42
+ freshness_lifetime, current_age = helper_freshness_lifetime.call headers[:cached]
43
+
44
+ response_is_fresh = freshness_lifetime.to_i > current_age
45
+
46
+ response_is_fresh ? 0 : 1
47
+ end
48
+
49
+ def validate_only_if_cached?(headers)
50
+ headers[:request]['Cache-Control'] && headers[:request]['Cache-Control']['only-if-cached'] ? 1 : 0
51
+ end
52
+
53
+ # Serving Stale Responses
54
+ # source: https://tools.ietf.org/html/rfc7234#section-4.2.4
55
+ def validate_allow_stale?(headers)
56
+ request, cached = headers.values_at :request, :cached
57
+ return 0 if cached.length == 0 || helper_validate_allow_stale(request, cached)
58
+
59
+ freshness_lifetime, current_age = helper_freshness_lifetime.call cached
60
+
61
+ max_stale = helper_max_stale.call request['Cache-Control'], freshness_lifetime, current_age
62
+ min_fresh = helper_min_fresh.call request['Cache-Control'], freshness_lifetime, current_age
63
+
64
+ (max_stale && min_fresh != false) || (max_stale.nil? && min_fresh) ? 1 : 0
65
+ end
66
+
67
+ # Response Cache-Control Directives
68
+ # source: https://tools.ietf.org/html/rfc7234#section-5.2.2
69
+ def validate_must_revalidate?(headers)
70
+ return 1 if headers[:cached].length == 0
71
+
72
+ # source: https://tools.ietf.org/html/rfc7234#section-5.2.2.1
73
+ # source: https://tools.ietf.org/html/rfc7234#section-5.2.2.7
74
+ (( cached = headers[:cached]['Cache-Control'] )) && ( cached['must-revalidate'] || cached['proxy-revalidate'] ) ? 1 : 0
75
+ end
76
+
77
+ # Verify if we're explicitly told not to cache the response
78
+ def validate_no_cache?(headers)
79
+ request_headers, cached_headers = headers.values_at :request, :cached
80
+ return 1 if cached_headers.length == 0
81
+
82
+ # Must revalidate if this request header exists
83
+ # source: https://tools.ietf.org/html/rfc7234#section-5.2.1.4
84
+ return 1 if (( request = request_headers['Cache-Control'] )) &&
85
+ request_headers['Cache-Control']['no-cache']
86
+
87
+ # source: https://tools.ietf.org/html/rfc7234#section-5.2.2.2
88
+ # source: https://tools.ietf.org/html/rfc7234#section-3.2
89
+ return 1 if (( cached = cached_headers['Cache-Control'] )) &&
90
+ helper_no_cache.call(cached_headers) ||
91
+ (cached['no-cache'] && cached['no-cache']['quoted_string'].nil?) ||
92
+ (cached['s-maxage'] && cached['s-maxage']['token'].to_s == "0") ||
93
+ (cached['max-age'] && cached['max-age']['token'].to_s == "0")
94
+
95
+ # source: https://tools.ietf.org/html/rfc7234#section-5.4
96
+ # Legacy support for HTTP/1.0 Pragma header
97
+ return 1 if request_headers['Pragma'] && request_headers['Pragma']['no-cache']
98
+
99
+ return 0
100
+ end
101
+
102
+ def validate_is_error?(headers)
103
+ headers[:response]['Status'].to_i.between?(500,599) ? 1 : 0
104
+ end
105
+
106
+ def validate_validator_match?(headers)
107
+ request, response = headers.values_at :request, :response
108
+ response['ETag'] && request['If-None-Match'] && request['If-None-Match'].include?(response['ETag']) ? 1 : 0
109
+ end
110
+
111
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'coveralls'
2
+ require 'fakeweb'
3
+ require 'simplecov'
4
+
5
+ SimpleCov.start do
6
+ add_filter '/test/'
7
+ add_filter '.bundle'
8
+ minimum_coverage 100
9
+ end
10
+
11
+ require './lib/cache_rules'
12
+ require 'minitest/autorun'
13
+ require 'minitest/unit'
14
+ require 'minitest/reporters'
15
+
16
+ Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
17
+
18
+ Coveralls.wear!
@@ -0,0 +1,253 @@
1
+ class TestCacheRules < MiniTest::Test
2
+
3
+ def setup
4
+ @request_if_none_match = CacheRules.normalize.call({ "Host" => "test.com", "If-None-Match" => "*", "Cache-Control" => "max-stale=100000000" })
5
+ @request_if_modified_since_yes = CacheRules.normalize.call({ "Host" => "test.com", "If-Modified-Since" => "Thu, 01 Jan 2015 07:03:45 GMT", "Cache-Control" => "max-stale=100000000" })
6
+ @request_if_modified_since_no = CacheRules.normalize.call({ "Host" => "test.com" })
7
+ @cached_headers = {
8
+ "Date" => {"httpdate"=>"Thu, 01 Jan 2015 07:03:45 GMT", "timestamp"=>1420095825},
9
+ "Cache-Control" => {
10
+ "public" => {"token"=>nil, "quoted_string"=>nil}
11
+ },
12
+ "X-Cache-Req-Date" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625},
13
+ "X-Cache-Res-Date" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}
14
+ }
15
+ end
16
+
17
+ def test_get_money
18
+ got_money = CacheRules::Everything::Around::Me.get_the_money
19
+
20
+ assert_equal got_money, "Dolla Dolla Bill Y'all"
21
+ end
22
+
23
+ def test_validate_column0
24
+ request = {"Host"=>"test.url"}
25
+
26
+ result = CacheRules.validate('http://test.url/test1', request)
27
+
28
+ assert_equal result[:code], 307
29
+ assert_nil result[:body]
30
+ assert_equal result[:headers]['Cache-Lookup'], 'MISS'
31
+ assert_equal result[:headers]['Location'], "http://test.url/test1"
32
+ end
33
+
34
+ def test_validate_column1
35
+ request = {"Host"=>"test.url","Cache-Control"=>"only-if-cached"}
36
+
37
+ result = CacheRules.validate('http://test.url/test1', request)
38
+
39
+ assert_equal result[:code], 504
40
+ assert_equal result[:body], 'Gateway Timeout'
41
+ assert_equal result[:headers]['Cache-Lookup'], 'MISS'
42
+ end
43
+
44
+ def test_validate_column2
45
+ request = {"Host"=>"test.url"}
46
+ cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Cache-Control"=>{"s-maxage"=>{"token"=>"100000000", "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}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}}
47
+
48
+ result = CacheRules.validate('http://test.url/test1', request, cached)
49
+
50
+ assert_equal result[:code], 200
51
+ assert_equal result[:body], 'cached'
52
+ assert_equal result[:headers]['Cache-Lookup'], 'HIT'
53
+ end
54
+
55
+ def test_validate_column3
56
+ request = {"Host"=>"test.url", "If-None-Match" => "*"}
57
+ cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Cache-Control"=>{"s-maxage"=>{"token"=>"100000000", "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}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "ETag" => "\"validEtag\""}
58
+
59
+ result = CacheRules.validate('http://test.url/test1', request, cached)
60
+
61
+ assert_equal result[:code], 304
62
+ assert_nil result[:body]
63
+ assert_equal result[:headers]['Cache-Lookup'], 'HIT'
64
+ end
65
+
66
+ def test_validate_column4
67
+ request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=10000000"}
68
+ 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}}}
69
+
70
+ result = CacheRules.validate('http://test.url/test1', request, cached)
71
+
72
+ assert_equal result[:code], 200
73
+ assert_equal result[:body], 'stale'
74
+ assert_equal result[:headers]['Cache-Lookup'], 'STALE'
75
+ assert_equal result[:headers]['Warning'], "110 - \"Response is Stale\""
76
+ end
77
+
78
+ def test_validate_column5
79
+ request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=10000000", "If-None-Match"=>"*"}
80
+ 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}}}
81
+
82
+ result = CacheRules.validate('http://test.url/test1', request, cached)
83
+
84
+ assert_equal result[:code], 304
85
+ assert_nil result[:body]
86
+ assert_equal result[:headers]['Cache-Lookup'], 'STALE'
87
+ assert_equal result[:headers]['Warning'], "110 - \"Response is Stale\""
88
+ end
89
+
90
+ def test_validate_column6
91
+ request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>"*"}
92
+ 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}}}
93
+
94
+ result = CacheRules.validate('http://test.url/test1', request, cached)
95
+
96
+ assert_equal result[:code], 504
97
+ assert_equal result[:body], 'Gateway Timeout'
98
+ assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
99
+ end
100
+
101
+ def test_validate_column7
102
+ request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>"*"}
103
+ 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}}}
104
+
105
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
106
+ result = CacheRules.validate('http://test.url/test1', request, cached)
107
+
108
+ assert_equal result[:code], 307
109
+ assert_nil result[:body]
110
+ assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
111
+ assert_equal result[:headers]['Location'], "http://test.url/test1"
112
+ end
113
+
114
+ def test_validate_column8
115
+ request = {"Host"=>"test.url", "Cache-Control"=>"max-stale=0", "If-None-Match"=>"*"}
116
+ 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}}}
117
+
118
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
119
+ result = CacheRules.validate('http://test.url/test1', request, cached)
120
+
121
+ assert_equal result[:code], 307
122
+ assert_nil result[:body]
123
+ assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
124
+ assert_equal result[:headers]['Location'], "http://test.url/test1"
125
+ end
126
+
127
+ def test_revalidate_response_column0
128
+ request = {"Host"=>"test.url", "If-None-Match"=>["*"], "Cache-Control"=>{"max-age"=>{"token"=>"100000000", "quoted_string"=>nil}}}
129
+ cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Cache-Control"=>{"s-maxage"=>{"token"=>"100000000", "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}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}}
130
+
131
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
132
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
133
+
134
+ assert_equal result[:code], 200
135
+ assert_equal result[:body], 'cached'
136
+ assert_equal result[:headers]['Cache-Lookup'], 'REVALIDATED'
137
+ end
138
+
139
+ def test_revalidate_response_column1
140
+ request = {"Host"=>"test.url", "If-None-Match"=>["\"validEtag\""], "Cache-Control"=>{"max-age"=>{"token"=>"100000000", "quoted_string"=>nil}}}
141
+ cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Cache-Control"=>{"s-maxage"=>{"token"=>"100000000", "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}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "ETag" => "\"validEtag\""}
142
+
143
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["304", "Not Modified"], :date => "Sat, 03 Jan 2015 07:15:45 GMT", :ETag => "\"validEtag\"")
144
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
145
+
146
+ assert_equal result[:code], 304
147
+ assert_nil result[:body]
148
+ assert_equal result[:headers]['Cache-Lookup'], 'REVALIDATED'
149
+ assert_equal result[:headers]['ETag'], "\"validEtag\""
150
+ end
151
+
152
+ def test_revalidate_response_column2_5xx
153
+ request = {"Host"=>"test.url", "If-None-Match"=>["\"validEtag\""], "Cache-Control"=>{"max-age"=>{"token"=>"100000000", "quoted_string"=>nil}}}
154
+ cached = {"Date"=>{"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "Cache-Control"=>{"s-maxage"=>{"token"=>"100000000", "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}, "Last-Modified" => {"httpdate"=>"Sat, 03 Jan 2015 07:03:45 GMT", "timestamp"=>1420268625}, "ETag" => "\"validEtag\""}
155
+
156
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["504", "Gateway Timeout"], :date => "Sat, 03 Jan 2015 07:15:45 GMT", :ETag => "\"validEtag\"")
157
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
158
+
159
+ assert_equal result[:code], 504
160
+ assert_equal result[:body], 'Gateway Timeout'
161
+ assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
162
+ end
163
+
164
+ def test_revalidate_response_column2_error
165
+ result = CacheRules.revalidate_response('ftp://test.url/test1', {}, {})
166
+
167
+ assert_equal result[:code], 504
168
+ assert_equal result[:body], 'Gateway Timeout'
169
+ assert result[:error]
170
+ end
171
+
172
+ def test_revalidate_response_column3
173
+ request = {"Host"=>"test.url", "If-None-Match"=>["*"], "Cache-Control"=>{"max-stale"=>{"token"=>"100000000", "quoted_string"=>nil}}}
174
+ 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}, "ETag" => "\"validEtag\""}
175
+
176
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["504", "Gateway Timeout"], :date => "Sat, 03 Jan 2015 07:15:45 GMT")
177
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
178
+
179
+ assert_equal result[:code], 200
180
+ assert_equal result[:body], 'stale'
181
+ assert_equal result[:headers]['Warning'], "111 - \"Revalidation Failed\""
182
+ assert_equal result[:headers]['Cache-Lookup'], 'STALE'
183
+ end
184
+
185
+ def test_revalidate_response_column4
186
+ request = {"Host"=>"test.url", "If-None-Match"=>["\"validEtag\""], "Cache-Control"=>{"max-stale"=>{"token"=>"100000000", "quoted_string"=>nil}}}
187
+ 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}, "ETag" => "\"validEtag\""}
188
+
189
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["504", "Gateway Timeout"], :date => "Sat, 03 Jan 2015 07:15:45 GMT", :ETag => "\"validEtag\"")
190
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
191
+
192
+ assert_equal result[:code], 304
193
+ assert_nil result[:body]
194
+ assert_equal result[:headers]['Warning'], "111 - \"Revalidation Failed\""
195
+ assert_equal result[:headers]['Cache-Lookup'], 'STALE'
196
+ assert_equal result[:headers]['ETag'], "\"validEtag\""
197
+ end
198
+
199
+ def test_revalidate_response_column5
200
+ request = {"Host"=>"test.url", "If-None-Match"=>["*"], "Cache-Control"=>{"max-stale"=>{"token"=>"100000000", "quoted_string"=>nil}}}
201
+ 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}}
202
+
203
+ FakeWeb.register_uri(:head, "http://test.url/test1", :status => ["200", "OK"])
204
+ result = CacheRules.revalidate_response('http://test.url/test1', request, cached)
205
+
206
+ assert_equal result[:code], 307
207
+ assert_nil result[:body]
208
+ assert_equal result[:headers]['Cache-Lookup'], 'EXPIRED'
209
+ assert_equal result[:headers]['Location'], "http://test.url/test1"
210
+ end
211
+
212
+ def test_make_http_request_with_entity_tag
213
+ result = CacheRules.make_request.call('http://test.url', @request_if_none_match, @cached_headers)
214
+ http = eval "http", result.binding
215
+ request = eval "request", result.binding
216
+
217
+ assert_kind_of Proc, result
218
+ assert_kind_of FalseClass, http.use_ssl?
219
+ assert_equal http.address, 'test.url'
220
+ assert_equal http.port, 80
221
+ assert_equal request.method, 'HEAD'
222
+ end
223
+
224
+ def test_make_http_request_with_last_modified
225
+ result = CacheRules.make_request.call('http://test.url', @request_if_modified_since_yes, @cached_headers)
226
+ http = eval "http", result.binding
227
+ request = eval "request", result.binding
228
+
229
+ assert_kind_of Proc, result
230
+ assert_kind_of FalseClass, http.use_ssl?
231
+ assert_equal http.address, 'test.url'
232
+ assert_equal http.port, 80
233
+ assert_equal request.method, 'HEAD'
234
+ end
235
+
236
+ def test_make_http_request_without_preconditions
237
+ result = CacheRules.make_request.call('https://test.url', @request_if_modified_since_no, @cached_headers)
238
+ http = eval "http", result.binding
239
+ request = eval "request", result.binding
240
+
241
+ assert_kind_of Proc, result
242
+ assert_kind_of TrueClass, http.use_ssl?
243
+ assert_equal http.address, 'test.url'
244
+ assert_equal http.port, 443
245
+ assert_equal request.method, 'HEAD'
246
+ end
247
+
248
+ def test_raises_an_error_if_the_url_is_invalid
249
+ assert_raises(SocketError) { CacheRules.make_request.call('http://test.urlzzz', {}, {}).call }
250
+ assert_raises(NoMethodError) { CacheRules.make_request.call('ftp://test.urlzzz', {}, {}).call }
251
+ end
252
+
253
+ end
@@ -0,0 +1,135 @@
1
+ class TestFormatting < MiniTest::Test
2
+
3
+ def setup
4
+ @request_headers = {
5
+ "Version" => "HTTP/1.1",
6
+ "user-agent" => "test user agent",
7
+ "Cookie" => "testcookie=deleteme",
8
+ "If-Modified-Since" => "Thu, 01 Jan 2015 07:03:42 GMT",
9
+ "Cache-Control" => "max-stale=1000, no-cache=\"Cookie\", no-store",
10
+ "Referer" => "http://some.url"
11
+ }
12
+ @cached_headers = {
13
+ "Retry-After" => 60,
14
+ "Cache-Control" => {
15
+ "public" => {"token"=>nil, "quoted_string"=>nil},
16
+ "max-stale" => {"token"=>"1000", "quoted_string"=>nil},
17
+ "no-cache" => {"token"=>nil, "quoted_string"=>"Cookie"}
18
+ },
19
+ "Last-Modified" => {"httpdate"=>"Thu, 01 Jan 2015 07:03:42 GMT", "timestamp"=>1420095822},
20
+ "ETag" => "\"validEtag\""
21
+ }
22
+ @nocache_headers = {"Version"=>"HTTP/1.1", "Set-Cookie"=>"test", "Cookie"=>"test", "Accept-Ranges"=>"test", "Range"=>"test", "If-Range"=>"test", "Content-Range"=>"test", "Referer"=>"http://test.url", "From"=>"test", "Authorization"=>"test", "Proxy-Authorization"=>"test", "User-Agent"=>"test", "If-Modified-Since"=>"invalid date"}
23
+ @duplicate_headers = [
24
+ ['Accept', 'text/html'],
25
+ ['Accept', 'application/json']
26
+ ]
27
+ @non_duplicate_headers = [
28
+ ['Age', '12345'],
29
+ ['Age', '67890']
30
+ ]
31
+ @normalized = {"Version"=>"HTTP/1.1", "User-Agent"=>"test user agent", "If-Modified-Since"=>{"httpdate"=>"Thu, 01 Jan 2015 07:03:42 GMT", "timestamp"=>1420095822}, "Cache-Control"=>{"max-stale"=>{"token"=>"1000", "quoted_string"=>nil}, "no-cache"=>{"token"=>nil, "quoted_string"=>"Cookie"}, "no-store"=>{"token"=>nil, "quoted_string"=>nil}}}
32
+ @normalized_fields = [["Version", "HTTP/1.1"], ["user-agent", "test user agent"], ["Cookie", "testcookie=deleteme"], ["If-Modified-Since", {"httpdate"=>"Thu, 01 Jan 2015 07:03:42 GMT", "timestamp"=>1420095822}], ["Cache-Control", {"max-stale"=>{"token"=>"1000", "quoted_string"=>nil}, "no-cache"=>{"token"=>nil, "quoted_string"=>"Cookie"}, "no-store"=>{"token"=>nil, "quoted_string"=>nil}}], ["Referer", "http://some.url"]]
33
+ @unnormalized_fields = {"Retry-After"=>"60", "Cache-Control"=>"public, max-stale=1000, no-cache=\"Cookie\"", "Last-Modified"=>"Thu, 01 Jan 2015 07:03:42 GMT", "ETag"=>"\"validEtag\""}
34
+ end
35
+
36
+ def test_normalize
37
+ normalized = CacheRules.normalize.call @request_headers
38
+
39
+ assert_kind_of Hash, normalized
40
+
41
+ assert_includes normalized, 'Version'
42
+ assert_includes normalized, 'User-Agent'
43
+ assert_includes normalized, 'If-Modified-Since'
44
+ assert_includes normalized, 'Cache-Control'
45
+
46
+ assert_equal normalized, @normalized
47
+ end
48
+
49
+ def test_format_key
50
+ etag = CacheRules.format_key.call 'etag', 'test value'
51
+ user = CacheRules.format_key.call 'user-agent', 'test user agent'
52
+ vary = CacheRules.format_key.call 'Vary', '*'
53
+
54
+ assert_equal etag, ['ETag', 'test value']
55
+ assert_equal user, ['User-Agent', 'test user agent']
56
+ assert_equal vary, ['Vary', '*']
57
+ end
58
+
59
+ def test_clean
60
+ cleaned = CacheRules.clean.call @nocache_headers
61
+ # if_modified = CacheRules.clean.call @nocache_headers
62
+ assert_equal cleaned, [['Version', 'HTTP/1.1'], ['User-Agent', 'test']]
63
+ end
64
+
65
+ def test_combine
66
+ combined = CacheRules.combine.call @duplicate_headers
67
+ not_combined = CacheRules.combine.call @non_duplicate_headers
68
+
69
+ assert_equal combined, [['Accept', 'text/html, application/json']]
70
+ assert_equal not_combined, [['Age', '12345']]
71
+ end
72
+
73
+ def test_normalize_fields
74
+ normalized = CacheRules.normalize_fields.call @request_headers
75
+
76
+ assert_kind_of Array, normalized
77
+ assert_equal normalized, @normalized_fields
78
+ end
79
+
80
+ def test_unnormalize_fields
81
+ unnormalized = CacheRules.unnormalize_fields.call @cached_headers
82
+
83
+ assert_kind_of Hash, unnormalized
84
+ assert_equal unnormalized, @unnormalized_fields
85
+ end
86
+
87
+ def test_format_field
88
+ httpdate = CacheRules.format_field.call 'If-Modified-Since', @request_headers['If-Modified-Since']
89
+ cache_control = CacheRules.format_field.call 'Cache-Control', @request_headers['Cache-Control']
90
+ csv = CacheRules.format_field.call 'Accept', 'text/html, application/json'
91
+ retry_after = CacheRules.format_field.call 'Retry-After', 60
92
+ retry_after_abs = CacheRules.format_field.call 'Retry-After', -100
93
+ retry_after_date= CacheRules.format_field.call 'Retry-After', 'Thu, 01 Jan 2015 07:03:42 GMT', false
94
+ other = CacheRules.format_field.call 'Version', @request_headers['Version'], false
95
+
96
+ cur_time = Time.now.gmtime.to_i
97
+ baddate = CacheRules.format_field.call 'If-Modified-Since', 'invalid date'
98
+
99
+ assert_kind_of Array, baddate
100
+
101
+ assert_equal httpdate, ["If-Modified-Since", {"httpdate"=>"Thu, 01 Jan 2015 07:03:42 GMT", "timestamp"=>1420095822}]
102
+ assert_equal cache_control, ["Cache-Control", {"max-stale"=>{"token"=>"1000", "quoted_string"=>nil}, "no-cache"=>{"token"=>nil, "quoted_string"=>"Cookie"}, "no-store"=>{"token"=>nil, "quoted_string"=>nil}}]
103
+ assert_equal csv, ["Accept", ["text/html", "application/json"]]
104
+ assert_equal retry_after, ["Retry-After", 60]
105
+ assert_equal retry_after_abs, ["Retry-After", 100]
106
+ assert_equal retry_after_date, ["Retry-After", {"httpdate"=>"Thu, 01 Jan 2015 07:03:42 GMT", "timestamp"=>1420095822}]
107
+ assert_equal other, ["Version", "HTTP/1.1"]
108
+
109
+ assert_in_delta baddate[1]["timestamp"], (cur_time - 300), 2, "Check the httpdate_helper, ensure it's 300 seconds, or increase the delta"
110
+ end
111
+
112
+ def test_format_field_string
113
+ cache_control = CacheRules.format_field.call 'Cache-Control', @cached_headers['Cache-Control'], true
114
+ csv = CacheRules.format_field.call 'Accept', ["text/html", "application/json"], true
115
+
116
+ assert_equal cache_control, ["Cache-Control", "public, max-stale=1000, no-cache=\"Cookie\""]
117
+ assert_equal csv, ["Accept", "text/html, application/json"]
118
+ end
119
+
120
+ def test_httpdate_helper
121
+ httpdate = "Sun, 06 Nov 1994 08:49:37 GMT"
122
+ rfc850 = "Sunday, 06-Nov-94 08:49:37 GMT"
123
+ ansi_c = "Sun Nov 6 08:49:37 1994"
124
+ result = 784111777
125
+
126
+ timestamp1 = CacheRules.httpdate_helper httpdate
127
+ timestamp2 = CacheRules.httpdate_helper rfc850
128
+ timestamp3 = CacheRules.httpdate_helper ansi_c
129
+
130
+ assert_equal timestamp1, result
131
+ assert_equal timestamp2, result
132
+ assert_equal timestamp3, result
133
+ end
134
+
135
+ end