mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
6520ea5f7e
Allowing :controller and :action values to be specified via the path in config/routes.rb has been an underlying cause of a number of issues in Rails that have resulted in security releases. In light of this it's better that controllers and actions are explicitly whitelisted rather than trying to blacklist or sanitize 'bad' values.
754 lines
21 KiB
Ruby
754 lines
21 KiB
Ruby
require 'abstract_unit'
|
|
require 'controller/fake_models'
|
|
|
|
class TestControllerWithExtraEtags < ActionController::Base
|
|
etag { nil }
|
|
etag { 'ab' }
|
|
etag { :cde }
|
|
etag { [:f] }
|
|
etag { nil }
|
|
|
|
def fresh
|
|
render plain: "stale" if stale?(etag: '123', template: false)
|
|
end
|
|
|
|
def array
|
|
render plain: "stale" if stale?(etag: %w(1 2 3), template: false)
|
|
end
|
|
|
|
def with_template
|
|
if stale? template: 'test/hello_world'
|
|
render plain: 'stale'
|
|
end
|
|
end
|
|
end
|
|
|
|
class ImplicitRenderTestController < ActionController::Base
|
|
def empty_action
|
|
end
|
|
|
|
def empty_action_with_template
|
|
end
|
|
end
|
|
|
|
class TestController < ActionController::Base
|
|
protect_from_forgery
|
|
|
|
before_action :set_variable_for_layout
|
|
|
|
class LabellingFormBuilder < ActionView::Helpers::FormBuilder
|
|
end
|
|
|
|
layout :determine_layout
|
|
|
|
def name
|
|
nil
|
|
end
|
|
|
|
private :name
|
|
helper_method :name
|
|
|
|
def hello_world
|
|
end
|
|
|
|
def conditional_hello
|
|
if stale?(:last_modified => Time.now.utc.beginning_of_day, :etag => [:foo, 123])
|
|
render :action => 'hello_world'
|
|
end
|
|
end
|
|
|
|
def conditional_hello_with_record
|
|
record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123")
|
|
|
|
if stale?(record)
|
|
render :action => 'hello_world'
|
|
end
|
|
end
|
|
|
|
def dynamic_render
|
|
render params[:id] # => String, AC::Params
|
|
end
|
|
|
|
def dynamic_render_permit
|
|
render params[:id].permit(:file)
|
|
end
|
|
|
|
def dynamic_render_with_file
|
|
# This is extremely bad, but should be possible to do.
|
|
file = params[:id] # => String, AC::Params
|
|
render file: file
|
|
end
|
|
|
|
class Collection
|
|
def initialize(records)
|
|
@records = records
|
|
end
|
|
|
|
def maximum(attribute)
|
|
@records.max_by(&attribute).public_send(attribute)
|
|
end
|
|
end
|
|
|
|
def conditional_hello_with_collection_of_records
|
|
ts = Time.now.utc.beginning_of_day
|
|
|
|
record = Struct.new(:updated_at, :cache_key).new(ts, "foo/123")
|
|
old_record = Struct.new(:updated_at, :cache_key).new(ts - 1.day, "bar/123")
|
|
|
|
if stale?(Collection.new([record, old_record]))
|
|
render action: 'hello_world'
|
|
end
|
|
end
|
|
|
|
def conditional_hello_with_expires_in
|
|
expires_in 60.1.seconds
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_in_with_public
|
|
expires_in 1.minute, :public => true
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_in_with_must_revalidate
|
|
expires_in 1.minute, :must_revalidate => true
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_in_with_public_and_must_revalidate
|
|
expires_in 1.minute, :public => true, :must_revalidate => true
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_in_with_public_with_more_keys
|
|
expires_in 1.minute, :public => true, 's-maxage' => 5.hours
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
|
|
expires_in 1.minute, :public => true, :private => nil, 's-maxage' => 5.hours
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_expires_now
|
|
expires_now
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def conditional_hello_with_cache_control_headers
|
|
response.headers['Cache-Control'] = 'no-transform'
|
|
expires_now
|
|
render :action => 'hello_world'
|
|
end
|
|
|
|
def respond_with_empty_body
|
|
render nothing: true
|
|
end
|
|
|
|
def conditional_hello_with_bangs
|
|
render :action => 'hello_world'
|
|
end
|
|
before_action :handle_last_modified_and_etags, :only=>:conditional_hello_with_bangs
|
|
|
|
def handle_last_modified_and_etags
|
|
fresh_when(:last_modified => Time.now.utc.beginning_of_day, :etag => [ :foo, 123 ])
|
|
end
|
|
|
|
def head_with_status_hash
|
|
head status: :created
|
|
end
|
|
|
|
def head_with_hash_does_not_include_status
|
|
head warning: :deprecated
|
|
end
|
|
|
|
def head_created
|
|
head :created
|
|
end
|
|
|
|
def head_created_with_application_json_content_type
|
|
head :created, :content_type => "application/json"
|
|
end
|
|
|
|
def head_ok_with_image_png_content_type
|
|
head :ok, :content_type => "image/png"
|
|
end
|
|
|
|
def head_with_location_header
|
|
head :ok, :location => "/foo"
|
|
end
|
|
|
|
def head_with_location_object
|
|
head :ok, :location => Customer.new("david", 1)
|
|
end
|
|
|
|
def head_with_symbolic_status
|
|
head params[:status].intern
|
|
end
|
|
|
|
def head_with_integer_status
|
|
head params[:status].to_i
|
|
end
|
|
|
|
def head_with_string_status
|
|
head params[:status]
|
|
end
|
|
|
|
def head_with_custom_header
|
|
head :ok, :x_custom_header => "something"
|
|
end
|
|
|
|
def head_with_www_authenticate_header
|
|
head :ok, 'WWW-Authenticate' => 'something'
|
|
end
|
|
|
|
def head_with_status_code_first
|
|
head :forbidden, :x_custom_header => "something"
|
|
end
|
|
|
|
def head_and_return
|
|
head :ok and return
|
|
raise 'should not reach this line'
|
|
end
|
|
|
|
def head_with_no_content
|
|
# Fill in the headers with dummy data to make
|
|
# sure they get removed during the testing
|
|
response.headers["Content-Type"] = "dummy"
|
|
response.headers["Content-Length"] = 42
|
|
|
|
head 204
|
|
end
|
|
|
|
private
|
|
|
|
def set_variable_for_layout
|
|
@variable_for_layout = nil
|
|
end
|
|
|
|
def determine_layout
|
|
case action_name
|
|
when "hello_world", "layout_test", "rendering_without_layout",
|
|
"rendering_nothing_on_layout", "render_text_hello_world",
|
|
"render_text_hello_world_with_layout",
|
|
"hello_world_with_layout_false",
|
|
"partial_only", "accessing_params_in_template",
|
|
"accessing_params_in_template_with_layout",
|
|
"render_with_explicit_template",
|
|
"render_with_explicit_string_template",
|
|
"update_page", "update_page_with_instance_variables"
|
|
|
|
"layouts/standard"
|
|
when "action_talk_to_layout", "layout_overriding_layout"
|
|
"layouts/talk_from_action"
|
|
when "render_implicit_html_template_from_xhr_request"
|
|
(request.xhr? ? 'layouts/xhr' : 'layouts/standard')
|
|
end
|
|
end
|
|
end
|
|
|
|
class MetalTestController < ActionController::Metal
|
|
include AbstractController::Rendering
|
|
include ActionView::Rendering
|
|
include ActionController::Rendering
|
|
|
|
def accessing_logger_in_template
|
|
render :inline => "<%= logger.class %>"
|
|
end
|
|
end
|
|
|
|
class ExpiresInRenderTest < ActionController::TestCase
|
|
tests TestController
|
|
|
|
def setup
|
|
super
|
|
ActionController::Base.view_paths.paths.each(&:clear_cache)
|
|
end
|
|
|
|
def test_dynamic_render_with_file
|
|
# This is extremely bad, but should be possible to do.
|
|
assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
|
|
response = get :dynamic_render_with_file, params: { id: '../\\../test/abstract_unit.rb' }
|
|
assert_equal File.read(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')),
|
|
response.body
|
|
end
|
|
|
|
def test_dynamic_render_with_absolute_path
|
|
file = Tempfile.new('name')
|
|
file.write "secrets!"
|
|
file.flush
|
|
assert_raises ActionView::MissingTemplate do
|
|
get :dynamic_render, params: { id: file.path }
|
|
end
|
|
ensure
|
|
file.close
|
|
file.unlink
|
|
end
|
|
|
|
def test_dynamic_render
|
|
assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
|
|
assert_raises ActionView::MissingTemplate do
|
|
get :dynamic_render, params: { id: '../\\../test/abstract_unit.rb' }
|
|
end
|
|
end
|
|
|
|
def test_permitted_dynamic_render_file_hash
|
|
skip "FIXME: this test passes on 4-2-stable but not master. Why?"
|
|
assert File.exist?(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb'))
|
|
response = get :dynamic_render_permit, params: { id: { file: '../\\../test/abstract_unit.rb' } }
|
|
assert_equal File.read(File.join(File.dirname(__FILE__), '../../test/abstract_unit.rb')),
|
|
response.body
|
|
end
|
|
|
|
def test_dynamic_render_file_hash
|
|
assert_raises ArgumentError do
|
|
get :dynamic_render, params: { id: { file: '../\\../test/abstract_unit.rb' } }
|
|
end
|
|
end
|
|
|
|
def test_expires_in_header
|
|
get :conditional_hello_with_expires_in
|
|
assert_equal "max-age=60, private", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_in_header_with_public
|
|
get :conditional_hello_with_expires_in_with_public
|
|
assert_equal "max-age=60, public", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_in_header_with_must_revalidate
|
|
get :conditional_hello_with_expires_in_with_must_revalidate
|
|
assert_equal "max-age=60, private, must-revalidate", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_in_header_with_public_and_must_revalidate
|
|
get :conditional_hello_with_expires_in_with_public_and_must_revalidate
|
|
assert_equal "max-age=60, public, must-revalidate", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_in_header_with_additional_headers
|
|
get :conditional_hello_with_expires_in_with_public_with_more_keys
|
|
assert_equal "max-age=60, public, s-maxage=18000", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_in_old_syntax
|
|
get :conditional_hello_with_expires_in_with_public_with_more_keys_old_syntax
|
|
assert_equal "max-age=60, public, s-maxage=18000", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_now
|
|
get :conditional_hello_with_expires_now
|
|
assert_equal "no-cache", @response.headers["Cache-Control"]
|
|
end
|
|
|
|
def test_expires_now_with_cache_control_headers
|
|
get :conditional_hello_with_cache_control_headers
|
|
assert_match(/no-cache/, @response.headers["Cache-Control"])
|
|
assert_match(/no-transform/, @response.headers["Cache-Control"])
|
|
end
|
|
|
|
def test_render_nothing_deprecated
|
|
assert_deprecated do
|
|
get :respond_with_empty_body
|
|
end
|
|
end
|
|
|
|
def test_date_header_when_expires_in
|
|
time = Time.mktime(2011,10,30)
|
|
Time.stub :now, time do
|
|
get :conditional_hello_with_expires_in
|
|
assert_equal Time.now.httpdate, @response.headers["Date"]
|
|
end
|
|
end
|
|
end
|
|
|
|
class LastModifiedRenderTest < ActionController::TestCase
|
|
tests TestController
|
|
|
|
def setup
|
|
super
|
|
@last_modified = Time.now.utc.beginning_of_day.httpdate
|
|
end
|
|
|
|
def test_responds_with_last_modified
|
|
get :conditional_hello
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified
|
|
@request.if_modified_since = @last_modified
|
|
get :conditional_hello
|
|
assert_equal 304, @response.status.to_i
|
|
assert @response.body.blank?
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified_but_etag_differs
|
|
@request.if_modified_since = @last_modified
|
|
@request.if_none_match = "234"
|
|
get :conditional_hello
|
|
assert_response :success
|
|
end
|
|
|
|
def test_request_modified
|
|
@request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT'
|
|
get :conditional_hello
|
|
assert_equal 200, @response.status.to_i
|
|
assert @response.body.present?
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_responds_with_last_modified_with_record
|
|
get :conditional_hello_with_record
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified_with_record
|
|
@request.if_modified_since = @last_modified
|
|
get :conditional_hello_with_record
|
|
assert_equal 304, @response.status.to_i
|
|
assert @response.body.blank?
|
|
assert_not_nil @response.etag
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified_but_etag_differs_with_record
|
|
@request.if_modified_since = @last_modified
|
|
@request.if_none_match = "234"
|
|
get :conditional_hello_with_record
|
|
assert_response :success
|
|
end
|
|
|
|
def test_request_modified_with_record
|
|
@request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT'
|
|
get :conditional_hello_with_record
|
|
assert_equal 200, @response.status.to_i
|
|
assert @response.body.present?
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_responds_with_last_modified_with_collection_of_records
|
|
get :conditional_hello_with_collection_of_records
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified_with_collection_of_records
|
|
@request.if_modified_since = @last_modified
|
|
get :conditional_hello_with_collection_of_records
|
|
assert_equal 304, @response.status.to_i
|
|
assert @response.body.blank?
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_not_modified_but_etag_differs_with_collection_of_records
|
|
@request.if_modified_since = @last_modified
|
|
@request.if_none_match = "234"
|
|
get :conditional_hello_with_collection_of_records
|
|
assert_response :success
|
|
end
|
|
|
|
def test_request_modified_with_collection_of_records
|
|
@request.if_modified_since = 'Thu, 16 Jul 2008 00:00:00 GMT'
|
|
get :conditional_hello_with_collection_of_records
|
|
assert_equal 200, @response.status.to_i
|
|
assert @response.body.present?
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
end
|
|
|
|
def test_request_with_bang_gets_last_modified
|
|
get :conditional_hello_with_bangs
|
|
assert_equal @last_modified, @response.headers['Last-Modified']
|
|
assert_response :success
|
|
end
|
|
|
|
def test_request_with_bang_obeys_last_modified
|
|
@request.if_modified_since = @last_modified
|
|
get :conditional_hello_with_bangs
|
|
assert_response :not_modified
|
|
end
|
|
|
|
def test_last_modified_works_with_less_than_too
|
|
@request.if_modified_since = 5.years.ago.httpdate
|
|
get :conditional_hello_with_bangs
|
|
assert_response :success
|
|
end
|
|
end
|
|
|
|
class EtagRenderTest < ActionController::TestCase
|
|
tests TestControllerWithExtraEtags
|
|
|
|
def test_multiple_etags
|
|
@request.if_none_match = etag(["123", 'ab', :cde, [:f]])
|
|
get :fresh
|
|
assert_response :not_modified
|
|
|
|
@request.if_none_match = %("nomatch")
|
|
get :fresh
|
|
assert_response :success
|
|
end
|
|
|
|
def test_array
|
|
@request.if_none_match = etag([%w(1 2 3), 'ab', :cde, [:f]])
|
|
get :array
|
|
assert_response :not_modified
|
|
|
|
@request.if_none_match = %("nomatch")
|
|
get :array
|
|
assert_response :success
|
|
end
|
|
|
|
def test_etag_reflects_template_digest
|
|
get :with_template
|
|
assert_response :ok
|
|
assert_not_nil etag = @response.etag
|
|
|
|
request.if_none_match = etag
|
|
get :with_template
|
|
assert_response :not_modified
|
|
|
|
# Modify the template digest
|
|
path = File.expand_path('../../fixtures/test/hello_world.erb', __FILE__)
|
|
old = File.read(path)
|
|
|
|
begin
|
|
File.write path, 'foo'
|
|
ActionView::LookupContext::DetailsKey.clear
|
|
|
|
request.if_none_match = etag
|
|
get :with_template
|
|
assert_response :ok
|
|
assert_not_equal etag, @response.etag
|
|
ensure
|
|
File.write path, old
|
|
end
|
|
end
|
|
|
|
def etag(record)
|
|
%(W/"#{Digest::MD5.hexdigest(ActiveSupport::Cache.expand_cache_key(record))}")
|
|
end
|
|
end
|
|
|
|
class MetalRenderTest < ActionController::TestCase
|
|
tests MetalTestController
|
|
|
|
def test_access_to_logger_in_view
|
|
get :accessing_logger_in_template
|
|
assert_equal "NilClass", @response.body
|
|
end
|
|
end
|
|
|
|
class ImplicitRenderTest < ActionController::TestCase
|
|
tests ImplicitRenderTestController
|
|
|
|
def test_implicit_no_content_response_as_browser
|
|
assert_raises(ActionController::UnknownFormat) do
|
|
get :empty_action
|
|
end
|
|
end
|
|
|
|
def test_implicit_no_content_response_as_xhr
|
|
get :empty_action, xhr: true
|
|
assert_response :no_content
|
|
end
|
|
|
|
def test_implicit_success_response_with_right_format
|
|
get :empty_action_with_template
|
|
assert_equal "<h1>Empty action rendered this implicitly.</h1>\n", @response.body
|
|
assert_response :success
|
|
end
|
|
|
|
def test_implicit_unknown_format_response
|
|
assert_raises(ActionController::UnknownFormat) do
|
|
get :empty_action_with_template, format: 'json'
|
|
end
|
|
end
|
|
end
|
|
|
|
class HeadRenderTest < ActionController::TestCase
|
|
tests TestController
|
|
|
|
def setup
|
|
@request.host = "www.nextangle.com"
|
|
end
|
|
|
|
def test_head_created
|
|
post :head_created
|
|
assert @response.body.blank?
|
|
assert_response :created
|
|
end
|
|
|
|
def test_passing_hash_to_head_as_first_parameter_deprecated
|
|
assert_deprecated do
|
|
get :head_with_status_hash
|
|
end
|
|
end
|
|
|
|
def test_head_with_default_value_is_deprecated
|
|
assert_deprecated do
|
|
get :head_with_hash_does_not_include_status
|
|
assert_response :ok
|
|
end
|
|
end
|
|
|
|
def test_head_created_with_application_json_content_type
|
|
post :head_created_with_application_json_content_type
|
|
assert @response.body.blank?
|
|
assert_equal "application/json", @response.header["Content-Type"]
|
|
assert_response :created
|
|
end
|
|
|
|
def test_head_ok_with_image_png_content_type
|
|
post :head_ok_with_image_png_content_type
|
|
assert @response.body.blank?
|
|
assert_equal "image/png", @response.header["Content-Type"]
|
|
assert_response :ok
|
|
end
|
|
|
|
def test_head_with_location_header
|
|
get :head_with_location_header
|
|
assert @response.body.blank?
|
|
assert_equal "/foo", @response.headers["Location"]
|
|
assert_response :ok
|
|
end
|
|
|
|
def test_head_with_location_object
|
|
with_routing do |set|
|
|
set.draw do
|
|
resources :customers
|
|
|
|
ActiveSupport::Deprecation.silence do
|
|
get ':controller/:action'
|
|
end
|
|
end
|
|
|
|
get :head_with_location_object
|
|
assert @response.body.blank?
|
|
assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
|
|
assert_response :ok
|
|
end
|
|
end
|
|
|
|
def test_head_with_custom_header
|
|
get :head_with_custom_header
|
|
assert @response.body.blank?
|
|
assert_equal "something", @response.headers["X-Custom-Header"]
|
|
assert_response :ok
|
|
end
|
|
|
|
def test_head_with_www_authenticate_header
|
|
get :head_with_www_authenticate_header
|
|
assert @response.body.blank?
|
|
assert_equal "something", @response.headers["WWW-Authenticate"]
|
|
assert_response :ok
|
|
end
|
|
|
|
def test_head_with_symbolic_status
|
|
get :head_with_symbolic_status, params: { status: "ok" }
|
|
assert_equal 200, @response.status
|
|
assert_response :ok
|
|
|
|
get :head_with_symbolic_status, params: { status: "not_found" }
|
|
assert_equal 404, @response.status
|
|
assert_response :not_found
|
|
|
|
get :head_with_symbolic_status, params: { status: "no_content" }
|
|
assert_equal 204, @response.status
|
|
assert !@response.headers.include?('Content-Length')
|
|
assert_response :no_content
|
|
|
|
Rack::Utils::SYMBOL_TO_STATUS_CODE.each do |status, code|
|
|
get :head_with_symbolic_status, params: { status: status.to_s }
|
|
assert_equal code, @response.response_code
|
|
assert_response status
|
|
end
|
|
end
|
|
|
|
def test_head_with_integer_status
|
|
Rack::Utils::HTTP_STATUS_CODES.each do |code, message|
|
|
get :head_with_integer_status, params: { status: code.to_s }
|
|
assert_equal message, @response.message
|
|
end
|
|
end
|
|
|
|
def test_head_with_no_content
|
|
get :head_with_no_content
|
|
|
|
assert_equal 204, @response.status
|
|
assert_nil @response.headers["Content-Type"]
|
|
assert_nil @response.headers["Content-Length"]
|
|
end
|
|
|
|
def test_head_with_string_status
|
|
get :head_with_string_status, params: { status: "404 Eat Dirt" }
|
|
assert_equal 404, @response.response_code
|
|
assert_equal "Not Found", @response.message
|
|
assert_response :not_found
|
|
end
|
|
|
|
def test_head_with_status_code_first
|
|
get :head_with_status_code_first
|
|
assert_equal 403, @response.response_code
|
|
assert_equal "Forbidden", @response.message
|
|
assert_equal "something", @response.headers["X-Custom-Header"]
|
|
assert_response :forbidden
|
|
end
|
|
|
|
def test_head_returns_truthy_value
|
|
assert_nothing_raised do
|
|
get :head_and_return
|
|
end
|
|
end
|
|
end
|
|
|
|
class HttpCacheForeverTest < ActionController::TestCase
|
|
class HttpCacheForeverController < ActionController::Base
|
|
def cache_me_forever
|
|
http_cache_forever(public: params[:public], version: params[:version] || 'v1') do
|
|
render plain: 'hello'
|
|
end
|
|
end
|
|
end
|
|
|
|
tests HttpCacheForeverController
|
|
|
|
def test_cache_with_public
|
|
get :cache_me_forever, params: {public: true}
|
|
assert_equal "max-age=#{100.years}, public", @response.headers["Cache-Control"]
|
|
assert_not_nil @response.etag
|
|
end
|
|
|
|
def test_cache_with_private
|
|
get :cache_me_forever
|
|
assert_equal "max-age=#{100.years}, private", @response.headers["Cache-Control"]
|
|
assert_not_nil @response.etag
|
|
assert_response :success
|
|
end
|
|
|
|
def test_cache_response_code_with_if_modified_since
|
|
get :cache_me_forever
|
|
assert_response :success
|
|
@request.if_modified_since = @response.headers['Last-Modified']
|
|
get :cache_me_forever
|
|
assert_response :not_modified
|
|
end
|
|
|
|
def test_cache_response_code_with_etag
|
|
get :cache_me_forever
|
|
assert_response :success
|
|
@request.if_modified_since = @response.headers['Last-Modified']
|
|
@request.if_none_match = @response.etag
|
|
|
|
get :cache_me_forever
|
|
assert_response :not_modified
|
|
@request.if_modified_since = @response.headers['Last-Modified']
|
|
@request.if_none_match = @response.etag
|
|
|
|
get :cache_me_forever, params: {version: 'v2'}
|
|
assert_response :success
|
|
@request.if_modified_since = @response.headers['Last-Modified']
|
|
@request.if_none_match = @response.etag
|
|
|
|
get :cache_me_forever, params: {version: 'v2'}
|
|
assert_response :not_modified
|
|
end
|
|
end
|