From e3442ed461a1c2474ce9e3b58ba55a9bc0cc2c11 Mon Sep 17 00:00:00 2001 From: Patrik Ragnarsson Date: Wed, 31 Jul 2024 12:58:54 +0200 Subject: [PATCH] Update headers and cookie handling for Rack 3 See the Rack 3 upgrade guide https://github.com/rack/rack/blob/df241355a7f122dc22437398267c1d5f0b27e1ad/UPGRADE-GUIDE.md --- lib/rack/ssl-enforcer.rb | 12 ++++++------ test/helper.rb | 4 ++-- test/rack-ssl-enforcer_test.rb | 28 ++++++++++++++-------------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/rack/ssl-enforcer.rb b/lib/rack/ssl-enforcer.rb index 72c071b..751a55d 100644 --- a/lib/rack/ssl-enforcer.rb +++ b/lib/rack/ssl-enforcer.rb @@ -93,7 +93,7 @@ def modify_location_and_redirect(req, scheme) location = replace_host(location, req, @options[:redirect_to]) redirect_to(location) rescue URI::InvalidURIError - [400, { 'Content-Type' => 'text/plain'}, []] + [400, { 'content-type' => 'text/plain'}, []] end def redirect_to(location) @@ -102,7 +102,7 @@ def redirect_to(location) body << @options[:redirect_html] if @options[:redirect_html].is_a?(String) body = @options[:redirect_html] if @options[:redirect_html].respond_to?('each') - [@options[:redirect_code] || 301, { 'Content-Type' => 'text/html', 'Location' => location }, body] + [@options[:redirect_code] || 301, { 'content-type' => 'text/html', 'location' => location }, body] end def ssl_request?(req) @@ -181,15 +181,15 @@ def adjust_port_to(scheme) # see http://en.wikipedia.org/wiki/HTTP_cookie#Cookie_theft_and_session_hijacking def flag_cookies_as_secure!(headers) - if cookies = headers['Set-Cookie'] + if cookies = headers['set-cookie'] # Support Rails 2.3 / Rack 1.1 arrays as headers unless cookies.is_a?(Array) cookies = cookies.split("\n") end - headers['Set-Cookie'] = cookies.map do |cookie| + headers['set-cookie'] = cookies.map do |cookie| cookie !~ /(^|;\s)secure($|;)/ ? "#{cookie}; secure" : cookie - end.join("\n") + end end end @@ -200,7 +200,7 @@ def set_hsts_headers!(headers) value = "max-age=#{opts[:expires]}" value += "; includeSubDomains" if opts[:subdomains] value += "; preload" if opts[:preload] - headers.merge!({ 'Strict-Transport-Security' => value }) + headers.merge!({ 'strict-transport-security' => value }) end end diff --git a/test/helper.rb b/test/helper.rb index 47c0e8d..099878b 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -16,8 +16,8 @@ def app; Rack::Lint.new(@app); end def mock_app(options_or_options_array = {}) main_app = lambda { |env| - headers = {'Content-Type' => "text/html"} - headers['Set-Cookie'] = "id=1; path=/\ntoken=abc; path=/; secure; HttpOnly" + headers = {'content-type' => "text/html"} + headers['set-cookie'] = ["id=1; path=/", "token=abc; path=/; secure; HttpOnly"] [200, headers, ['Hello world!']] } diff --git a/test/rack-ssl-enforcer_test.rb b/test/rack-ssl-enforcer_test.rb index 8d7ca55..84cd955 100644 --- a/test/rack-ssl-enforcer_test.rb +++ b/test/rack-ssl-enforcer_test.rb @@ -44,25 +44,25 @@ class TestRackSslEnforcer < Test::Unit::TestCase should 'secure cookies' do get 'https://www.example.org/' - assert_equal ["id=1; path=/; secure", "token=abc; path=/; secure; HttpOnly"], last_response.headers['Set-Cookie'].split("\n") + assert_equal ["id=1; path=/; secure", "token=abc; path=/; secure; HttpOnly"], last_response.headers['set-cookie'] end should 'not set default HSTS headers to SSL requests' do get 'https://www.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end should 'not set hsts headers to non-SSL requests' do get 'http://www.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end end context 'With Rails 2.3 / Rack 1.1-style Array-based cookies' do setup do main_app = lambda { |env| - headers = {'Content-Type' => "text/html"} - headers['Set-Cookie'] = ["id=1; path=/", "token=abc; path=/; HttpOnly"] + headers = {'content-type' => "text/html"} + headers['set-cookie'] = ["id=1; path=/", "token=abc; path=/; HttpOnly"] [200, headers, ['Hello world!']] } @@ -74,7 +74,7 @@ class TestRackSslEnforcer < Test::Unit::TestCase should 'secure cookies' do get 'https://www.example.org/' - assert_equal ["id=1; path=/; secure", "token=abc; path=/; HttpOnly; secure"], last_response.headers['Set-Cookie'].split("\n") + assert_equal ["id=1; path=/; secure", "token=abc; path=/; HttpOnly; secure"], last_response.headers['set-cookie'] end end @@ -708,22 +708,22 @@ def self.startup should 'not set hsts for www.example.org (HTTP)' do get 'http://www.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end should 'not set hsts for www.example.org (HTTPS)' do get 'https://www.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end should 'not set hsts for abc.example.org (HTTP)' do get 'http://abc.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end should 'not set hsts for abc.example.org (HTTPS)' do get 'https://abc.example.org/' - assert !last_response.headers["Strict-Transport-Security"] + assert !last_response.headers["strict-transport-security"] end end @@ -792,17 +792,17 @@ def self.startup should 'set expiry option' do get 'https://www.example.org/' - assert last_response.headers["Strict-Transport-Security"].include?("max-age=500") + assert last_response.headers["strict-transport-security"].include?("max-age=500") end should 'not include subdomains' do get 'https://www.example.org/' - assert !last_response.headers["Strict-Transport-Security"].include?("includeSubDomains") + assert !last_response.headers["strict-transport-security"].include?("includeSubDomains") end should 'set preload option' do get 'https://www.example.org' - assert last_response.headers["Strict-Transport-Security"].include?("preload") + assert last_response.headers["strict-transport-security"].include?("preload") end end @@ -811,7 +811,7 @@ def self.startup should 'not secure cookies but warn the user of the consequences' do get 'https://www.example.org/users/123/edit' - assert_equal ["id=1; path=/", "token=abc; path=/; secure; HttpOnly"], last_response.headers['Set-Cookie'].split("\n") + assert_equal ["id=1; path=/", "token=abc; path=/; secure; HttpOnly"], last_response.headers['set-cookie'] end end