summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Williams <samuel.williams@oriontransfer.co.nz>2020-01-09 11:21:43 +1300
committerSamuel Williams <samuel.williams@oriontransfer.co.nz>2020-01-09 11:25:28 +1300
commita49b0ab9afb13f85b9117b37f9fe2ca3d33e7701 (patch)
tree255e2eca9dbc0615592872b3b47e038a42fbdaef
parent126a3800ec37f50ed017a56b6bdab4d15fc78a75 (diff)
downloadrack-a49b0ab9afb13f85b9117b37f9fe2ca3d33e7701.tar.gz
Use "strict encoding" for Base64 encoded cookiesbase64-strict
The prior implementation would include new lines characters. Subsequently, these characters would then be URI encoded when the headers are written (as "%0A"). Not including new lines via "strict encoding" will slightly reduce the size for long session values. In order to handle existing sessions encoded with new lines, Base64#decode will handle ArgumentError exceptions and try to decode using non-strict encoding. A couple of small specs have also been added for this case. # Conflicts: # lib/rack/session/cookie.rb
-rw-r--r--lib/rack/session/cookie.rb2
-rw-r--r--test/spec_session_cookie.rb62
2 files changed, 52 insertions, 12 deletions
diff --git a/lib/rack/session/cookie.rb b/lib/rack/session/cookie.rb
index d78fa997..d110aee2 100644
--- a/lib/rack/session/cookie.rb
+++ b/lib/rack/session/cookie.rb
@@ -52,7 +52,7 @@ module Rack
# Encode session cookies as Base64
class Base64
def encode(str)
- ::Base64.encode64(str)
+ ::Base64.strict_encode64(str)
end
def decode(str)
diff --git a/test/spec_session_cookie.rb b/test/spec_session_cookie.rb
index 9b4442dd..57850239 100644
--- a/test/spec_session_cookie.rb
+++ b/test/spec_session_cookie.rb
@@ -76,26 +76,32 @@ describe Rack::Session::Cookie do
it 'uses base64 to encode' do
coder = Rack::Session::Cookie::Base64.new
str = 'fuuuuu'
- coder.encode(str).must_equal [str].pack('m')
+ coder.encode(str).must_equal [str].pack('m0')
end
it 'uses base64 to decode' do
coder = Rack::Session::Cookie::Base64.new
- str = ['fuuuuu'].pack('m')
- coder.decode(str).must_equal str.unpack('m').first
+ str = ['fuuuuu'].pack('m0')
+ coder.decode(str).must_equal str.unpack('m0').first
+ end
+
+ it 'handles non-strict base64 encoding' do
+ coder = Rack::Session::Cookie::Base64.new
+ str = ['A' * 256].pack('m')
+ coder.decode(str).must_equal 'A' * 256
end
describe 'Marshal' do
it 'marshals and base64 encodes' do
coder = Rack::Session::Cookie::Base64::Marshal.new
str = 'fuuuuu'
- coder.encode(str).must_equal [::Marshal.dump(str)].pack('m')
+ coder.encode(str).must_equal [::Marshal.dump(str)].pack('m0')
end
it 'marshals and base64 decodes' do
coder = Rack::Session::Cookie::Base64::Marshal.new
- str = [::Marshal.dump('fuuuuu')].pack('m')
- coder.decode(str).must_equal ::Marshal.load(str.unpack('m').first)
+ str = [::Marshal.dump('fuuuuu')].pack('m0')
+ coder.decode(str).must_equal ::Marshal.load(str.unpack('m0').first)
end
it 'rescues failures on decode' do
@@ -108,13 +114,13 @@ describe Rack::Session::Cookie do
it 'JSON and base64 encodes' do
coder = Rack::Session::Cookie::Base64::JSON.new
obj = %w[fuuuuu]
- coder.encode(obj).must_equal [::JSON.dump(obj)].pack('m')
+ coder.encode(obj).must_equal [::JSON.dump(obj)].pack('m0')
end
it 'JSON and base64 decodes' do
coder = Rack::Session::Cookie::Base64::JSON.new
- str = [::JSON.dump(%w[fuuuuu])].pack('m')
- coder.decode(str).must_equal ::JSON.parse(str.unpack('m').first)
+ str = [::JSON.dump(%w[fuuuuu])].pack('m0')
+ coder.decode(str).must_equal ::JSON.parse(str.unpack('m0').first)
end
it 'rescues failures on decode' do
@@ -128,14 +134,14 @@ describe Rack::Session::Cookie do
coder = Rack::Session::Cookie::Base64::ZipJSON.new
obj = %w[fuuuuu]
json = JSON.dump(obj)
- coder.encode(obj).must_equal [Zlib::Deflate.deflate(json)].pack('m')
+ coder.encode(obj).must_equal [Zlib::Deflate.deflate(json)].pack('m0')
end
it 'base64 decodes, inflates, and decodes json' do
coder = Rack::Session::Cookie::Base64::ZipJSON.new
obj = %w[fuuuuu]
json = JSON.dump(obj)
- b64 = [Zlib::Deflate.deflate(json)].pack('m')
+ b64 = [Zlib::Deflate.deflate(json)].pack('m0')
coder.decode(b64).must_equal obj
end
@@ -441,4 +447,38 @@ describe Rack::Session::Cookie do
response = response_for(app: _app, cookie: response)
response.body.must_equal "1--2--"
end
+
+ it 'allows for non-strict encoded cookie' do
+ long_session_app = lambda do |env|
+ env['rack.session']['value'] = 'A' * 256
+ env['rack.session']['counter'] = 1
+ hash = env["rack.session"].dup
+ hash.delete("session_id")
+ Rack::Response.new(hash.inspect).to_a
+ end
+
+ non_strict_coder = Class.new {
+ def encode(str)
+ [Marshal.dump(str)].pack('m')
+ end
+
+ def decode(str)
+ return unless str
+
+ Marshal.load(str.unpack('m').first)
+ end
+ }.new
+
+ non_strict_response = response_for(app: [
+ long_session_app, { coder: non_strict_coder }
+ ])
+
+ response = response_for(app: [
+ incrementor
+ ], cookie: non_strict_response)
+
+ response.body.must_match %Q["value"=>"#{'A' * 256}"]
+ response.body.must_match '"counter"=>2'
+ response.body.must_match(/\A{[^}]+}\z/)
+ end
end