From 41dcae71c7d10b9cc3c190897d02c5082ddd2076 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 27 Apr 2021 11:27:27 -0700 Subject: [PATCH] (PUP-11046) Implement RFC2396 style escape/unescape URI.escape/unescape was removed in Ruby 3, because it implements RFC 2396 escape/unescape with updates for RFCs 2732 and 2373, and those have been superseded by RFC 3986. To maintain 100% compatibility while supporting Ruby 3, implement the escape/unescape methods in puppet[1]. In the future we can look at using Addressable or using the newer URI parser in ruby. [1] https://github.com/ruby/ruby/blob/v2_7_3/lib/uri/rfc2396_parser.rb#L24-L46 --- lib/puppet/util.rb | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/puppet/util.rb b/lib/puppet/util.rb index db1aa640062..6986550755d 100644 --- a/lib/puppet/util.rb +++ b/lib/puppet/util.rb @@ -466,17 +466,7 @@ def uri_encode(path, opts = { :allow_fragment => false }) # URI::parse and URI::Generic.build don't like paths encoded with CGI.escape # URI.escape does not change / to %2F and : to %3A like CGI.escape # - # URI.escape is obsolete in Ruby 2.7. Ignore this error until we're able to - # switch to a different escape mechanism. If this is JRuby, we can't mask - # the error message, because this isn't thread safe. JRuby shouldn't be - # using Ruby 2.7 or raising the warning anyway. - orig_verbose = $VERBOSE - $VERBOSE = nil unless Puppet::Util::Platform.jruby? - begin - encoded += URI.escape(parts[:path]) unless parts[:path].nil? - ensure - $VERBOSE = orig_verbose unless Puppet::Util::Platform.jruby? - end + encoded += rfc2396_escape(parts[:path]) unless parts[:path].nil? # each query parameter if !parts[:query].nil? @@ -495,12 +485,31 @@ def uri_encode(path, opts = { :allow_fragment => false }) end module_function :uri_encode - def uri_unescape(path) - orig_verbose = $VERBOSE - $VERBOSE = nil unless Puppet::Util::Platform.jruby? - return URI.unescape(path) - ensure - $VERBOSE = orig_verbose unless Puppet::Util::Platform.jruby? + # From https://github.com/ruby/ruby/blob/v2_7_3/lib/uri/rfc2396_parser.rb#L24-L46 + ALPHA = "a-zA-Z".freeze + ALNUM = "#{ALPHA}\\d".freeze + UNRESERVED = "\\-_.!~*'()#{ALNUM}".freeze + RESERVED = ";/?:@&=+$,\\[\\]".freeze + UNSAFE = Regexp.new("[^#{UNRESERVED}#{RESERVED}]").freeze + + HEX = "a-fA-F\\d".freeze + ESCAPED = Regexp.new("%[#{HEX}]{2}").freeze + + def rfc2396_escape(str) + str.gsub(UNSAFE) do |match| + tmp = '' + match.each_byte do |uc| + tmp << sprintf('%%%02X', uc) + end + tmp + end.force_encoding(Encoding::US_ASCII) + end + module_function :rfc2396_escape + + def uri_unescape(str) + enc = str.encoding + enc = Encoding::UTF_8 if enc == Encoding::US_ASCII + str.gsub(ESCAPED) { [$&[1, 2]].pack('H2').force_encoding(enc) } end module_function :uri_unescape