Remove the action_cache plugin
The action_cache plugin is now rather superfluous (Rails has native support for ETags, for instance). And it wasn't working right with Rails 2.0.x (pages were being cached, and 304s were being returned as appropriate, but cached pages were not being served).
This commit is contained in:
parent
5a0a6b2ca1
commit
550c2e6c40
57
vendor/plugins/action_cache/CHANGELOG
vendored
57
vendor/plugins/action_cache/CHANGELOG
vendored
|
@ -1,57 +0,0 @@
|
||||||
|
|
||||||
|
|
||||||
=== v0.0.1
|
|
||||||
|
|
||||||
* Initial implemenation
|
|
||||||
* Plugin implementation
|
|
||||||
|
|
||||||
=== v0.0.2
|
|
||||||
|
|
||||||
* Add the ability to replace the fragment_key method to do your own thing
|
|
||||||
|
|
||||||
=== v0.0.3
|
|
||||||
|
|
||||||
* Add timed expiry of action cache items with response.time_to_live = x
|
|
||||||
|
|
||||||
=== v.0.0.4
|
|
||||||
|
|
||||||
* Set the max-age value of the Cache-Control header to be the response.time_to_live
|
|
||||||
value if it is set, or 1 second if not
|
|
||||||
|
|
||||||
=== v.0.0.5
|
|
||||||
|
|
||||||
* Changed the Last-Modified header setting to not set Time.now if the header has already
|
|
||||||
been set. Fix from Eli Miller.
|
|
||||||
|
|
||||||
=== v.0.0.6
|
|
||||||
|
|
||||||
* Added encoding/decoding of the response body to allow UTF-8 encodings to not break due to
|
|
||||||
YAML bugs. Fix from Hui
|
|
||||||
* Handle potential problem with LastModified not being set correctly
|
|
||||||
* Add some simple tests using the Plugin Test Kit system
|
|
||||||
|
|
||||||
=== v.0.1.0
|
|
||||||
|
|
||||||
* Added support for the X-Sendfile feature in lighttpd
|
|
||||||
* Changed fragment usage to have body and headers in different fragments to allow X-Sendfile to work
|
|
||||||
* Refactored the code to make it easier to read
|
|
||||||
|
|
||||||
=== v.0.1.1
|
|
||||||
|
|
||||||
* Add the ability to decide whether to cache a request at request time
|
|
||||||
|
|
||||||
=== v.0.1.2
|
|
||||||
|
|
||||||
* Add support for the X-Accel-Redirect header in nginx
|
|
||||||
|
|
||||||
=== v.0.1.3
|
|
||||||
|
|
||||||
* Add the ability to enable the X-Sendfile feature by sending a HTTP_X_ENABLE_X_SENDFILE request
|
|
||||||
header for when lighttpd doesn't create the Rails process
|
|
||||||
|
|
||||||
=== v.0.1.4
|
|
||||||
|
|
||||||
* Change cache key generation from fragment_key member of an internal class to be an method
|
|
||||||
on the application controller that you can override in your own code.
|
|
||||||
* Make expire_action work with the user generated cache key
|
|
||||||
* Add an expire_all_actions method to clean everything out
|
|
20
vendor/plugins/action_cache/MIT-LICENSE
vendored
20
vendor/plugins/action_cache/MIT-LICENSE
vendored
|
@ -1,20 +0,0 @@
|
||||||
Copyright (c) 2005-2006 Tom Fakes
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining
|
|
||||||
a copy of this software and associated documentation files (the
|
|
||||||
"Software"), to deal in the Software without restriction, including
|
|
||||||
without limitation the rights to use, copy, modify, merge, publish,
|
|
||||||
distribute, sublicense, and/or sell copies of the Software, and to
|
|
||||||
permit persons to whom the Software is furnished to do so, subject to
|
|
||||||
the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be
|
|
||||||
included in all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
||||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
||||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
||||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
||||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
174
vendor/plugins/action_cache/README
vendored
174
vendor/plugins/action_cache/README
vendored
|
@ -1,174 +0,0 @@
|
||||||
Contributors:
|
|
||||||
Tom Fakes (tom@craz8.com) - Initial implementation, plugin implementation, x-sendfile work
|
|
||||||
Scott Laird - Ideas for the timed expiry and programmable fragment_key features
|
|
||||||
|
|
||||||
=== Action Cache Upgrade
|
|
||||||
|
|
||||||
This is a drop in replacement for the Rails Action Cache. When this plugin is
|
|
||||||
installed, the new behavior will take effect without any further configuration.
|
|
||||||
|
|
||||||
All documentation for the Rails Action Cache is still relevant. Sweepers still work, all the
|
|
||||||
fragment stores are supported.
|
|
||||||
|
|
||||||
See my blog at http://blog.craz8.com to find some interesting uses of the extended behavior
|
|
||||||
provided by this plugin
|
|
||||||
|
|
||||||
=== Major Change!
|
|
||||||
|
|
||||||
This version uses a different cache key generation mechanism. Instead of setting
|
|
||||||
ActionController::Caching::Actions::ActionCacheFilter.fragment_key, the cache code calls out to
|
|
||||||
the action_fragment_key method on the current controller. A default version of this method is
|
|
||||||
supplied that emulates the Rails built in Action Cache. If you haven't set the fragment_key
|
|
||||||
in your code, then nothing changes. If you have set the fragment_key, then you will need
|
|
||||||
to move that code to the application controller for your code to continue working.
|
|
||||||
|
|
||||||
=== Features
|
|
||||||
|
|
||||||
1. Store cache entries as YAML streams so the Response headers from the original
|
|
||||||
response can be returned with cache hits
|
|
||||||
|
|
||||||
2. Add a 'last-modified' header to the response to get the client to use a
|
|
||||||
get-if-modified request
|
|
||||||
|
|
||||||
3. If the client has the response we have cached, don't send it again, send a
|
|
||||||
'304 Not Modified' response to reduce data on the wire
|
|
||||||
|
|
||||||
4. Fix a bug in the original Rails code where responses other than '200 OK' are cached
|
|
||||||
(since the headers aren't cached in the original, all the clients would get
|
|
||||||
is an empty '200 OK' response from subsequent requests)
|
|
||||||
|
|
||||||
5. Allow clients to provide their own implementation of the cache key for the actions, e.g.
|
|
||||||
|
|
||||||
- application.rb
|
|
||||||
|
|
||||||
# Cache different pages for Admin and Users
|
|
||||||
def action_fragment_key(options)
|
|
||||||
url_for(options).split('://').last + "/#{admin? : 'admin' : 'user'}"
|
|
||||||
end
|
|
||||||
|
|
||||||
The options hash can be used to pass parameters in to override the current controller, and is
|
|
||||||
used by the cache expiry code to expire an action from a sweeper or a different controller than
|
|
||||||
the one the action is cached for.
|
|
||||||
|
|
||||||
6. Allow an action to specify a Time To Live for the cached item. Set 'response.time_to_live' to
|
|
||||||
the number of seconds before this cached item will be expired. If not set, the default setting
|
|
||||||
of 'never' will be used and the item will only be expired by using the regular action cache
|
|
||||||
expiry mechanism.
|
|
||||||
|
|
||||||
def my_action
|
|
||||||
@response.time_to_live = 10.minutes
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
7. If the ENABLE_X_SENDFILE environment variable is set, or the HTTP_ENABLE_X_SENDFILE request
|
|
||||||
header is set, and the fragment cache is set to the FileStore, then the Action Cache code
|
|
||||||
will not return the response body, but will set the X-Sendfile header in the response to
|
|
||||||
the filename of the cache entry that contains the body.
|
|
||||||
|
|
||||||
Be sure your web server is has the X-Sendfile feature enabled, otherwise you'll just get
|
|
||||||
empty responses!
|
|
||||||
|
|
||||||
Check out the lighttpd documentation for how to use the X-Sendfile feature: http://lighttpd.net/
|
|
||||||
|
|
||||||
To enable this, the ENABLE_X_SENDFILE environment variable must be set, *and* the FileStore fragment
|
|
||||||
cache must be used.
|
|
||||||
|
|
||||||
lighttpd.conf:
|
|
||||||
|
|
||||||
fastcgi.server = ( ".fcgi" =>
|
|
||||||
( "app" =>
|
|
||||||
( "min-procs" => 1,
|
|
||||||
"max-procs" => 1,
|
|
||||||
"allow-x-send-file" => "enable",
|
|
||||||
"socket" => "/tmp/app.fcgi.socket",
|
|
||||||
"bin-path" => "/path/to/app/public/dispatch.fcgi",
|
|
||||||
"bin-environment" => ( "RAILS_ENV" => "development", "ENABLE_X_SENDFILE" => "true" )
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
environment.rb:
|
|
||||||
ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory"
|
|
||||||
|
|
||||||
Note: The cache directory can be anywhere on your server that your web server user has read and write
|
|
||||||
access to. This should *not* be in the Rails /public directory.
|
|
||||||
|
|
||||||
8. Control whether caching occurs for an action at runtime instead of load time.
|
|
||||||
|
|
||||||
To control caching, add a method *cache_action?(action_name)* to your controller. If this
|
|
||||||
method returns true, then the action cache will work as before. If false, then caching will
|
|
||||||
not occur for this request.
|
|
||||||
|
|
||||||
e.g.
|
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
|
||||||
...
|
|
||||||
|
|
||||||
def cache_action?(action_name)
|
|
||||||
!admin?
|
|
||||||
end
|
|
||||||
|
|
||||||
...
|
|
||||||
end
|
|
||||||
|
|
||||||
Note: The action must still be marked for caching by adding *caches_action :action* to the controller
|
|
||||||
|
|
||||||
9. If the ENABLE_X_ACCEL_REDIRECT request header is set, and the fragment cache is set to
|
|
||||||
the FileStore, then the Action Cache code will not return the response body, but will set
|
|
||||||
the X-Accel-Redirect header in the response to the filename of the cache entry that contains the
|
|
||||||
body.
|
|
||||||
|
|
||||||
The nginx configuration must contain a 'location' section labeled 'cache', that points to the location
|
|
||||||
you have configured for your Rails fragment cache, default is RAILS_ROOT/tmp/cache. e.g:
|
|
||||||
|
|
||||||
location /cache/ {
|
|
||||||
internal;
|
|
||||||
root /path/to/rails/app/current/tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
To enable this, the ENABLE_X_SENDFILE environment variable must be set, *and* the FileStore fragment
|
|
||||||
cache must be used.
|
|
||||||
|
|
||||||
nginx.conf:
|
|
||||||
location /cache/ {
|
|
||||||
internal;
|
|
||||||
root /path/to/rails/app/current/tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
||||||
proxy_set_header Host $http_host;
|
|
||||||
proxy_set_header "ENABLE_X_ACCEL_REDIRECT" "true";
|
|
||||||
...
|
|
||||||
}
|
|
||||||
|
|
||||||
environment.rb:
|
|
||||||
ActionController::Base.fragment_cache_store = :file_store, "/path/to/cache/directory"
|
|
||||||
|
|
||||||
Note: The cache directory can be anywhere on your server that your web server user has read and write
|
|
||||||
access to. This should *not* be in the Rails /public directory.
|
|
||||||
|
|
||||||
10. A new method 'expire_all_actions' will clear out the entire action cache contents.
|
|
||||||
|
|
||||||
11. expire_action will now work with the custom generated action cache keys, so your cache
|
|
||||||
expiry calls and sweepers will work correctly.
|
|
||||||
|
|
||||||
The expire_action call implemented here will actually use the Regexp fragment expiry call,
|
|
||||||
causing all matching cache items to be cleared. For those of you using REST, and providing
|
|
||||||
HTML, JS and XML for the same action, all three will be expired when you expire one of them
|
|
||||||
with code like:
|
|
||||||
|
|
||||||
# Expires all formats of the action
|
|
||||||
expire_action :controller => 'foo', :action => 'bar'
|
|
||||||
|
|
||||||
=== Performance
|
|
||||||
|
|
||||||
If a client requests an action whose output hasn't changed since their last request, the returning of
|
|
||||||
a 304 response instead of the full response greatly reduces the load on the server.
|
|
||||||
|
|
||||||
In my informal testing, with the X-Sendfile enabled, I was able to get about 20% more requests out of my
|
|
||||||
rails application, based on the requests-per-second displayed in the rails log. This doesn't mean the
|
|
||||||
request is faster, but that the work of delivering the content is offloaded to the web server from the
|
|
||||||
Rails app.
|
|
7
vendor/plugins/action_cache/about.yml
vendored
7
vendor/plugins/action_cache/about.yml
vendored
|
@ -1,7 +0,0 @@
|
||||||
author: Tom Fakes
|
|
||||||
summary: A drop-in replacement for the Rails Action Cache. Fixes some inconsistencies and adds some extra control. Use X-Sendfile or X-Accel-Redirect to send responses
|
|
||||||
homepage: http://blog.craz8.com
|
|
||||||
plugin: http://craz8.com/svn/trunk/plugins/action_cache
|
|
||||||
license: MIT
|
|
||||||
version: 0.1.4
|
|
||||||
rails_version: 1.0+
|
|
16
vendor/plugins/action_cache/index.html
vendored
16
vendor/plugins/action_cache/index.html
vendored
|
@ -1,16 +0,0 @@
|
||||||
<html><head><title>Revision 53: /trunk/plugins/action_cache</title></head>
|
|
||||||
<body>
|
|
||||||
<h2>Revision 53: /trunk/plugins/action_cache</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../">..</a></li>
|
|
||||||
<li><a href="CHANGELOG">CHANGELOG</a></li>
|
|
||||||
<li><a href="MIT-LICENSE">MIT-LICENSE</a></li>
|
|
||||||
<li><a href="README">README</a></li>
|
|
||||||
<li><a href="about.yml">about.yml</a></li>
|
|
||||||
<li><a href="init.rb">init.rb</a></li>
|
|
||||||
<li><a href="lib/">lib/</a></li>
|
|
||||||
<li><a href="rakefile">rakefile</a></li>
|
|
||||||
<li><a href="test/">test/</a></li>
|
|
||||||
</ul>
|
|
||||||
<hr noshade><em>Powered by <a href="http://subversion.tigris.org/">Subversion</a> version 1.4.2 (r22196).</em>
|
|
||||||
</body></html>
|
|
1
vendor/plugins/action_cache/init.rb
vendored
1
vendor/plugins/action_cache/init.rb
vendored
|
@ -1 +0,0 @@
|
||||||
require 'action_cache'
|
|
240
vendor/plugins/action_cache/lib/action_cache.rb
vendored
240
vendor/plugins/action_cache/lib/action_cache.rb
vendored
|
@ -1,240 +0,0 @@
|
||||||
require 'yaml'
|
|
||||||
require 'time'
|
|
||||||
require 'md5'
|
|
||||||
|
|
||||||
module ActionController
|
|
||||||
class AbstractResponse #:nodoc:
|
|
||||||
attr_accessor :time_to_live
|
|
||||||
end
|
|
||||||
|
|
||||||
module Caching
|
|
||||||
|
|
||||||
module Actions
|
|
||||||
|
|
||||||
# All documentation is keeping DRY in the plugin's README
|
|
||||||
|
|
||||||
def expire_all_actions
|
|
||||||
return unless perform_caching
|
|
||||||
expire_fragment(/.*\/(META|DATA)\/.*/)
|
|
||||||
end
|
|
||||||
|
|
||||||
def expire_one_action(options)
|
|
||||||
expire_fragment(Regexp.new(".*/" + Regexp.escape(ActionCachePath.path_for(self, options)) + ".*"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def expire_action(options = {})
|
|
||||||
return unless perform_caching
|
|
||||||
if options[:action].is_a?(Array)
|
|
||||||
options[:action].dup.each do |action|
|
|
||||||
expire_one_action options.merge({ :action => action })
|
|
||||||
end
|
|
||||||
else
|
|
||||||
expire_one_action options
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def action_fragment_key(options)
|
|
||||||
url_for(options).split('://').last
|
|
||||||
end
|
|
||||||
|
|
||||||
# Override the 1.2 ActionCachePath class, works in 1.1.x too
|
|
||||||
class ActionCachePath
|
|
||||||
attr_reader :controller, :options
|
|
||||||
|
|
||||||
class << self
|
|
||||||
def path_for(*args, &block)
|
|
||||||
new(*args).path
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(controller, options = {})
|
|
||||||
@controller = controller
|
|
||||||
@options = options
|
|
||||||
end
|
|
||||||
|
|
||||||
# Override this to change behavior
|
|
||||||
def path
|
|
||||||
return @path if @path
|
|
||||||
@path = @controller.send(:action_fragment_key, @options)
|
|
||||||
add_extension!
|
|
||||||
clean!
|
|
||||||
end
|
|
||||||
|
|
||||||
def extension
|
|
||||||
@extension ||= extract_extension(controller.request.path)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def clean!
|
|
||||||
@path = @path.gsub(':', '-').gsub('?', '-')
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_extension!
|
|
||||||
@path << ".#{extension}" if extension
|
|
||||||
end
|
|
||||||
|
|
||||||
def extract_extension(file_path)
|
|
||||||
# Don't want just what comes after the last '.' to accomodate multi part extensions
|
|
||||||
# such as tar.gz.
|
|
||||||
file_path[/^[^.]+\.(.+)$/, 1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class ActionCacheFilter #:nodoc:
|
|
||||||
|
|
||||||
def self.fragment_key=(key_block)
|
|
||||||
raise "fragment_key member no longer supported - use action_fragment_key on controller instead"
|
|
||||||
end
|
|
||||||
|
|
||||||
class CacheEntry #:nodoc:
|
|
||||||
def initialize(headers, time_to_live = nil)
|
|
||||||
@headers = headers.merge({ 'cookie' => [] }) # Don't send cookies for cached responses
|
|
||||||
@expire_time = Time.now + time_to_live unless time_to_live.nil?
|
|
||||||
end
|
|
||||||
|
|
||||||
def expired?
|
|
||||||
!expire_time.nil? && Time.now > expire_time
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :headers, :expire_time
|
|
||||||
end
|
|
||||||
|
|
||||||
def before(controller)
|
|
||||||
if cache_entry = cached_entry(controller)
|
|
||||||
if cache_entry.expired?
|
|
||||||
remove_cache_item(controller) and return
|
|
||||||
end
|
|
||||||
|
|
||||||
if x_sendfile_enabled?(controller)
|
|
||||||
send_using_x_sendfile(cache_entry, controller)
|
|
||||||
else if x_accel_redirect_enabled?(controller)
|
|
||||||
send_using_x_accel_redirect(cache_entry, controller)
|
|
||||||
else
|
|
||||||
if client_has_latest?(cache_entry, controller)
|
|
||||||
send_not_modified(controller)
|
|
||||||
else
|
|
||||||
send_cached_response(cache_entry, controller)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
controller.rendered_action_cache = true
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def after(controller)
|
|
||||||
if cache_this_request?(controller)
|
|
||||||
adjust_headers(controller)
|
|
||||||
save_to_cache(controller)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
def adjust_headers(controller)
|
|
||||||
if controller.response.time_to_live &&
|
|
||||||
controller.response.headers['Cache-Control'] == 'no-cache'
|
|
||||||
controller.response.headers['Cache-Control'] = "max-age=#{controller.response.time_to_live}"
|
|
||||||
end
|
|
||||||
controller.response.headers['ETag'] = %{"#{MD5.new(controller.response.body).to_s}"}
|
|
||||||
controller.response.headers['Last-Modified'] ||= Time.now.httpdate
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_cached_response(cache_entry, controller)
|
|
||||||
controller.logger.info "Send #{body_name(controller)} by response.body"
|
|
||||||
controller.response.headers = cache_entry.headers
|
|
||||||
controller.set_content_type_header
|
|
||||||
controller.response.body = fragment_body(controller)
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_not_modified(controller)
|
|
||||||
controller.logger.info "Send Not Modified"
|
|
||||||
controller.response.headers['ETag'] = %{"#{MD5.new(fragment_body(controller)).to_s}"}
|
|
||||||
controller.send(:render, {:text => "", :status => 304})
|
|
||||||
end
|
|
||||||
|
|
||||||
def client_has_latest?(cache_entry, controller)
|
|
||||||
requestEtag = controller.request.env['HTTP_IF_NONE_MATCH'] rescue nil
|
|
||||||
responseEtag = cache_entry.headers['ETag'] rescue nil
|
|
||||||
return true if (requestEtag and responseEtag and requestEtag == responseEtag)
|
|
||||||
requestTime = Time.rfc2822(controller.request.env["HTTP_IF_MODIFIED_SINCE"]) rescue nil
|
|
||||||
responseTime = Time.rfc2822(cache_entry.headers['Last-Modified']) rescue nil
|
|
||||||
return (requestTime and responseTime and responseTime <= requestTime)
|
|
||||||
end
|
|
||||||
|
|
||||||
def remove_cache_item(controller)
|
|
||||||
controller.expire_fragment(meta_name(controller))
|
|
||||||
controller.expire_fragment(body_name(controller))
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_using_x_sendfile(cache_entry, controller)
|
|
||||||
filename = fragment_body_filename(controller)
|
|
||||||
controller.logger.info "Send #{filename} by X-Sendfile"
|
|
||||||
controller.response.headers = cache_entry.headers
|
|
||||||
controller.response.headers["X-Sendfile"] = filename
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_using_x_accel_redirect(cache_entry, controller)
|
|
||||||
filename = "/cache/#{fragment_body_filename(controller)[(controller.fragment_cache_store.cache_path.length + 1)..-1]}"
|
|
||||||
controller.logger.info "Send #{filename} by X-Accel-Redirect"
|
|
||||||
controller.response.headers = cache_entry.headers
|
|
||||||
controller.response.headers["X-Accel-Redirect"] = filename
|
|
||||||
end
|
|
||||||
|
|
||||||
def fragment_body_filename(controller)
|
|
||||||
controller.fragment_cache_store.send(:real_file_path, body_name(controller))
|
|
||||||
end
|
|
||||||
|
|
||||||
def fragment_body(controller)
|
|
||||||
controller.read_fragment body_name(controller)
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_request?(controller)
|
|
||||||
controller.respond_to?(:cache_action?) ? controller.cache_action?(controller.action_name) : true
|
|
||||||
end
|
|
||||||
|
|
||||||
def cache_this_request?(controller)
|
|
||||||
@actions.include?(controller.action_name.intern) && cache_request?(controller) &&
|
|
||||||
!controller.rendered_action_cache && controller.response.headers['Status'] == '200 OK'
|
|
||||||
end
|
|
||||||
|
|
||||||
def cached_entry(controller)
|
|
||||||
if @actions.include?(controller.action_name.intern) &&
|
|
||||||
cache_request?(controller) &&
|
|
||||||
(cache = controller.read_fragment(meta_name(controller)))
|
|
||||||
return YAML.load(cache)
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def save_to_cache(controller)
|
|
||||||
cache = CacheEntry.new(controller.response.headers, controller.response.time_to_live)
|
|
||||||
controller.write_fragment(body_name(controller), controller.response.body)
|
|
||||||
controller.write_fragment(meta_name(controller), YAML.dump(cache))
|
|
||||||
end
|
|
||||||
|
|
||||||
def x_sendfile_enabled?(controller)
|
|
||||||
(controller.request.env["ENABLE_X_SENDFILE"] == "true" ||
|
|
||||||
controller.request.env["HTTP_X_ENABLE_X_SENDFILE"] == "true") &&
|
|
||||||
controller.fragment_cache_store.is_a?(ActionController::Caching::Fragments::UnthreadedFileStore)
|
|
||||||
end
|
|
||||||
|
|
||||||
def x_accel_redirect_enabled?(controller)
|
|
||||||
controller.request.env["HTTP_ENABLE_X_ACCEL_REDIRECT"] == "true" &&
|
|
||||||
controller.fragment_cache_store.is_a?(ActionController::Caching::Fragments::UnthreadedFileStore)
|
|
||||||
end
|
|
||||||
|
|
||||||
def meta_name(controller)
|
|
||||||
"META/#{ActionCachePath.path_for(controller)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def body_name(controller)
|
|
||||||
"DATA/#{ActionCachePath.path_for(controller)}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
9
vendor/plugins/action_cache/lib/index.html
vendored
9
vendor/plugins/action_cache/lib/index.html
vendored
|
@ -1,9 +0,0 @@
|
||||||
<html><head><title>Revision 53: /trunk/plugins/action_cache/lib</title></head>
|
|
||||||
<body>
|
|
||||||
<h2>Revision 53: /trunk/plugins/action_cache/lib</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../">..</a></li>
|
|
||||||
<li><a href="action_cache.rb">action_cache.rb</a></li>
|
|
||||||
</ul>
|
|
||||||
<hr noshade><em>Powered by <a href="http://subversion.tigris.org/">Subversion</a> version 1.4.2 (r22196).</em>
|
|
||||||
</body></html>
|
|
22
vendor/plugins/action_cache/rakefile
vendored
22
vendor/plugins/action_cache/rakefile
vendored
|
@ -1,22 +0,0 @@
|
||||||
require 'rake'
|
|
||||||
require 'rake/testtask'
|
|
||||||
require 'rake/rdoctask'
|
|
||||||
|
|
||||||
desc 'Default: run unit tests.'
|
|
||||||
task :default => :test
|
|
||||||
|
|
||||||
desc 'Test the Action Cache Upgrade plugin.'
|
|
||||||
Rake::TestTask.new(:test) do |t|
|
|
||||||
t.libs << 'lib'
|
|
||||||
t.pattern = 'test/**/*_test.rb'
|
|
||||||
t.verbose = true
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'Generate documentation for the Action Cache Upgrade plugin.'
|
|
||||||
Rake::RDocTask.new(:rdoc) do |rdoc|
|
|
||||||
rdoc.rdoc_dir = 'rdoc'
|
|
||||||
rdoc.title = 'Action Cache Upgrade'
|
|
||||||
rdoc.options << '--line-numbers --inline-source'
|
|
||||||
rdoc.rdoc_files.include('README')
|
|
||||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
||||||
end
|
|
|
@ -1,150 +0,0 @@
|
||||||
|
|
||||||
require "#{File.dirname(__FILE__)}/../../../../config/boot.rb"
|
|
||||||
require "#{File.dirname(__FILE__)}/../../../../config/environment.rb"
|
|
||||||
|
|
||||||
require 'action_controller/test_process'
|
|
||||||
require 'test/unit'
|
|
||||||
|
|
||||||
ActionController::Base.perform_caching = true
|
|
||||||
ActionController::Routing::Routes.reload rescue nil
|
|
||||||
|
|
||||||
require "#{File.dirname(__FILE__)}/../lib/action_cache"
|
|
||||||
|
|
||||||
class ActionCacheController < ActionController::Base
|
|
||||||
|
|
||||||
caches_action :a, :b, :c, :action_to_expire, :action_sets_cookie
|
|
||||||
attr_accessor :var
|
|
||||||
|
|
||||||
def a
|
|
||||||
response.time_to_live = 1
|
|
||||||
render :text => "Action A: Some text that will be cached: #{@var}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def b
|
|
||||||
response.time_to_live = 1
|
|
||||||
render :text => "Action B: Some text that will be cached: #{@var}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def c
|
|
||||||
response.time_to_live = 1
|
|
||||||
logger.info "Action C"
|
|
||||||
render :text => "Action C: Some text that will be cached: #{@var}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def action_sets_cookie
|
|
||||||
cookies["one_time_only"] = "Hello!"
|
|
||||||
render :text => "Action Sets A Cookie Value"
|
|
||||||
end
|
|
||||||
|
|
||||||
def action_to_expire
|
|
||||||
logger.info "Action To Expire"
|
|
||||||
render :text => "Action To Expire: Some text that will be cached: #{@var}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_cache_item
|
|
||||||
expire_action :action => 'action_to_expire'
|
|
||||||
render :text => 'Cache Item Expired'
|
|
||||||
end
|
|
||||||
|
|
||||||
def clear_all_cache
|
|
||||||
expire_all_actions
|
|
||||||
render :text => 'All Cache Items Expired'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
class ActionCacheTest < Test::Unit::TestCase
|
|
||||||
def setup
|
|
||||||
@controller = ActionCacheController.new
|
|
||||||
@request = ActionController::TestRequest.new
|
|
||||||
@response = ActionController::TestResponse.new
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_action_cookie_not_cached
|
|
||||||
get :action_sets_cookie
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_not_nil cookies["one_time_only"]
|
|
||||||
|
|
||||||
# Cache should drop the cookie and not return to the second request
|
|
||||||
get :action_sets_cookie
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_nil cookies["one_time_only"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_action_is_cached_without_x_sendfile
|
|
||||||
@controller.var = "nothing"
|
|
||||||
assert_not_equal "true", @request.env["ENABLE_X_SENDFILE"]
|
|
||||||
get :a
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_nil @response.headers['X-Sendfile']
|
|
||||||
assert_match %r{nothing}, @response.body, "Body is not as expected: #{@response.body}"
|
|
||||||
|
|
||||||
# Make a change that the cache won't return
|
|
||||||
@controller.var = "something"
|
|
||||||
get :a
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_nil @response.headers['X-Sendfile']
|
|
||||||
assert_match %r{nothing}, @response.body, "Body should not be changed: #{@response.body}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_action_is_cached_with_x_sendfile
|
|
||||||
@request.env['ENABLE_X_SENDFILE'] = "true"
|
|
||||||
get :b
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_nil @response.headers['X-Sendfile'], "No x-sendfile header expected: #{@response.headers.inspect}"
|
|
||||||
|
|
||||||
get :b
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_not_nil @response.headers['X-Sendfile'], "X-sendfile header expected: #{@response.headers.inspect}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_action_is_cached_with_accel_redirect
|
|
||||||
@request.env['HTTP_ENABLE_X_ACCEL_REDIRECT'] = "true"
|
|
||||||
get :c
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_nil @response.headers['X-Accel-Redirect'], "No x-accel-redirect header expected: #{@response.headers.inspect}"
|
|
||||||
|
|
||||||
get :c
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_not_nil @response.headers['X-Accel-Redirect'], "X-Accel-Redirect header expected: #{@response.headers.inspect}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_expire_action
|
|
||||||
@controller.var = "nothing"
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_match %r{nothing}, @response.body, "Body is not as expected: #{@response.body}"
|
|
||||||
|
|
||||||
@controller.var = "something"
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_match %r{nothing}, @response.body, "Body should not be changed: #{@response.body}"
|
|
||||||
|
|
||||||
get :clear_cache_item
|
|
||||||
assert_response :success, @response.body
|
|
||||||
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_match %r{something}, @response.body, "Body should be changed: #{@response.body}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_expire_all_action
|
|
||||||
@controller.var = "nothing"
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.inspect
|
|
||||||
assert_match %r{nothing}, @response.body, "Body is not as expected: #{@response.body}"
|
|
||||||
|
|
||||||
@controller.var = "something"
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_match %r{nothing}, @response.body, "Body should not be changed: #{@response.body}"
|
|
||||||
|
|
||||||
get :clear_all_cache
|
|
||||||
assert_response :success, @response.body
|
|
||||||
|
|
||||||
get :action_to_expire
|
|
||||||
assert_response :success, @response.body
|
|
||||||
assert_match %r{something}, @response.body, "Body should be changed: #{@response.body}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
9
vendor/plugins/action_cache/test/index.html
vendored
9
vendor/plugins/action_cache/test/index.html
vendored
|
@ -1,9 +0,0 @@
|
||||||
<html><head><title>Revision 53: /trunk/plugins/action_cache/test</title></head>
|
|
||||||
<body>
|
|
||||||
<h2>Revision 53: /trunk/plugins/action_cache/test</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="../">..</a></li>
|
|
||||||
<li><a href="action_cache_test.rb">action_cache_test.rb</a></li>
|
|
||||||
</ul>
|
|
||||||
<hr noshade><em>Powered by <a href="http://subversion.tigris.org/">Subversion</a> version 1.4.2 (r22196).</em>
|
|
||||||
</body></html>
|
|
Loading…
Reference in a new issue