Skip to content

Commit b8e4640

Browse files
Handling relative paths with extra URI parts.
1 parent f735328 commit b8e4640

File tree

2 files changed

+37
-5
lines changed

2 files changed

+37
-5
lines changed

actionpack/lib/action_controller/metal/request_forgery_protection.rb

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -637,16 +637,22 @@ def normalize_action_path(action_path) # :doc:
637637
uri = URI.parse(action_path)
638638

639639
if uri.relative? && (action_path.blank? || !action_path.start_with?("/"))
640-
uri = URI.parse(request.path)
641-
# add the action path to the request.path
642-
uri.path += "/#{action_path}"
643-
# relative path with "./path"
644-
uri.path.gsub!("/./", "/")
640+
return normalize_relative_action_path(uri.path)
645641
end
646642

647643
uri.path.chomp("/")
648644
end
649645

646+
def normalize_relative_action_path(rel_action_path) # :doc:
647+
uri = URI.parse(request.path)
648+
# add the action path to the request.path
649+
uri.path += "/#{rel_action_path}"
650+
# relative path with "./path"
651+
uri.path.gsub!("/./", "/")
652+
653+
uri.path.chomp("/")
654+
end
655+
650656
def generate_csrf_token # :nodoc:
651657
SecureRandom.urlsafe_base64(AUTHENTICITY_TOKEN_LENGTH)
652658
end

actionpack/test/controller/request_forgery_protection_test.rb

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1151,6 +1151,32 @@ def test_handles_relative_paths_with_dot
11511151
assert_response :success
11521152
end
11531153

1154+
def test_handles_query_string
1155+
get :index, params: { form_path: "./post_one?a=b" }
1156+
1157+
form_token = assert_presence_and_fetch_form_csrf_token
1158+
1159+
# This is required because PATH_INFO isn't reset between requests.
1160+
@request.env["PATH_INFO"] = "/per_form_tokens/post_one"
1161+
assert_nothing_raised do
1162+
post :post_one, params: { custom_authenticity_token: form_token }
1163+
end
1164+
assert_response :success
1165+
end
1166+
1167+
def test_handles_fragment
1168+
get :index, params: { form_path: "./post_one#a" }
1169+
1170+
form_token = assert_presence_and_fetch_form_csrf_token
1171+
1172+
# This is required because PATH_INFO isn't reset between requests.
1173+
@request.env["PATH_INFO"] = "/per_form_tokens/post_one"
1174+
assert_nothing_raised do
1175+
post :post_one, params: { custom_authenticity_token: form_token }
1176+
end
1177+
assert_response :success
1178+
end
1179+
11541180
def test_ignores_origin_during_generation
11551181
get :index, params: { form_path: "https://example.com/per_form_tokens/post_one/" }
11561182

0 commit comments

Comments
 (0)