diff --git a/CHANGELOG.md b/CHANGELOG.md index 73480fa..f67038c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +* [BREAKING] We now rely only on rack-spec-compliant values to investigate the URLs. This should improve compatibility with different application servers. In particular, this means we now ignore the `REQUEST_URI` value and rely solely on `PATH_INFO`. If your application relies on `REQUEST_URI` being downcased, this could be a breaking change. + * Added support for URLs with non-ASCII characters in them. In other words, your application shouldn't get stuck in a an infinite redirect loop when a request contains non-ASCII characters that can be downcased. * Added Ruby 3.0, 3.1, 3.2 to the test matrix. diff --git a/lib/route_downcaser/downcase_route_middleware.rb b/lib/route_downcaser/downcase_route_middleware.rb index 6f64ae4..8f50573 100644 --- a/lib/route_downcaser/downcase_route_middleware.rb +++ b/lib/route_downcaser/downcase_route_middleware.rb @@ -13,26 +13,21 @@ def call(env) end def _call(env) - request_uri = env["REQUEST_URI"] path_info = env["PATH_INFO"] - # Don't touch anything, if uri/path is part of exclude_patterns - return @app.call(env) if excluded?([request_uri, path_info]) + # Don't touch anything, if path is part of exclude_patterns + return @app.call(env) if excluded?([path_info]) - # Downcase request_uri and/or path_info if applicable - request_uri = downcased_uri(request_uri) + # Downcase path_info if applicable path_info = downcased_uri(path_info) - # If redirect configured, then return redirect request, - # if either request_uri or path_info has changed + # If redirect configured, then return redirect request, if either + # path_info has changed if RouteDowncaser.redirect && env["REQUEST_METHOD"] == "GET" - return redirect_header(request_uri) if request_uri.present? && request_uri != env["REQUEST_URI"] - return redirect_header(path_info) if path_info.present? && path_info != env["PATH_INFO"] end env["PATH_INFO"] = path_info.to_s if path_info - env["REQUEST_URI"] = request_uri.to_s if request_uri # Default just move to next chain in Rack callstack # calling with downcased uri if needed diff --git a/test/route_downcaser_test.rb b/test/route_downcaser_test.rb index 4c95db9..6e61cc7 100644 --- a/test/route_downcaser_test.rb +++ b/test/route_downcaser_test.rb @@ -23,24 +23,6 @@ class BasicTests < ActiveSupport::TestCase end end - test "REQUEST_URI path-part is downcased" do - callenv = {"REQUEST_URI" => "HELLO/WORLD", "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal("hello/world", @app.env["REQUEST_URI"]) - end - - test "REQUEST_URI querystring parameters are not touched" do - callenv = {"REQUEST_URI" => "HELLO/WORLD?FOO=BAR", "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal("hello/world?FOO=BAR", @app.env["REQUEST_URI"]) - end - - test "REQUEST_URI querystring parameters can contain ?" do - callenv = {"REQUEST_URI" => "HELLO/WORLD?FOO=BAR?BAZ=BING", "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal("hello/world?FOO=BAR?BAZ=BING", @app.env["REQUEST_URI"]) - end - test "entire PATH_INFO is downcased" do callenv = {"PATH_INFO" => "HELLO/WORLD", "REQUEST_METHOD" => "GET"} RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) @@ -68,18 +50,6 @@ class ExcludePatternsTests < ActiveSupport::TestCase RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) assert_equal("/ASSETS/IMAges/SpaceCat.jpeg", @app.env["PATH_INFO"]) end - - test "when REQUEST_URI is found in exclude_patterns, do nothing" do - callenv = {"REQUEST_URI" => "ASSETS/IMAges/SpaceCat.jpeg", "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal("ASSETS/IMAges/SpaceCat.jpeg", @app.env["REQUEST_URI"]) - end - - test "the call environment should always be returned" do - callenv = {"REQUEST_URI" => "ASSETS/IMAges/SpaceCat.jpeg", "REQUEST_METHOD" => "GET"} - retval = RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal(callenv, retval) - end end class RedirectTrueTests < ActiveSupport::TestCase @@ -91,14 +61,6 @@ class RedirectTrueTests < ActiveSupport::TestCase end end - test "when redirect is true it redirects REQUEST_URI" do - callenv = {"REQUEST_URI" => "HELLO/WORLD", "REQUEST_METHOD" => "GET"} - assert_equal( - [301, {"Location" => "hello/world", "Content-Type" => "text/html"}, []], - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - ) - end - test "when redirect is true it redirects PATH_INFO" do callenv = {"PATH_INFO" => "/HELLO/WORLD", "REQUEST_METHOD" => "GET"} assert_equal( @@ -117,12 +79,6 @@ class RedirectTrueExcludePatternsTests < ActiveSupport::TestCase end end - test "when redirect is true it does not redirect, if REQUEST_URI match exclude patterns" do - callenv = {"REQUEST_URI" => "fonts/Icons.woff", "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal("fonts/Icons.woff", @app.env["REQUEST_URI"]) - end - test "when redirect is true it does not redirect, if PATH_INFO match exclude patterns" do callenv = {"PATH_INFO" => "/fonts/Icons.woff", "REQUEST_METHOD" => "GET"} RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) @@ -139,12 +95,6 @@ class MultibyteTests < ActiveSupport::TestCase end end - test "Multibyte REQUEST_URI path-part is downcased" do - callenv = {"REQUEST_URI" => URI.encode_www_form_component("ШУРШАЩАЯ ЗМЕЯ"), "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - assert_equal(URI.encode_www_form_component("шуршащая змея"), @app.env["REQUEST_URI"]) - end - test "Multibyte PATH_INFO is downcased" do callenv = {"PATH_INFO" => "/" + URI.encode_www_form_component("ВЕЛОСИПЕД"), "REQUEST_METHOD" => "GET"} RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) @@ -161,17 +111,6 @@ class MultibyteRedirectTests < ActiveSupport::TestCase end end - test "it redirects Multibyte REQUEST_URI" do - callenv = {"REQUEST_URI" => URI.encode_www_form_component("ШУРШАЩАЯ ЗМЕЯ"), "REQUEST_METHOD" => "GET"} - RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - result = RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv) - status, headers = *result - - assert_equal 301, status - assert_equal URI.encode_www_form_component("шуршащая змея"), headers["Location"] - assert_instance_of String, headers["Location"], "Headers must be strings" - end - test "it redirects Multibyte PATH_INFO" do callenv = {"PATH_INFO" => "/" + URI.encode_www_form_component("ВЕЛОСИПЕД"), "REQUEST_METHOD" => "GET"} RouteDowncaser::DowncaseRouteMiddleware.new(@app).call(callenv)