From 2401b336fbe809430ac2943037665228766c15cc Mon Sep 17 00:00:00 2001 From: Adrianna Chang Date: Fri, 28 Jul 2023 15:38:43 -0400 Subject: [PATCH] Use expected casing for x-cascade headers in router This commit changes the router to use the expected casing for the x-cascade header: in Rack 2, this is mixed-case, and in Rack 3, this is lower case. This also fixes https://github.com/rails/rails/issues/47096. --- actionpack/lib/action_dispatch/constants.rb | 2 ++ .../lib/action_dispatch/http/request.rb | 2 +- .../lib/action_dispatch/journey/router.rb | 4 ++-- .../middleware/debug_exceptions.rb | 2 +- .../middleware/public_exceptions.rb | 2 +- .../middleware/show_exceptions.rb | 2 +- .../lib/action_dispatch/routing/mapper.rb | 2 +- .../lib/action_dispatch/routing/route_set.rb | 2 +- .../test/controller/integration_test.rb | 3 ++- .../test/dispatch/debug_exceptions_test.rb | 2 +- actionpack/test/dispatch/routing_test.rb | 22 +++++++++---------- .../test/dispatch/show_exceptions_test.rb | 4 ++-- actionpack/test/journey/router_test.rb | 4 ++-- 13 files changed, 28 insertions(+), 25 deletions(-) diff --git a/actionpack/lib/action_dispatch/constants.rb b/actionpack/lib/action_dispatch/constants.rb index f6a225de4cd2b..31ed436c4b657 100644 --- a/actionpack/lib/action_dispatch/constants.rb +++ b/actionpack/lib/action_dispatch/constants.rb @@ -13,6 +13,7 @@ module Constants LOCATION = "Location" FEATURE_POLICY = "Feature-Policy" X_REQUEST_ID = "X-Request-Id" + X_CASCADE = "X-Cascade" SERVER_TIMING = "Server-Timing" STRICT_TRANSPORT_SECURITY = "Strict-Transport-Security" else @@ -23,6 +24,7 @@ module Constants LOCATION = "location" FEATURE_POLICY = "feature-policy" X_REQUEST_ID = "x-request-id" + X_CASCADE = "x-cascade" SERVER_TIMING = "server-timing" STRICT_TRANSPORT_SECURITY = "strict-transport-security" end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index 8494fbdd60cb7..b28e3463acf76 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -72,7 +72,7 @@ def commit_cookie_jar! # :nodoc: PASS_NOT_FOUND = Class.new { # :nodoc: def self.action(_); self; end - def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end + def self.call(_); [404, { Constants::X_CASCADE => "pass" }, []]; end def self.action_encoding_template(action); false; end } diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb index af015cc98e047..119905a0de76c 100644 --- a/actionpack/lib/action_dispatch/journey/router.rb +++ b/actionpack/lib/action_dispatch/journey/router.rb @@ -50,7 +50,7 @@ def serve(req) _, headers, _ = response = route.app.serve(req) - if "pass" == headers["X-Cascade"] + if "pass" == headers[Constants::X_CASCADE] req.script_name = script_name req.path_info = path_info req.path_parameters = set_params @@ -60,7 +60,7 @@ def serve(req) return response end - [404, { "X-Cascade" => "pass" }, ["Not Found"]] + [404, { Constants::X_CASCADE => "pass" }, ["Not Found"]] end def recognize(rails_req) diff --git a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb index 187678d18a324..8a813d51fccfa 100644 --- a/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb @@ -28,7 +28,7 @@ def initialize(app, routes_app = nil, response_format = :default, interceptors = def call(env) _, headers, body = response = @app.call(env) - if headers["X-Cascade"] == "pass" + if headers[Constants::X_CASCADE] == "pass" body.close if body.respond_to?(:close) raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" end diff --git a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb index a210988c82789..f937096dfbc66 100644 --- a/actionpack/lib/action_dispatch/middleware/public_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/public_exceptions.rb @@ -55,7 +55,7 @@ def render_html(status) if found || File.exist?(path) render_format(status, "text/html", File.read(path)) else - [404, { "X-Cascade" => "pass" }, []] + [404, { Constants::X_CASCADE => "pass" }, []] end end end diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index e8590d13a878a..6c525383da333 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -50,7 +50,7 @@ def render_exception(request, wrapper) request.path_info = "/#{status}" request.request_method = "GET" response = @exceptions_app.call(request.env) - response[1]["X-Cascade"] == "pass" ? pass_response(status) : response + response[1][Constants::X_CASCADE] == "pass" ? pass_response(status) : response rescue Exception => failsafe_error $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}" diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 0173e3c17fcc3..8b75d6cc0cbfb 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -46,7 +46,7 @@ def matches?(req) end def serve(req) - return [ 404, { "X-Cascade" => "pass" }, [] ] unless matches?(req) + return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req) @strategy.call @app, req end diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 1d6708d674fd7..f167414d8b043 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -34,7 +34,7 @@ def serve(req) if @raise_on_name_error raise else - [404, { "X-Cascade" => "pass" }, []] + [404, { Constants::X_CASCADE => "pass" }, []] end end diff --git a/actionpack/test/controller/integration_test.rb b/actionpack/test/controller/integration_test.rb index 2a4e9e4aa6490..3151cf1526fdb 100644 --- a/actionpack/test/controller/integration_test.rb +++ b/actionpack/test/controller/integration_test.rb @@ -782,7 +782,8 @@ def self.call(*) get "bar", to: "application_integration_test/test#index", as: :bar mount MountedApp => "/mounted", :as => "mounted" - get "fooz" => proc { |env| [ 200, { "X-Cascade" => "pass" }, [ "omg" ] ] }, :anchor => false + get "fooz" => proc { |env| [ 200, { ActionDispatch::Constants::X_CASCADE => "pass" }, [ "omg" ] ] }, + :anchor => false get "fooz", to: "application_integration_test/test#index" end diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb index d9ad35baf5bb7..7ac7cc372b010 100644 --- a/actionpack/test/dispatch/debug_exceptions_test.rb +++ b/actionpack/test/dispatch/debug_exceptions_test.rb @@ -61,7 +61,7 @@ def call(env) case req.path when "/pass" - [404, { "X-Cascade" => "pass" }, self] + [404, { ActionDispatch::Constants::X_CASCADE => "pass" }, self] when "/not_found" controller = SimpleController.new raise AbstractController::ActionNotFound.new(nil, controller, :ello) diff --git a/actionpack/test/dispatch/routing_test.rb b/actionpack/test/dispatch/routing_test.rb index 2d5f38d8f14a3..a9be0cc1afb84 100644 --- a/actionpack/test/dispatch/routing_test.rb +++ b/actionpack/test/dispatch/routing_test.rb @@ -430,19 +430,19 @@ def test_admin assert_equal "queenbee#index", @response.body get "/admin", headers: { "REMOTE_ADDR" => "10.0.0.100" } - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] get "/admin/accounts", headers: { "REMOTE_ADDR" => "192.168.1.100" } assert_equal "queenbee#accounts", @response.body get "/admin/accounts", headers: { "REMOTE_ADDR" => "10.0.0.100" } - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] get "/admin/passwords", headers: { "REMOTE_ADDR" => "192.168.1.100" } assert_equal "queenbee#passwords", @response.body get "/admin/passwords", headers: { "REMOTE_ADDR" => "10.0.0.100" } - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] end def test_global @@ -890,13 +890,13 @@ def test_resource_routes_with_only_and_except assert_equal "/posts/1/comments", post_comments_path(post_id: 1) post "/posts" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] put "/posts/1" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] delete "/posts/1" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] delete "/posts/1/comments" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] end def test_resource_routes_only_create_update_destroy @@ -1325,7 +1325,7 @@ def test_articles_with_id assert_equal "articles#with_id", @response.body get "/articles/123/1" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] assert_equal "/articles/rails/1", article_with_title_path(title: "rails", id: 1) end @@ -1909,7 +1909,7 @@ def test_resource_constraints end get "/products/1" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] get "/products" assert_equal "products#root", @response.body get "/products/favorite" @@ -1918,14 +1918,14 @@ def test_resource_constraints assert_equal "products#show", @response.body get "/products/1/images" - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] get "/products/0001/images" assert_equal "images#index", @response.body get "/products/0001/images/0001" assert_equal "images#show", @response.body get "/dashboard", headers: { "REMOTE_ADDR" => "10.0.0.100" } - assert_equal "pass", @response.headers["X-Cascade"] + assert_equal "pass", @response.headers["x-cascade"] get "/dashboard", headers: { "REMOTE_ADDR" => "192.168.1.100" } assert_equal "dashboards#show", @response.body end diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 4b302c5d18188..a9475aa6afd50 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -117,9 +117,9 @@ def call(env) assert_equal "YOU FAILED", body end - test "returns an empty response if custom exceptions app returns X-Cascade pass" do + test "returns an empty response if custom exceptions app returns x-cascade pass" do exceptions_app = lambda do |env| - [404, { "X-Cascade" => "pass" }, []] + [404, { ActionDispatch::Constants::X_CASCADE => "pass" }, []] end @app = ActionDispatch::ShowExceptions.new(Boomer.new, exceptions_app) diff --git a/actionpack/test/journey/router_test.rb b/actionpack/test/journey/router_test.rb index d0ea022063439..5606b3ef2e5d3 100644 --- a/actionpack/test/journey/router_test.rb +++ b/actionpack/test/journey/router_test.rb @@ -110,11 +110,11 @@ def test_does_not_include_missing_keys_message assert_no_match(/missing required keys: \[\]/, error.message) end - def test_X_Cascade + def test_x_cascade get "/messages(.:format)", to: "foo#bar" resp = router.serve(rails_env("REQUEST_METHOD" => "GET", "PATH_INFO" => "/lol")) assert_equal ["Not Found"], resp.last - assert_equal "pass", resp[1]["X-Cascade"] + assert_equal "pass", resp[1][Constants::X_CASCADE] assert_equal 404, resp.first end