Merge pull request #30121 from assain/add_expires_in_and_expires_at_to_cookies

Add expiry metadata to Cookies and freshen expires option to support duration
This commit is contained in:
Kasper Timm Hansen 2017-08-20 20:23:25 +02:00 committed by GitHub
commit cdcd6c0945
3 changed files with 54 additions and 5 deletions

@ -360,7 +360,11 @@ def to_header
@cookies.map { |k, v| "#{escape(k)}=#{escape(v)}" }.join "; "
end
def handle_options(options) #:nodoc:
def handle_options(options) # :nodoc:
if options[:expires].respond_to?(:from_now)
options[:expires] = options[:expires].from_now
end
options[:path] ||= "/"
if options[:domain] == :all || options[:domain] == "all"
@ -488,6 +492,14 @@ def []=(name, options)
def request; @parent_jar.request; end
private
def expiry_options(options)
if options[:expires].respond_to?(:from_now)
{ expires_in: options[:expires] }
else
{ expires_at: options[:expires] }
end
end
def parse(name, data); data; end
def commit(options); end
end
@ -569,7 +581,7 @@ def parse(name, signed_message)
end
def commit(options)
options[:value] = @verifier.generate(serialize(options[:value]))
options[:value] = @verifier.generate(serialize(options[:value]), expiry_options(options))
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
end
@ -609,7 +621,7 @@ def parse(name, encrypted_message)
end
def commit(options)
options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]))
options[:value] = @encryptor.encrypt_and_sign(serialize(options[:value]), expiry_options(options))
raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
end

@ -278,6 +278,11 @@ def noop
def encrypted_cookie
cookies.encrypted["foo"]
end
def cookie_expires_in_two_hours
cookies[:user_name] = { value: "assain", expires: 2.hours }
head :ok
end
end
tests TestController
@ -1235,6 +1240,33 @@ def test_cookies_are_not_cleared
assert_equal "bar", @controller.encrypted_cookie
end
def test_signed_cookie_with_expires_set_relatively
cookies.signed[:user_name] = { value: "assain", expires: 2.hours }
travel 1.hour
assert_equal "assain", cookies.signed[:user_name]
travel 2.hours
assert_nil cookies.signed[:user_name]
end
def test_encrypted_cookie_with_expires_set_relatively
cookies.encrypted[:user_name] = { value: "assain", expires: 2.hours }
travel 1.hour
assert_equal "assain", cookies.encrypted[:user_name]
travel 2.hours
assert_nil cookies.encrypted[:user_name]
end
def test_vanilla_cookie_with_expires_set_relatively
travel_to Time.utc(2017, 8, 15) do
get :cookie_expires_in_two_hours
assert_cookie_header "user_name=assain; path=/; expires=Tue, 15 Aug 2017 02:00:00 -0000"
end
end
private
def assert_cookie_header(expected)
header = @response.headers["Set-Cookie"]

@ -26,6 +26,11 @@ def set_session_value
render plain: Rack::Utils.escape(Verifier.generate(session.to_hash))
end
def set_session_value_expires_in_five_hours
session[:foo] = "bar"
render plain: Rack::Utils.escape(Verifier.generate(session.to_hash, expires_in: 5.hours))
end
def get_session_value
render plain: "foo: #{session[:foo].inspect}"
end
@ -283,7 +288,7 @@ def test_session_store_with_expire_after
cookies[SessionKey] = SignedBar
get "/set_session_value"
get "/set_session_value_expires_in_five_hours"
assert_response :success
cookie_body = response.body
@ -299,7 +304,7 @@ def test_session_store_with_expire_after
get "/no_session_access"
assert_response :success
assert_equal "_myapp_session=#{cookie_body}; path=/; expires=#{expected_expiry}; HttpOnly",
assert_equal "_myapp_session=#{cookies[SessionKey]}; path=/; expires=#{expected_expiry}; HttpOnly",
headers["Set-Cookie"]
end
end