summary refs log tree commit
diff options
context:
space:
mode:
authorRobin Wallin <walro467@gmail.com>2021-11-14 22:16:07 +0100
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2022-01-25 17:57:20 +1300
commita411e18b00fe58187eb95dd1479878631f3a7473 (patch)
treea38b7b373e06d0411483224432645fd8c912ebae
parentf1583d47f695a1799fb568bb57f2c3687d2fd40c (diff)
downloadrack-a411e18b00fe58187eb95dd1479878631f3a7473.tar.gz
Properly set the expires attribute for the mock response cookie
Prior to this change, cookies with the `Expires` attribute would have the attribute stored as a `String` object  rather than a `Time` object. `CGI::Cookie` expects a `Time` object [1]. Having strings could lead to confusing errors later on. For example, calling `Rack::MockResponse#inspect` would lead to `undefined method `gmtime' for "Fri, 03 Jun 2022 19:37:33 GMT":String`.

As per RFC 6265, if a cookie has both the `Max-Age` and the `Expires` attribute, `Max-Age` has precedence. [2]

Close #1758

[1]: https://ruby-doc.org/stdlib-3.0.1/libdoc/cgi/rdoc/CGI/Cookie.html
[2]: https://datatracker.ietf.org/doc/html/rfc6265#section-4.1.2.2
-rw-r--r--lib/rack/mock.rb11
-rw-r--r--test/spec_mock.rb23
2 files changed, 30 insertions, 4 deletions
diff --git a/lib/rack/mock.rb b/lib/rack/mock.rb
index 184e3cbb..33339117 100644
--- a/lib/rack/mock.rb
+++ b/lib/rack/mock.rb
@@ -4,6 +4,7 @@ require 'uri'
 require 'stringio'
 require_relative '../rack'
 require 'cgi/cookie'
+require 'time'
 
 module Rack
   # Rack::MockRequest helps testing your Rack application without
@@ -260,14 +261,18 @@ module Rack
         if bit.include? '='
           cookie_attribute, attribute_value = bit.split('=', 2)
           cookie_attributes.store(cookie_attribute.strip, attribute_value.strip)
-          if cookie_attribute.include? 'max-age'
-            cookie_attributes.store('expires', Time.now + attribute_value.strip.to_i)
-          end
         end
         if bit.include? 'secure'
           cookie_attributes.store('secure', true)
         end
       end
+
+      if cookie_attributes.key? 'max-age'
+        cookie_attributes.store('expires', Time.now + cookie_attributes['max-age'].to_i)
+      elsif cookie_attributes.key? 'expires'
+        cookie_attributes.store('expires', Time.httpdate(cookie_attributes['expires']))
+      end
+
       cookie_attributes
     end
 
diff --git a/test/spec_mock.rb b/test/spec_mock.rb
index 08e3a457..e81f8d83 100644
--- a/test/spec_mock.rb
+++ b/test/spec_mock.rb
@@ -30,6 +30,8 @@ app = Rack::Lint.new(lambda { |env|
   response.set_cookie("session_test", { value: "session_test", domain: ".test.com", path: "/" })
   response.set_cookie("secure_test", { value: "secure_test", domain: ".test.com",  path: "/", secure: true })
   response.set_cookie("persistent_test", { value: "persistent_test", max_age: 15552000, path: "/" })
+  response.set_cookie("persistent_with_expires_test", { value: "persistent_with_expires_test", expires: Time.httpdate("Thu, 31 Oct 2021 07:28:00 GMT"), path: "/" })
+  response.set_cookie("expires_and_max-age_test", { value: "expires_and_max-age_test", expires: Time.now + 15552000 * 2, max_age: 15552000, path: "/" })
   response.finish
 })
 
@@ -307,7 +309,7 @@ describe Rack::MockResponse do
     session_cookie.expires.must_be_nil
   end
 
-  it "provide access to persistent cookies" do
+  it "provides access to persistent cookies set with max-age" do
     res = Rack::MockRequest.new(app).get("")
     persistent_cookie = res.cookie("persistent_test")
     persistent_cookie.value[0].must_equal "persistent_test"
@@ -318,6 +320,25 @@ describe Rack::MockResponse do
     persistent_cookie.expires.must_be :<, (Time.now + 15552000)
   end
 
+  it "provides access to persistent cookies set with expires" do
+    res = Rack::MockRequest.new(app).get("")
+    persistent_cookie = res.cookie("persistent_with_expires_test")
+    persistent_cookie.value[0].must_equal "persistent_with_expires_test"
+    persistent_cookie.domain.must_be_nil
+    persistent_cookie.path.must_equal "/"
+    persistent_cookie.secure.must_equal false
+    persistent_cookie.expires.wont_be_nil
+    persistent_cookie.expires.must_equal Time.httpdate("Thu, 31 Oct 2021 07:28:00 GMT")
+  end
+
+  it "parses cookies giving max-age precedence over expires" do
+    res = Rack::MockRequest.new(app).get("")
+    persistent_cookie = res.cookie("expires_and_max-age_test")
+    persistent_cookie.value[0].must_equal "expires_and_max-age_test"
+    persistent_cookie.expires.wont_be_nil
+    persistent_cookie.expires.must_be :<, (Time.now + 15552000)
+  end
+
   it "provide access to secure cookies" do
     res = Rack::MockRequest.new(app).get("")
     secure_cookie = res.cookie("secure_test")