mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
aa3dcabd87
Since Rails 6.0 will support Ruby 2.4.1 or higher `# frozen_string_literal: true` magic comment is enough to make string object frozen. This magic comment is enabled by `Style/FrozenStringLiteralComment` cop. * Exclude these files not to auto correct false positive `Regexp#freeze` - 'actionpack/lib/action_dispatch/journey/router/utils.rb' - 'activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb' It has been fixed by https://github.com/rubocop-hq/rubocop/pull/6333 Once the newer version of RuboCop released and available at Code Climate these exclude entries should be removed. * Replace `String#freeze` with `String#-@` manually if explicit frozen string objects are required - 'actionpack/test/controller/test_case_test.rb' - 'activemodel/test/cases/type/string_test.rb' - 'activesupport/lib/active_support/core_ext/string/strip.rb' - 'activesupport/test/core_ext/string_ext_test.rb' - 'railties/test/generators/actions_test.rb'
102 lines
3.1 KiB
Ruby
102 lines
3.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module ActionDispatch
|
|
module Journey # :nodoc:
|
|
class Router # :nodoc:
|
|
class Utils # :nodoc:
|
|
# Normalizes URI path.
|
|
#
|
|
# Strips off trailing slash and ensures there is a leading slash.
|
|
# Also converts downcase URL encoded string to uppercase.
|
|
#
|
|
# normalize_path("/foo") # => "/foo"
|
|
# normalize_path("/foo/") # => "/foo"
|
|
# normalize_path("foo") # => "/foo"
|
|
# normalize_path("") # => "/"
|
|
# normalize_path("/%ab") # => "/%AB"
|
|
def self.normalize_path(path)
|
|
path ||= ""
|
|
encoding = path.encoding
|
|
path = +"/#{path}"
|
|
path.squeeze!("/")
|
|
path.sub!(%r{/+\Z}, "")
|
|
path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
|
|
path = +"/" if path == ""
|
|
path.force_encoding(encoding)
|
|
path
|
|
end
|
|
|
|
# URI path and fragment escaping
|
|
# https://tools.ietf.org/html/rfc3986
|
|
class UriEncoder # :nodoc:
|
|
ENCODE = "%%%02X"
|
|
US_ASCII = Encoding::US_ASCII
|
|
UTF_8 = Encoding::UTF_8
|
|
EMPTY = (+"").force_encoding(US_ASCII).freeze
|
|
DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
|
|
|
|
ALPHA = "a-zA-Z"
|
|
DIGIT = "0-9"
|
|
UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
|
|
SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
|
|
|
|
ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
|
|
|
|
FRAGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/\?]/.freeze
|
|
SEGMENT = /[^#{UNRESERVED}#{SUB_DELIMS}:@]/.freeze
|
|
PATH = /[^#{UNRESERVED}#{SUB_DELIMS}:@\/]/.freeze
|
|
|
|
def escape_fragment(fragment)
|
|
escape(fragment, FRAGMENT)
|
|
end
|
|
|
|
def escape_path(path)
|
|
escape(path, PATH)
|
|
end
|
|
|
|
def escape_segment(segment)
|
|
escape(segment, SEGMENT)
|
|
end
|
|
|
|
def unescape_uri(uri)
|
|
encoding = uri.encoding == US_ASCII ? UTF_8 : uri.encoding
|
|
uri.gsub(ESCAPED) { |match| [match[1, 2].hex].pack("C") }.force_encoding(encoding)
|
|
end
|
|
|
|
private
|
|
def escape(component, pattern)
|
|
component.gsub(pattern) { |unsafe| percent_encode(unsafe) }.force_encoding(US_ASCII)
|
|
end
|
|
|
|
def percent_encode(unsafe)
|
|
safe = EMPTY.dup
|
|
unsafe.each_byte { |b| safe << DEC2HEX[b] }
|
|
safe
|
|
end
|
|
end
|
|
|
|
ENCODER = UriEncoder.new
|
|
|
|
def self.escape_path(path)
|
|
ENCODER.escape_path(path.to_s)
|
|
end
|
|
|
|
def self.escape_segment(segment)
|
|
ENCODER.escape_segment(segment.to_s)
|
|
end
|
|
|
|
def self.escape_fragment(fragment)
|
|
ENCODER.escape_fragment(fragment.to_s)
|
|
end
|
|
|
|
# Replaces any escaped sequences with their unescaped representations.
|
|
#
|
|
# uri = "/topics?title=Ruby%20on%20Rails"
|
|
# unescape_uri(uri) #=> "/topics?title=Ruby on Rails"
|
|
def self.unescape_uri(uri)
|
|
ENCODER.unescape_uri(uri)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|