diff --git a/CHANGELOG.md b/CHANGELOG.md index 3021af3e..92d925c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ### Fixed +- [Router] Compose and restore `SCRIPT_NAME` correctly for mounted Rack apps. - [OpenAPI] Fix schema registry key collisions for Blueprinter classes referenced under different views. ## [1.26.0] - 2026-07-07 diff --git a/lib/rage/router/backend.rb b/lib/rage/router/backend.rb index 9e59f0d6..4b27d7f6 100644 --- a/lib/rage/router/backend.rb +++ b/lib/rage/router/backend.rb @@ -35,13 +35,17 @@ def mount(path, handler, methods) # by the time the app is called, `rack.input` is already consumed in `Rage::ParamsParser` env["rack.input"].rewind - env["SCRIPT_NAME"] = path - sub_path = env["PATH_INFO"].delete_prefix!(path) - env["PATH_INFO"] = "/" if sub_path == "" + script_name = env["SCRIPT_NAME"] + path_info = env["PATH_INFO"] + + env["SCRIPT_NAME"] = "#{script_name}#{path}" + sub_path = path_info.delete_prefix(path) + env["PATH_INFO"] = sub_path == "" ? "/" : sub_path handler.call(env) ensure - env["PATH_INFO"] = "#{env["SCRIPT_NAME"]}#{sub_path}" + env["SCRIPT_NAME"] = script_name + env["PATH_INFO"] = path_info end methods.each do |method| diff --git a/spec/router/mount_spec.rb b/spec/router/mount_spec.rb index a324bd73..2eda5031 100644 --- a/spec/router/mount_spec.rb +++ b/spec/router/mount_spec.rb @@ -28,6 +28,30 @@ expect(result).to eq("/rack_app") end + it "composes and restores script name for mounted apps" do + seen = nil + + router.mount("/rack_app", ->(env) { + seen = { script_name: env["SCRIPT_NAME"], path_info: env["PATH_INFO"] } + :rack_app_response + }, %w(GET)) + + env = { + "REQUEST_METHOD" => "GET", + "PATH_INFO" => "/rack_app/index", + "SCRIPT_NAME" => "/outer", + "rack.input" => StringIO.new + } + + handler = router.lookup(env) + result = handler[:handler].call(env, handler[:params]) + + expect(result).to eq(:rack_app_response) + expect(seen).to eq({ script_name: "/outer/rack_app", path_info: "/index" }) + expect(env["SCRIPT_NAME"]).to eq("/outer") + expect(env["PATH_INFO"]).to eq("/rack_app/index") + end + it "updates path info" do router.mount("/rack_app", ->(env) { env["PATH_INFO"] }, %w(GET))