From cce5c0b441beaca4b6053af7fda6a0b02a852df9 Mon Sep 17 00:00:00 2001 From: Jan Berkel Date: Tue, 29 Jun 2010 12:02:28 +0200 Subject: [PATCH] Backported patch from [#4762] URL fragments should not have safe characters escaped. Ref: Appendix A, http://tools.ietf.org/rfc/rfc3986.txt --- actionpack/lib/action_controller/url_rewriter.rb | 10 +++++++++- actionpack/test/controller/url_rewriter_test.rb | 12 +++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/actionpack/lib/action_controller/url_rewriter.rb b/actionpack/lib/action_controller/url_rewriter.rb index 13194bc..552c2ae 100644 --- a/actionpack/lib/action_controller/url_rewriter.rb +++ b/actionpack/lib/action_controller/url_rewriter.rb @@ -92,6 +92,14 @@ module ActionController # end # end module UrlWriter + RESERVED_PCHAR = ':@&=+$,;%' + SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}" + if RUBY_VERSION >= '1.9' + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze + else + UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false, 'N').freeze + end + def self.included(base) #:nodoc: ActionController::Routing::Routes.install_helpers(base) base.mattr_accessor :default_url_options @@ -142,7 +150,7 @@ module ActionController end trailing_slash = options.delete(:trailing_slash) if options.key?(:trailing_slash) url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root] - anchor = "##{CGI.escape options.delete(:anchor).to_param.to_s}" if options[:anchor] + anchor = "##{URI.escape(options.delete(:anchor).to_param.to_s, UNSAFE_PCHAR)}" if options[:anchor] generated = Routing::Routes.generate(options, {}) url << (trailing_slash ? generated.sub(/\?|\z/) { "/" + $& } : generated) url << anchor if anchor diff --git a/actionpack/test/controller/url_rewriter_test.rb b/actionpack/test/controller/url_rewriter_test.rb index e9ae66b..11add3a 100644 --- a/actionpack/test/controller/url_rewriter_test.rb +++ b/actionpack/test/controller/url_rewriter_test.rb @@ -134,9 +134,15 @@ class UrlWriterTests < ActionController::TestCase ) end - def test_anchor_should_be_cgi_escaped - assert_equal('/c/a#anc%2Fhor', - W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('anc/hor')) + def test_anchor_should_escape_unsafe_pchar + assert_equal('/c/a#%23anchor', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('#anchor')) + ) + end + + def test_anchor_should_not_escape_safe_pchar + assert_equal('/c/a#name=user&email=user@domain.com', + W.new.url_for(:only_path => true, :controller => 'c', :action => 'a', :anchor => Struct.new(:to_param).new('name=user&email=user@domain.com')) ) end -- 1.7.0.4