easy_http_cache 2.2
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.
- data/MIT-LICENSE +21 -0
- data/README.rdoc +155 -0
- data/Rakefile +37 -0
- data/init.rb +1 -0
- data/lib/easy_http_cache.rb +126 -0
- data/test/easy_http_cache_test.rb +212 -0
- metadata +59 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2006 Coda Hale
|
2
|
+
Copyright (c) 2008 José Valim (jose.valim at gmail dot com)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
== Easy HTTP Cache
|
2
|
+
|
3
|
+
Allows Rails applications to do conditional cache easily and in a DRY way
|
4
|
+
(without messing up your actions):
|
5
|
+
|
6
|
+
class ListsController < ApplicationController
|
7
|
+
http_cache :index, :show, :last_modified => :list
|
8
|
+
|
9
|
+
protected
|
10
|
+
def list
|
11
|
+
@list ||= List.find(params[:id])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
It uses :last_modified and :etag keys, that besides Time, String or resources
|
16
|
+
accepts Proc, Method and Symbol that are evaluated within the current controller.
|
17
|
+
|
18
|
+
Read more about each option (more examples at the end of this page):
|
19
|
+
|
20
|
+
:last_modified
|
21
|
+
Used to manipulate Last-Modified header. You can pass any object that responds
|
22
|
+
to :updated_at, :updated_on or :to_time. If you pass a Proc or Method or Symbol,
|
23
|
+
they will be evaluated within the current controller first.
|
24
|
+
|
25
|
+
Finally, if you pass an array, it will get the most recent time to be used.
|
26
|
+
|
27
|
+
:etag
|
28
|
+
Used to manipulate Etag header. The Etag is generated as memcached keys are
|
29
|
+
generated, i.e. calling to_param in the object and then MD5 is applied.
|
30
|
+
|
31
|
+
If you pass a Proc or Method or Symbols, they will be also evaluated within the
|
32
|
+
current controller first.
|
33
|
+
|
34
|
+
:if
|
35
|
+
Only perform http cache if it returns true.
|
36
|
+
|
37
|
+
:unless
|
38
|
+
Only perform http cache if it returns false.
|
39
|
+
|
40
|
+
:method
|
41
|
+
If in :last_modified you want to pass a object that doesn't respond to updated_at,
|
42
|
+
updated_on or to_time, you can specify the method that will be called in this object.
|
43
|
+
|
44
|
+
== Install
|
45
|
+
|
46
|
+
Install Easy HTTP Cache is available on gemcutter, so just execute:
|
47
|
+
|
48
|
+
sudo gem install easy_http_cache
|
49
|
+
|
50
|
+
And add it to your environment.
|
51
|
+
|
52
|
+
== Environment Variables
|
53
|
+
|
54
|
+
As in memcached, you can set ENV['RAILS_CACHE_ID'] or ENV['RAILS_APP_VERSION'] variables
|
55
|
+
to change the Etag that will be generated. This means you can control the cache by setting
|
56
|
+
a timestamp or a version number in ENV['RAILS_APP_VERSION'] everytime you deploy.
|
57
|
+
|
58
|
+
== Examples
|
59
|
+
|
60
|
+
The example below will cache your actions and it will never expire:
|
61
|
+
|
62
|
+
class ListsController < ApplicationController
|
63
|
+
http_cache :index, :show
|
64
|
+
end
|
65
|
+
|
66
|
+
If you do not want to cache when you are showing a flash message (and you
|
67
|
+
usually want that), you can simply do:
|
68
|
+
|
69
|
+
class ListsController < ApplicationController
|
70
|
+
http_cache :index, :show, :if => Proc.new { |c| c.send(:flash).empty? }
|
71
|
+
end
|
72
|
+
|
73
|
+
And if you do not want to cache JSON requests:
|
74
|
+
|
75
|
+
class ListsController < ApplicationController
|
76
|
+
http_cache :index, :show, :unless => Proc.new { |c| c.request.format.json? }
|
77
|
+
end
|
78
|
+
|
79
|
+
Or if you want to expire all http cache before 2008, just do:
|
80
|
+
|
81
|
+
class ListsController < ApplicationController
|
82
|
+
http_cache :index, :show, :last_modified => Time.utc(2008)
|
83
|
+
end
|
84
|
+
|
85
|
+
If you want to cache a list and automatically expire the cache when it changes,
|
86
|
+
just do (it will check updated_at and updated_on on the @list object):
|
87
|
+
|
88
|
+
class ListsController < ApplicationController
|
89
|
+
http_cache :index, :show, :last_modified => :list
|
90
|
+
|
91
|
+
protected
|
92
|
+
def list
|
93
|
+
@list ||= List.find(params[:id])
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
You can also set :etag header (it will generate an etag calling to_param
|
98
|
+
in the object and applying MD5):
|
99
|
+
|
100
|
+
class ListsController < ApplicationController
|
101
|
+
http_cache :index, :show, :etag => :list
|
102
|
+
|
103
|
+
protected
|
104
|
+
def list
|
105
|
+
@list ||= List.find(params[:id])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
If you are using a resource that doesn't respond to updated_at or updated_on,
|
110
|
+
you can pass a method as parameter that will be called in your resources:
|
111
|
+
|
112
|
+
class ListsController < ApplicationController
|
113
|
+
http_cache :index, :show, :last_modified => :list, :method => :cached_at
|
114
|
+
|
115
|
+
protected
|
116
|
+
def list
|
117
|
+
@list ||= List.find(params[:id])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
The sample below will call @list.cached_at to generate Last-Modified header.
|
122
|
+
Finally, you can also pass an array at :last_modified as below:
|
123
|
+
|
124
|
+
class ItemsController < ApplicationController
|
125
|
+
http_cache :index, :show,
|
126
|
+
:last_modified => [ :list, :item ]
|
127
|
+
|
128
|
+
protected
|
129
|
+
def list
|
130
|
+
@list ||= List.find(params[:list_id])
|
131
|
+
end
|
132
|
+
|
133
|
+
def item
|
134
|
+
@item ||= list.items.find(params[:id])
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
This will check which one is the most recent to compare with the
|
139
|
+
"Last-Modified" field sent by the client.
|
140
|
+
|
141
|
+
== What if?
|
142
|
+
|
143
|
+
At this point (or at some point), you will ask what happens if you use :etag
|
144
|
+
and :last_modified at the same time.
|
145
|
+
|
146
|
+
Well, the specification says that if both are sent by the client, both have
|
147
|
+
to be valid for the cache not be considered stale. This subject was already brought
|
148
|
+
to Rails Core group and this is also how Rails' current implementation behaves.
|
149
|
+
|
150
|
+
== Bugs and Feedback
|
151
|
+
|
152
|
+
If you find any issues, please use Github issues tracker.
|
153
|
+
|
154
|
+
Copyright (c) 2009 José Valim
|
155
|
+
http://blog.plataformatec.com.br/
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Run tests for Easy HTTP Cache.'
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.pattern = 'test/**/*_test.rb'
|
8
|
+
t.verbose = true
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Generate documentation for Easy HTTP Cache.'
|
12
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
13
|
+
rdoc.rdoc_dir = 'rdoc'
|
14
|
+
rdoc.title = 'Easy HTTP Cache'
|
15
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
16
|
+
rdoc.rdoc_files.include('README')
|
17
|
+
rdoc.rdoc_files.include('MIT-LICENSE')
|
18
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
require 'jeweler'
|
23
|
+
Jeweler::Tasks.new do |s|
|
24
|
+
s.name = "easy_http_cache"
|
25
|
+
s.version = "2.2"
|
26
|
+
s.summary = "Allows Rails applications to use HTTP cache specifications easily."
|
27
|
+
s.email = "contact@plataformatec.com.br"
|
28
|
+
s.homepage = "http://github.com/josevalim/easy_http_cache"
|
29
|
+
s.description = "Allows Rails applications to use HTTP cache specifications easily."
|
30
|
+
s.authors = ['José Valim']
|
31
|
+
s.files = FileList["[A-Z]*", "lib/**/*", "init.rb"]
|
32
|
+
end
|
33
|
+
|
34
|
+
Jeweler::GemcutterTasks.new
|
35
|
+
rescue LoadError
|
36
|
+
puts "Jeweler, or one of its dependencies, is not available. Install it with: sudo gem install jeweler"
|
37
|
+
end
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'easy_http_cache'
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module ActionController #:nodoc:
|
2
|
+
module Caching
|
3
|
+
module HttpCache
|
4
|
+
def self.included(base) #:nodoc:
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
# Declares that +actions+ should be cached.
|
10
|
+
#
|
11
|
+
def http_cache(*actions)
|
12
|
+
return unless perform_caching
|
13
|
+
options = actions.extract_options!
|
14
|
+
|
15
|
+
options.assert_valid_keys(
|
16
|
+
:last_modified, :method, :etag, :if, :unless
|
17
|
+
)
|
18
|
+
|
19
|
+
http_cache_filter = HttpCacheFilter.new(
|
20
|
+
:method => options.delete(:method),
|
21
|
+
:last_modified => [options.delete(:last_modified)].flatten.compact,
|
22
|
+
:etag => options.delete(:etag)
|
23
|
+
)
|
24
|
+
filter_options = {:only => actions}.merge(options)
|
25
|
+
|
26
|
+
before_filter(http_cache_filter, filter_options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class HttpCacheFilter #:nodoc:
|
31
|
+
def initialize(options = {})
|
32
|
+
@options = options
|
33
|
+
end
|
34
|
+
|
35
|
+
def filter(controller)
|
36
|
+
return unless flash.empty? && controller.request.get?
|
37
|
+
|
38
|
+
last_modified = get_last_modified(controller)
|
39
|
+
controller.response.last_modified = last_modified if last_modified
|
40
|
+
|
41
|
+
processed_etags = get_processed_etags(controller)
|
42
|
+
controller.response.etag = processed_etags if processed_etags
|
43
|
+
|
44
|
+
if controller.request.fresh?(controller.response)
|
45
|
+
controller.send(:head, :not_modified)
|
46
|
+
return false
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
# If :etag is an array, it processes all Methods, Procs and Symbols
|
52
|
+
# and return them as array. If it's an object, we only evaluate it.
|
53
|
+
#
|
54
|
+
def get_processed_etags(controller)
|
55
|
+
if @options[:etag].is_a?(Array)
|
56
|
+
@options[:etag].collect do |item|
|
57
|
+
evaluate_method(item, controller)
|
58
|
+
end
|
59
|
+
elsif @options[:etag]
|
60
|
+
evaluate_method(@options[:etag], controller)
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# We perform Last-Modified HTTP Cache when the option :last_modified is sent
|
67
|
+
# or no other cache mechanism is set (then we set a very old timestamp).
|
68
|
+
#
|
69
|
+
def get_last_modified(controller)
|
70
|
+
# Then, if @options[:last_modified] is not empty, we run through the array
|
71
|
+
# processing all objects (if needed) and return the latest one to be used.
|
72
|
+
#
|
73
|
+
if !@options[:last_modified].empty?
|
74
|
+
@options[:last_modified].collect do |item|
|
75
|
+
evaluate_time(item, controller)
|
76
|
+
end.compact.sort.last
|
77
|
+
elsif @options[:etag].blank?
|
78
|
+
Time.utc(0)
|
79
|
+
else
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def evaluate_method(method, controller)
|
85
|
+
case method
|
86
|
+
when Symbol
|
87
|
+
controller.__send__(method)
|
88
|
+
when Proc, Method
|
89
|
+
method.call(controller)
|
90
|
+
else
|
91
|
+
method
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Evaluate the objects sent and return time objects
|
96
|
+
#
|
97
|
+
# It process Symbols, String, Proc and Methods, get its results and then
|
98
|
+
# call :to_time, :updated_at, :updated_on on it.
|
99
|
+
#
|
100
|
+
# If the parameter :method is sent, it will try to call it on the object before
|
101
|
+
# calling :to_time, :updated_at, :updated_on.
|
102
|
+
#
|
103
|
+
def evaluate_time(method, controller)
|
104
|
+
return nil unless method
|
105
|
+
time = evaluate_method(method, controller)
|
106
|
+
|
107
|
+
time = time.__send__(@options[:method]) if @options[:method].is_a?(Symbol) && time.respond_to?(@options[:method])
|
108
|
+
|
109
|
+
if time.respond_to?(:to_time)
|
110
|
+
time.to_time.utc
|
111
|
+
elsif time.respond_to?(:updated_at)
|
112
|
+
time.updated_at.utc
|
113
|
+
elsif time.respond_to?(:updated_on)
|
114
|
+
time.updated_on.utc
|
115
|
+
else
|
116
|
+
nil
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
ActionController::Base.send :include, ActionController::Caching::HttpCache
|
@@ -0,0 +1,212 @@
|
|
1
|
+
# Those lines are plugin test settings
|
2
|
+
require 'test/unit'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
ENV["RAILS_ENV"] = "test"
|
7
|
+
|
8
|
+
require 'active_support'
|
9
|
+
require 'action_controller'
|
10
|
+
require 'action_controller/test_case'
|
11
|
+
require 'action_controller/test_process'
|
12
|
+
|
13
|
+
require File.dirname(__FILE__) + '/../lib/easy_http_cache.rb'
|
14
|
+
|
15
|
+
ActionController::Base.perform_caching = true
|
16
|
+
ActionController::Routing::Routes.draw do |map|
|
17
|
+
map.connect ':controller/:action/:id'
|
18
|
+
end
|
19
|
+
|
20
|
+
class HttpCacheTestController < ActionController::Base
|
21
|
+
http_cache :index
|
22
|
+
http_cache :show, :last_modified => 2.hours.ago, :if => Proc.new { |c| !c.request.format.json? }
|
23
|
+
http_cache :edit, :last_modified => Proc.new{ 30.minutes.ago }
|
24
|
+
http_cache :destroy, :last_modified => [2.hours.ago, Proc.new{|c| 30.minutes.ago }]
|
25
|
+
http_cache :invalid, :last_modified => [1.hours.ago, false]
|
26
|
+
|
27
|
+
http_cache :etag, :etag => 'ETAG_CACHE'
|
28
|
+
http_cache :etag_array, :etag => [ 'ETAG_CACHE', :resource ]
|
29
|
+
http_cache :resources, :last_modified => [:resource, :list, :object]
|
30
|
+
http_cache :resources_with_method, :last_modified => [:resource, :list, :object], :method => :cached_at
|
31
|
+
|
32
|
+
def index
|
33
|
+
render :text => '200 OK', :status => 200
|
34
|
+
end
|
35
|
+
|
36
|
+
alias_method :show, :index
|
37
|
+
alias_method :edit, :index
|
38
|
+
alias_method :destroy, :index
|
39
|
+
alias_method :invalid, :index
|
40
|
+
alias_method :etag, :index
|
41
|
+
alias_method :etag_array, :index
|
42
|
+
alias_method :resources, :index
|
43
|
+
alias_method :resources_with_method, :index
|
44
|
+
|
45
|
+
protected
|
46
|
+
|
47
|
+
def resource
|
48
|
+
resource = OpenStruct.new
|
49
|
+
resource.instance_eval do
|
50
|
+
def to_param
|
51
|
+
12345
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
resource.updated_at = 2.hours.ago
|
56
|
+
resource
|
57
|
+
end
|
58
|
+
|
59
|
+
def list
|
60
|
+
list = OpenStruct.new
|
61
|
+
list.updated_on = 30.minutes.ago
|
62
|
+
list
|
63
|
+
end
|
64
|
+
|
65
|
+
def object
|
66
|
+
object = OpenStruct.new
|
67
|
+
object.cached_at = 15.minutes.ago
|
68
|
+
object
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class HttpCacheTest < ActionController::TestCase
|
73
|
+
def setup
|
74
|
+
reset!
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_last_modified_http_cache
|
78
|
+
last_modified_http_cache(:show, 1.hour.ago, 3.hours.ago)
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_last_modified_http_cache_with_proc
|
82
|
+
last_modified_http_cache(:edit, 15.minutes.ago, 45.minutes.ago)
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_last_modified_http_cache_with_array
|
86
|
+
last_modified_http_cache(:destroy, 15.minutes.ago, 45.minutes.ago)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_last_modified_http_cache_with_resources
|
90
|
+
last_modified_http_cache(:resources, 15.minutes.ago, 45.minutes.ago)
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_last_modified_http_cache_with_resources_with_method
|
94
|
+
last_modified_http_cache(:resources_with_method, 10.minutes.ago, 20.minutes.ago)
|
95
|
+
end
|
96
|
+
|
97
|
+
def test_last_modified_http_cache_discards_invalid_input
|
98
|
+
last_modified_http_cache(:invalid, 30.minutes.ago, 90.minutes.ago)
|
99
|
+
end
|
100
|
+
|
101
|
+
def test_http_cache_without_input
|
102
|
+
get :index
|
103
|
+
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'Last-Modified', Time.utc(0).httpdate)
|
104
|
+
reset!
|
105
|
+
|
106
|
+
@request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
|
107
|
+
get :index
|
108
|
+
assert_headers('304 Not Modified', 'private, max-age=0, must-revalidate', 'Last-Modified', Time.utc(0).httpdate)
|
109
|
+
reset!
|
110
|
+
|
111
|
+
@request.env['HTTP_IF_MODIFIED_SINCE'] = 3.hours.ago.httpdate
|
112
|
+
get :index
|
113
|
+
assert_headers('304 Not Modified', 'private, max-age=0, must-revalidate', 'Last-Modified', Time.utc(0).httpdate)
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_http_cache_with_conditional_options
|
117
|
+
@request.env['HTTP_ACCEPT'] = 'application/json'
|
118
|
+
get :show
|
119
|
+
assert_nil @response.headers['Last-Modified']
|
120
|
+
reset!
|
121
|
+
|
122
|
+
@request.env['HTTP_ACCEPT'] = 'application/json'
|
123
|
+
@request.env['HTTP_IF_MODIFIED_SINCE'] = 1.hour.ago.httpdate
|
124
|
+
get :show
|
125
|
+
assert_equal '200 OK', @response.status
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_etag_http_cache
|
129
|
+
etag_http_cache(:etag, 'ETAG_CACHE')
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_etag_http_cache_with_array
|
133
|
+
etag_http_cache(:etag_array, ['ETAG_CACHE', 12345])
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_etag_http_cache_with_env_variable
|
137
|
+
ENV['RAILS_APP_VERSION'] = '1.2.3'
|
138
|
+
etag_http_cache(:etag, 'ETAG_CACHE')
|
139
|
+
end
|
140
|
+
|
141
|
+
private
|
142
|
+
def reset!
|
143
|
+
@request = ActionController::TestRequest.new
|
144
|
+
@response = ActionController::TestResponse.new
|
145
|
+
@controller = HttpCacheTestController.new
|
146
|
+
end
|
147
|
+
|
148
|
+
def etag_for(etag)
|
149
|
+
%("#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(etag))}")
|
150
|
+
end
|
151
|
+
|
152
|
+
def assert_headers(status, control, cache_header=nil, value=nil)
|
153
|
+
assert_equal status, @response.status
|
154
|
+
assert_equal control, @response.headers['Cache-Control']
|
155
|
+
|
156
|
+
if cache_header
|
157
|
+
if value
|
158
|
+
assert_equal value, @response.headers[cache_header]
|
159
|
+
else
|
160
|
+
assert @response.headers[cache_header]
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Goes through a http cache process:
|
166
|
+
#
|
167
|
+
# 1. Request an action
|
168
|
+
# 2. Get a '200 OK' status
|
169
|
+
# 3. Request the same action with a not expired HTTP_IF_MODIFIED_SINCE
|
170
|
+
# 4. Get a '304 Not Modified' status
|
171
|
+
# 5. Request the same action with an expired HTTP_IF_MODIFIED_SINCE
|
172
|
+
# 6. Get a '200 OK' status
|
173
|
+
#
|
174
|
+
def last_modified_http_cache(action, not_expired_time, expired_time)
|
175
|
+
get action
|
176
|
+
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'Last-Modified')
|
177
|
+
reset!
|
178
|
+
|
179
|
+
@request.env['HTTP_IF_MODIFIED_SINCE'] = not_expired_time.httpdate
|
180
|
+
get action
|
181
|
+
assert_headers('304 Not Modified', 'private, max-age=0, must-revalidate', 'Last-Modified')
|
182
|
+
reset!
|
183
|
+
|
184
|
+
@request.env['HTTP_IF_MODIFIED_SINCE'] = expired_time.httpdate
|
185
|
+
get action
|
186
|
+
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'Last-Modified')
|
187
|
+
end
|
188
|
+
|
189
|
+
# Goes through a http cache process:
|
190
|
+
#
|
191
|
+
# 1. Request an action
|
192
|
+
# 2. Get a '200 OK' status
|
193
|
+
# 3. Request the same action with a valid ETAG
|
194
|
+
# 4. Get a '304 Not Modified' status
|
195
|
+
# 5. Request the same action with an invalid IF_NONE_MATCH
|
196
|
+
# 6. Get a '200 OK' status
|
197
|
+
#
|
198
|
+
def etag_http_cache(action, variable)
|
199
|
+
get action
|
200
|
+
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'ETag', etag_for(variable))
|
201
|
+
reset!
|
202
|
+
|
203
|
+
@request.env['HTTP_IF_NONE_MATCH'] = etag_for(variable)
|
204
|
+
get action
|
205
|
+
assert_headers('304 Not Modified', 'private, max-age=0, must-revalidate', 'ETag', etag_for(variable))
|
206
|
+
reset!
|
207
|
+
|
208
|
+
@request.env['HTTP_IF_NONE_MATCH'] = 'INVALID'
|
209
|
+
get action
|
210
|
+
assert_headers('200 OK', 'private, max-age=0, must-revalidate', 'ETag', etag_for(variable))
|
211
|
+
end
|
212
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: easy_http_cache
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "2.2"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- "Jos\xC3\xA9 Valim"
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-23 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Allows Rails applications to use HTTP cache specifications easily.
|
17
|
+
email: contact@plataformatec.com.br
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- README.rdoc
|
27
|
+
- Rakefile
|
28
|
+
- init.rb
|
29
|
+
- lib/easy_http_cache.rb
|
30
|
+
has_rdoc: true
|
31
|
+
homepage: http://github.com/josevalim/easy_http_cache
|
32
|
+
licenses: []
|
33
|
+
|
34
|
+
post_install_message:
|
35
|
+
rdoc_options:
|
36
|
+
- --charset=UTF-8
|
37
|
+
require_paths:
|
38
|
+
- lib
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
requirements: []
|
52
|
+
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 1.3.5
|
55
|
+
signing_key:
|
56
|
+
specification_version: 3
|
57
|
+
summary: Allows Rails applications to use HTTP cache specifications easily.
|
58
|
+
test_files:
|
59
|
+
- test/easy_http_cache_test.rb
|