addressable 2.7.0 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/CHANGELOG.md +12 -1
- data/Gemfile +11 -15
- data/README.md +7 -7
- data/addressable.gemspec +37 -0
- data/lib/addressable/idna/pure.rb +34 -32
- data/lib/addressable/template.rb +25 -39
- data/lib/addressable/uri.rb +44 -17
- data/lib/addressable/version.rb +1 -1
- data/spec/addressable/idna_spec.rb +3 -1
- data/spec/addressable/template_spec.rb +9 -0
- data/spec/addressable/uri_spec.rb +265 -203
- data/spec/spec_helper.rb +9 -0
- data/tasks/gem.rake +0 -1
- data/tasks/profile.rake +72 -0
- data/tasks/rspec.rake +1 -1
- metadata +5 -5
- data/spec/addressable/rack_mount_compat_spec.rb +0 -106
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 | 
            -
             | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 2 | 
            +
            SHA256:
         | 
| 3 | 
            +
              metadata.gz: 03a21b1eab156a16e90bd7963af85980edfbddc8f3dbe052766303dba76cc000
         | 
| 4 | 
            +
              data.tar.gz: 03eca5d86f4c70f9320000f36e3cff4fd8023342a4e0ac855d0ef1ec89ee6183
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d504f9475ad823f5bb077b9c039a2c91c83e52c20896247a7289b61725c61b1ddefe8ae06155fb018fc67087cf04276081b42105a18394b45e2374ad0b2fadb0
         | 
| 7 | 
            +
              data.tar.gz: b81766fbcb9335d5ca94403b62d3b2a6fae31b66cd3c05f48e1885eaf07883bfa1321b6930271fe1415135aec687af51312a26ce27bd4b83b2ac6424dec597c9
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,7 +1,18 @@ | |
| 1 | 
            +
            # Addressable 2.8.0
         | 
| 2 | 
            +
            - fixes ReDoS vulnerability in Addressable::Template#match
         | 
| 3 | 
            +
            - no longer replaces `+` with spaces in queries for non-http(s) schemes
         | 
| 4 | 
            +
            - fixed encoding ipv6 literals
         | 
| 5 | 
            +
            - the `:compacted` flag for `normalized_query` now dedupes parameters
         | 
| 6 | 
            +
            - fix broken `escape_component` alias
         | 
| 7 | 
            +
            - dropping support for Ruby 2.0 and 2.1
         | 
| 8 | 
            +
            - adding Ruby 3.0 compatibility for development tasks
         | 
| 9 | 
            +
            - drop support for `rack-mount` and remove Addressable::Template#generate
         | 
| 10 | 
            +
            - performance improvements
         | 
| 11 | 
            +
            - switch CI/CD to GitHub Actions
         | 
| 12 | 
            +
             | 
| 1 13 | 
             
            # Addressable 2.7.0
         | 
| 2 14 | 
             
            - added `:compacted` flag to `normalized_query`
         | 
| 3 15 | 
             
            - `heuristic_parse` handles `mailto:` more intuitively
         | 
| 4 | 
            -
            - refactored validation to use a prepended module
         | 
| 5 16 | 
             
            - dropped explicit support for JRuby 9.0.5.0
         | 
| 6 17 | 
             
            - compatibility w/ public_suffix 4.x
         | 
| 7 18 | 
             
            - performance improvements
         | 
    
        data/Gemfile
    CHANGED
    
    | @@ -1,12 +1,19 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            source 'https://rubygems.org'
         | 
| 2 4 |  | 
| 3 | 
            -
            gemspec
         | 
| 5 | 
            +
            gemspec(path: __FILE__ == "(eval)" ? ".." : ".")
         | 
| 4 6 |  | 
| 5 7 | 
             
            group :test do
         | 
| 6 8 | 
             
              gem 'rspec', '~> 3.8'
         | 
| 7 9 | 
             
              gem 'rspec-its', '~> 1.3'
         | 
| 8 10 | 
             
            end
         | 
| 9 11 |  | 
| 12 | 
            +
            group :coverage do
         | 
| 13 | 
            +
              gem "coveralls", "> 0.7", require: false, platforms: :mri
         | 
| 14 | 
            +
              gem "simplecov", require: false
         | 
| 15 | 
            +
            end
         | 
| 16 | 
            +
             | 
| 10 17 | 
             
            group :development do
         | 
| 11 18 | 
             
              gem 'launchy', '~> 2.4', '>= 2.4.3'
         | 
| 12 19 | 
             
              gem 'redcarpet', :platform => :mri_19
         | 
| @@ -14,19 +21,8 @@ group :development do | |
| 14 21 | 
             
            end
         | 
| 15 22 |  | 
| 16 23 | 
             
            group :test, :development do
         | 
| 17 | 
            -
              gem ' | 
| 18 | 
            -
              gem  | 
| 19 | 
            -
              gem 'coveralls', :require => false, :platforms => [
         | 
| 20 | 
            -
                :ruby_20, :ruby_21, :ruby_22, :ruby_23
         | 
| 21 | 
            -
              ]
         | 
| 22 | 
            -
              # Used to test compatibility.
         | 
| 23 | 
            -
              gem 'rack-mount', git: 'https://github.com/sporkmonger/rack-mount.git', require: 'rack/mount'
         | 
| 24 | 
            -
             | 
| 25 | 
            -
              if RUBY_VERSION.start_with?('2.0', '2.1')
         | 
| 26 | 
            -
                gem 'rack', '< 2', :require => false
         | 
| 27 | 
            -
              else
         | 
| 28 | 
            -
                gem 'rack', :require => false
         | 
| 29 | 
            -
              end
         | 
| 24 | 
            +
              gem 'memory_profiler'
         | 
| 25 | 
            +
              gem "rake", ">= 12.3.3"
         | 
| 30 26 | 
             
            end
         | 
| 31 27 |  | 
| 32 | 
            -
            gem  | 
| 28 | 
            +
            gem "idn-ruby", platform: :mri
         | 
    
        data/README.md
    CHANGED
    
    | @@ -7,15 +7,15 @@ | |
| 7 7 | 
             
              <dt>License</dt><dd>Apache 2.0</dd>
         | 
| 8 8 | 
             
            </dl>
         | 
| 9 9 |  | 
| 10 | 
            -
            [][gem]
         | 
| 11 | 
            +
            [][actions]
         | 
| 12 12 | 
             
            [][coveralls]
         | 
| 13 | 
            -
            [][inch]
         | 
| 14 14 |  | 
| 15 15 | 
             
            [gem]: https://rubygems.org/gems/addressable
         | 
| 16 | 
            -
            [ | 
| 16 | 
            +
            [actions]: https://github.com/sporkmonger/addressable/actions
         | 
| 17 17 | 
             
            [coveralls]: https://coveralls.io/r/sporkmonger/addressable
         | 
| 18 | 
            -
            [inch]:  | 
| 18 | 
            +
            [inch]: https://inch-ci.org/github/sporkmonger/addressable
         | 
| 19 19 |  | 
| 20 20 | 
             
            # Description
         | 
| 21 21 |  | 
| @@ -98,7 +98,7 @@ You may optionally turn on native IDN support by installing libidn and the | |
| 98 98 | 
             
            idn gem:
         | 
| 99 99 |  | 
| 100 100 | 
             
            ```console
         | 
| 101 | 
            -
            $ sudo apt-get install  | 
| 101 | 
            +
            $ sudo apt-get install libidn11-dev # Debian/Ubuntu
         | 
| 102 102 | 
             
            $ brew install libidn # OS X
         | 
| 103 103 | 
             
            $ gem install idn-ruby
         | 
| 104 104 | 
             
            ```
         | 
| @@ -110,7 +110,7 @@ dependency using a pessimistic version constraint covering the major and minor | |
| 110 110 | 
             
            values:
         | 
| 111 111 |  | 
| 112 112 | 
             
            ```ruby
         | 
| 113 | 
            -
            spec.add_dependency 'addressable', '~> 2. | 
| 113 | 
            +
            spec.add_dependency 'addressable', '~> 2.7'
         | 
| 114 114 | 
             
            ```
         | 
| 115 115 |  | 
| 116 116 | 
             
            If you need a specific bug fix, you can also specify minimum tiny versions
         | 
    
        data/addressable.gemspec
    ADDED
    
    | @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # -*- encoding: utf-8 -*-
         | 
| 2 | 
            +
            # stub: addressable 2.8.0 ruby lib
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            Gem::Specification.new do |s|
         | 
| 5 | 
            +
              s.name = "addressable".freeze
         | 
| 6 | 
            +
              s.version = "2.8.0"
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
         | 
| 9 | 
            +
              s.require_paths = ["lib".freeze]
         | 
| 10 | 
            +
              s.authors = ["Bob Aman".freeze]
         | 
| 11 | 
            +
              s.date = "2021-07-03"
         | 
| 12 | 
            +
              s.description = "Addressable is an alternative implementation to the URI implementation that is\npart of Ruby's standard library. It is flexible, offers heuristic parsing, and\nadditionally provides extensive support for IRIs and URI templates.\n".freeze
         | 
| 13 | 
            +
              s.email = "bob@sporkmonger.com".freeze
         | 
| 14 | 
            +
              s.extra_rdoc_files = ["README.md".freeze]
         | 
| 15 | 
            +
              s.files = ["CHANGELOG.md".freeze, "Gemfile".freeze, "LICENSE.txt".freeze, "README.md".freeze, "Rakefile".freeze, "addressable.gemspec".freeze, "data/unicode.data".freeze, "lib/addressable.rb".freeze, "lib/addressable/idna.rb".freeze, "lib/addressable/idna/native.rb".freeze, "lib/addressable/idna/pure.rb".freeze, "lib/addressable/template.rb".freeze, "lib/addressable/uri.rb".freeze, "lib/addressable/version.rb".freeze, "spec/addressable/idna_spec.rb".freeze, "spec/addressable/net_http_compat_spec.rb".freeze, "spec/addressable/security_spec.rb".freeze, "spec/addressable/template_spec.rb".freeze, "spec/addressable/uri_spec.rb".freeze, "spec/spec_helper.rb".freeze, "tasks/clobber.rake".freeze, "tasks/gem.rake".freeze, "tasks/git.rake".freeze, "tasks/metrics.rake".freeze, "tasks/profile.rake".freeze, "tasks/rspec.rake".freeze, "tasks/yard.rake".freeze]
         | 
| 16 | 
            +
              s.homepage = "https://github.com/sporkmonger/addressable".freeze
         | 
| 17 | 
            +
              s.licenses = ["Apache-2.0".freeze]
         | 
| 18 | 
            +
              s.rdoc_options = ["--main".freeze, "README.md".freeze]
         | 
| 19 | 
            +
              s.required_ruby_version = Gem::Requirement.new(">= 2.0".freeze)
         | 
| 20 | 
            +
              s.rubygems_version = "3.0.3".freeze
         | 
| 21 | 
            +
              s.summary = "URI Implementation".freeze
         | 
| 22 | 
            +
             | 
| 23 | 
            +
              if s.respond_to? :specification_version then
         | 
| 24 | 
            +
                s.specification_version = 4
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
         | 
| 27 | 
            +
                  s.add_runtime_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
         | 
| 28 | 
            +
                  s.add_development_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
         | 
| 29 | 
            +
                else
         | 
| 30 | 
            +
                  s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
         | 
| 31 | 
            +
                  s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              else
         | 
| 34 | 
            +
                s.add_dependency(%q<public_suffix>.freeze, [">= 2.0.2", "< 5.0"])
         | 
| 35 | 
            +
                s.add_dependency(%q<bundler>.freeze, [">= 1.0", "< 3.0"])
         | 
| 36 | 
            +
              end
         | 
| 37 | 
            +
            end
         | 
| @@ -178,44 +178,46 @@ module Addressable | |
| 178 178 | 
             
                  end
         | 
| 179 179 |  | 
| 180 180 | 
             
                  p = []
         | 
| 181 | 
            -
                  ucs4_to_utf8 = lambda do |ch|
         | 
| 182 | 
            -
                    if ch < 128
         | 
| 183 | 
            -
                      p << ch
         | 
| 184 | 
            -
                    elsif ch < 2048
         | 
| 185 | 
            -
                      p << (ch >> 6 | 192)
         | 
| 186 | 
            -
                      p << (ch & 63 | 128)
         | 
| 187 | 
            -
                    elsif ch < 0x10000
         | 
| 188 | 
            -
                      p << (ch >> 12 | 224)
         | 
| 189 | 
            -
                      p << (ch >> 6 & 63 | 128)
         | 
| 190 | 
            -
                      p << (ch & 63 | 128)
         | 
| 191 | 
            -
                    elsif ch < 0x200000
         | 
| 192 | 
            -
                      p << (ch >> 18 | 240)
         | 
| 193 | 
            -
                      p << (ch >> 12 & 63 | 128)
         | 
| 194 | 
            -
                      p << (ch >> 6 & 63 | 128)
         | 
| 195 | 
            -
                      p << (ch & 63 | 128)
         | 
| 196 | 
            -
                    elsif ch < 0x4000000
         | 
| 197 | 
            -
                      p << (ch >> 24 | 248)
         | 
| 198 | 
            -
                      p << (ch >> 18 & 63 | 128)
         | 
| 199 | 
            -
                      p << (ch >> 12 & 63 | 128)
         | 
| 200 | 
            -
                      p << (ch >> 6 & 63 | 128)
         | 
| 201 | 
            -
                      p << (ch & 63 | 128)
         | 
| 202 | 
            -
                    elsif ch < 0x80000000
         | 
| 203 | 
            -
                      p << (ch >> 30 | 252)
         | 
| 204 | 
            -
                      p << (ch >> 24 & 63 | 128)
         | 
| 205 | 
            -
                      p << (ch >> 18 & 63 | 128)
         | 
| 206 | 
            -
                      p << (ch >> 12 & 63 | 128)
         | 
| 207 | 
            -
                      p << (ch >> 6 & 63 | 128)
         | 
| 208 | 
            -
                      p << (ch & 63 | 128)
         | 
| 209 | 
            -
                    end
         | 
| 210 | 
            -
                  end
         | 
| 211 181 |  | 
| 212 | 
            -
                  ucs4_to_utf8 | 
| 213 | 
            -
                  ucs4_to_utf8 | 
| 182 | 
            +
                  ucs4_to_utf8(ch_one, p)
         | 
| 183 | 
            +
                  ucs4_to_utf8(ch_two, p)
         | 
| 214 184 |  | 
| 215 185 | 
             
                  return lookup_unicode_composition(p)
         | 
| 216 186 | 
             
                end
         | 
| 217 187 | 
             
                private_class_method :unicode_compose_pair
         | 
| 218 188 |  | 
| 189 | 
            +
                def self.ucs4_to_utf8(char, buffer)
         | 
| 190 | 
            +
                  if char < 128
         | 
| 191 | 
            +
                    buffer << char
         | 
| 192 | 
            +
                  elsif char < 2048
         | 
| 193 | 
            +
                    buffer << (char >> 6 | 192)
         | 
| 194 | 
            +
                    buffer << (char & 63 | 128)
         | 
| 195 | 
            +
                  elsif char < 0x10000
         | 
| 196 | 
            +
                    buffer << (char >> 12 | 224)
         | 
| 197 | 
            +
                    buffer << (char >> 6 & 63 | 128)
         | 
| 198 | 
            +
                    buffer << (char & 63 | 128)
         | 
| 199 | 
            +
                  elsif char < 0x200000
         | 
| 200 | 
            +
                    buffer << (char >> 18 | 240)
         | 
| 201 | 
            +
                    buffer << (char >> 12 & 63 | 128)
         | 
| 202 | 
            +
                    buffer << (char >> 6 & 63 | 128)
         | 
| 203 | 
            +
                    buffer << (char & 63 | 128)
         | 
| 204 | 
            +
                  elsif char < 0x4000000
         | 
| 205 | 
            +
                    buffer << (char >> 24 | 248)
         | 
| 206 | 
            +
                    buffer << (char >> 18 & 63 | 128)
         | 
| 207 | 
            +
                    buffer << (char >> 12 & 63 | 128)
         | 
| 208 | 
            +
                    buffer << (char >> 6 & 63 | 128)
         | 
| 209 | 
            +
                    buffer << (char & 63 | 128)
         | 
| 210 | 
            +
                  elsif char < 0x80000000
         | 
| 211 | 
            +
                    buffer << (char >> 30 | 252)
         | 
| 212 | 
            +
                    buffer << (char >> 24 & 63 | 128)
         | 
| 213 | 
            +
                    buffer << (char >> 18 & 63 | 128)
         | 
| 214 | 
            +
                    buffer << (char >> 12 & 63 | 128)
         | 
| 215 | 
            +
                    buffer << (char >> 6 & 63 | 128)
         | 
| 216 | 
            +
                    buffer << (char & 63 | 128)
         | 
| 217 | 
            +
                  end
         | 
| 218 | 
            +
                end
         | 
| 219 | 
            +
                private_class_method :ucs4_to_utf8
         | 
| 220 | 
            +
             | 
| 219 221 | 
             
                def self.unicode_sort_canonical(unpacked)
         | 
| 220 222 | 
             
                  unpacked = unpacked.dup
         | 
| 221 223 | 
             
                  i = 1
         | 
    
        data/lib/addressable/template.rb
    CHANGED
    
    | @@ -37,7 +37,7 @@ module Addressable | |
| 37 37 | 
             
                  Addressable::URI::CharacterClasses::DIGIT + '_'
         | 
| 38 38 |  | 
| 39 39 | 
             
                var_char =
         | 
| 40 | 
            -
                  "( | 
| 40 | 
            +
                  "(?>(?:[#{variable_char_class}]|%[a-fA-F0-9][a-fA-F0-9])+)"
         | 
| 41 41 | 
             
                RESERVED =
         | 
| 42 42 | 
             
                  "(?:[#{anything}]|%[a-fA-F0-9][a-fA-F0-9])"
         | 
| 43 43 | 
             
                UNRESERVED =
         | 
| @@ -412,7 +412,7 @@ module Addressable | |
| 412 412 | 
             
                #   match.captures
         | 
| 413 413 | 
             
                #   #=> ["a", ["b", "c"]]
         | 
| 414 414 | 
             
                def match(uri, processor=nil)
         | 
| 415 | 
            -
                  uri = Addressable::URI.parse(uri)
         | 
| 415 | 
            +
                  uri = Addressable::URI.parse(uri) unless uri.is_a?(Addressable::URI)
         | 
| 416 416 | 
             
                  mapping = {}
         | 
| 417 417 |  | 
| 418 418 | 
             
                  # First, we need to process the pattern, and extract the values.
         | 
| @@ -653,40 +653,6 @@ module Addressable | |
| 653 653 | 
             
                  self.to_regexp.named_captures
         | 
| 654 654 | 
             
                end
         | 
| 655 655 |  | 
| 656 | 
            -
                ##
         | 
| 657 | 
            -
                # Generates a route result for a given set of parameters.
         | 
| 658 | 
            -
                # Should only be used by rack-mount.
         | 
| 659 | 
            -
                #
         | 
| 660 | 
            -
                # @param params [Hash] The set of parameters used to expand the template.
         | 
| 661 | 
            -
                # @param recall [Hash] Default parameters used to expand the template.
         | 
| 662 | 
            -
                # @param options [Hash] Either a `:processor` or a `:parameterize` block.
         | 
| 663 | 
            -
                #
         | 
| 664 | 
            -
                # @api private
         | 
| 665 | 
            -
                def generate(params={}, recall={}, options={})
         | 
| 666 | 
            -
                  merged = recall.merge(params)
         | 
| 667 | 
            -
                  if options[:processor]
         | 
| 668 | 
            -
                    processor = options[:processor]
         | 
| 669 | 
            -
                  elsif options[:parameterize]
         | 
| 670 | 
            -
                    # TODO: This is sending me into fits trying to shoe-horn this into
         | 
| 671 | 
            -
                    # the existing API. I think I've got this backwards and processors
         | 
| 672 | 
            -
                    # should be a set of 4 optional blocks named :validate, :transform,
         | 
| 673 | 
            -
                    # :match, and :restore. Having to use a singleton here is a huge
         | 
| 674 | 
            -
                    # code smell.
         | 
| 675 | 
            -
                    processor = Object.new
         | 
| 676 | 
            -
                    class <<processor
         | 
| 677 | 
            -
                      attr_accessor :block
         | 
| 678 | 
            -
                      def transform(name, value)
         | 
| 679 | 
            -
                        block.call(name, value)
         | 
| 680 | 
            -
                      end
         | 
| 681 | 
            -
                    end
         | 
| 682 | 
            -
                    processor.block = options[:parameterize]
         | 
| 683 | 
            -
                  else
         | 
| 684 | 
            -
                    processor = nil
         | 
| 685 | 
            -
                  end
         | 
| 686 | 
            -
                  result = self.expand(merged, processor)
         | 
| 687 | 
            -
                  result.to_s if result
         | 
| 688 | 
            -
                end
         | 
| 689 | 
            -
             | 
| 690 656 | 
             
              private
         | 
| 691 657 | 
             
                def ordered_variable_defaults
         | 
| 692 658 | 
             
                  @ordered_variable_defaults ||= begin
         | 
| @@ -973,15 +939,35 @@ module Addressable | |
| 973 939 | 
             
                  end
         | 
| 974 940 | 
             
                end
         | 
| 975 941 |  | 
| 942 | 
            +
                ##
         | 
| 943 | 
            +
                # Generates the <tt>Regexp</tt> that parses a template pattern. Memoizes the
         | 
| 944 | 
            +
                # value if template processor not set (processors may not be deterministic)
         | 
| 945 | 
            +
                #
         | 
| 946 | 
            +
                # @param [String] pattern The URI template pattern.
         | 
| 947 | 
            +
                # @param [#match] processor The template processor to use.
         | 
| 948 | 
            +
                #
         | 
| 949 | 
            +
                # @return [Array, Regexp]
         | 
| 950 | 
            +
                #   An array of expansion variables nad a regular expression which may be
         | 
| 951 | 
            +
                #   used to parse a template pattern
         | 
| 952 | 
            +
                def parse_template_pattern(pattern, processor = nil)
         | 
| 953 | 
            +
                  if processor.nil? && pattern == @pattern
         | 
| 954 | 
            +
                    @cached_template_parse ||=
         | 
| 955 | 
            +
                      parse_new_template_pattern(pattern, processor)
         | 
| 956 | 
            +
                  else
         | 
| 957 | 
            +
                    parse_new_template_pattern(pattern, processor)
         | 
| 958 | 
            +
                  end
         | 
| 959 | 
            +
                end
         | 
| 960 | 
            +
             | 
| 976 961 | 
             
                ##
         | 
| 977 962 | 
             
                # Generates the <tt>Regexp</tt> that parses a template pattern.
         | 
| 978 963 | 
             
                #
         | 
| 979 964 | 
             
                # @param [String] pattern The URI template pattern.
         | 
| 980 965 | 
             
                # @param [#match] processor The template processor to use.
         | 
| 981 966 | 
             
                #
         | 
| 982 | 
            -
                # @return [Regexp]
         | 
| 983 | 
            -
                #    | 
| 984 | 
            -
                 | 
| 967 | 
            +
                # @return [Array, Regexp]
         | 
| 968 | 
            +
                #   An array of expansion variables nad a regular expression which may be
         | 
| 969 | 
            +
                #   used to parse a template pattern
         | 
| 970 | 
            +
                def parse_new_template_pattern(pattern, processor = nil)
         | 
| 985 971 | 
             
                  # Escape the pattern. The two gsubs restore the escaped curly braces
         | 
| 986 972 | 
             
                  # back to their original form. Basically, escape everything that isn't
         | 
| 987 973 | 
             
                  # within an expansion.
         | 
    
        data/lib/addressable/uri.rb
    CHANGED
    
    | @@ -48,12 +48,21 @@ module Addressable | |
| 48 48 | 
             
                  PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
         | 
| 49 49 | 
             
                  SCHEME = ALPHA + DIGIT + "\\-\\+\\."
         | 
| 50 50 | 
             
                  HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
         | 
| 51 | 
            -
                  AUTHORITY = PCHAR
         | 
| 51 | 
            +
                  AUTHORITY = PCHAR + "\\[\\:\\]"
         | 
| 52 52 | 
             
                  PATH = PCHAR + "\\/"
         | 
| 53 53 | 
             
                  QUERY = PCHAR + "\\/\\?"
         | 
| 54 54 | 
             
                  FRAGMENT = PCHAR + "\\/\\?"
         | 
| 55 55 | 
             
                end
         | 
| 56 56 |  | 
| 57 | 
            +
                module NormalizeCharacterClasses
         | 
| 58 | 
            +
                  HOST = /[^#{CharacterClasses::HOST}]/
         | 
| 59 | 
            +
                  UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
         | 
| 60 | 
            +
                  PCHAR = /[^#{CharacterClasses::PCHAR}]/
         | 
| 61 | 
            +
                  SCHEME = /[^#{CharacterClasses::SCHEME}]/
         | 
| 62 | 
            +
                  FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
         | 
| 63 | 
            +
                  QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 57 66 | 
             
                SLASH = '/'
         | 
| 58 67 | 
             
                EMPTY_STR = ''
         | 
| 59 68 |  | 
| @@ -73,7 +82,7 @@ module Addressable | |
| 73 82 | 
             
                  "wais" => 210,
         | 
| 74 83 | 
             
                  "ldap" => 389,
         | 
| 75 84 | 
             
                  "prospero" => 1525
         | 
| 76 | 
            -
                }
         | 
| 85 | 
            +
                }.freeze
         | 
| 77 86 |  | 
| 78 87 | 
             
                ##
         | 
| 79 88 | 
             
                # Returns a URI object based on the parsed string.
         | 
| @@ -421,7 +430,7 @@ module Addressable | |
| 421 430 | 
             
                end
         | 
| 422 431 |  | 
| 423 432 | 
             
                class << self
         | 
| 424 | 
            -
                  alias_method : | 
| 433 | 
            +
                  alias_method :escape_component, :encode_component
         | 
| 425 434 | 
             
                end
         | 
| 426 435 |  | 
| 427 436 | 
             
                ##
         | 
| @@ -463,7 +472,11 @@ module Addressable | |
| 463 472 | 
             
                  uri = uri.dup
         | 
| 464 473 | 
             
                  # Seriously, only use UTF-8. I'm really not kidding!
         | 
| 465 474 | 
             
                  uri.force_encoding("utf-8")
         | 
| 466 | 
            -
             | 
| 475 | 
            +
             | 
| 476 | 
            +
                  unless leave_encoded.empty?
         | 
| 477 | 
            +
                    leave_encoded = leave_encoded.dup.force_encoding("utf-8")
         | 
| 478 | 
            +
                  end
         | 
| 479 | 
            +
             | 
| 467 480 | 
             
                  result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
         | 
| 468 481 | 
             
                    c = sequence[1..3].to_i(16).chr
         | 
| 469 482 | 
             
                    c.force_encoding("utf-8")
         | 
| @@ -554,7 +567,11 @@ module Addressable | |
| 554 567 | 
             
                      end.flatten.join('|')})"
         | 
| 555 568 | 
             
                    end
         | 
| 556 569 |  | 
| 557 | 
            -
                    character_class =  | 
| 570 | 
            +
                    character_class = if leave_re
         | 
| 571 | 
            +
                                        /[^#{character_class}]#{leave_re}/
         | 
| 572 | 
            +
                                      else
         | 
| 573 | 
            +
                                        /[^#{character_class}]/
         | 
| 574 | 
            +
                                      end
         | 
| 558 575 | 
             
                  end
         | 
| 559 576 | 
             
                  # We can't perform regexps on invalid UTF sequences, but
         | 
| 560 577 | 
             
                  # here we need to, so switch to ASCII.
         | 
| @@ -878,7 +895,7 @@ module Addressable | |
| 878 895 | 
             
                    else
         | 
| 879 896 | 
             
                      Addressable::URI.normalize_component(
         | 
| 880 897 | 
             
                        self.scheme.strip.downcase,
         | 
| 881 | 
            -
                        Addressable::URI:: | 
| 898 | 
            +
                        Addressable::URI::NormalizeCharacterClasses::SCHEME
         | 
| 882 899 | 
             
                      )
         | 
| 883 900 | 
             
                    end
         | 
| 884 901 | 
             
                  end
         | 
| @@ -898,7 +915,7 @@ module Addressable | |
| 898 915 | 
             
                    new_scheme = new_scheme.to_str
         | 
| 899 916 | 
             
                  end
         | 
| 900 917 | 
             
                  if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
         | 
| 901 | 
            -
                    raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
         | 
| 918 | 
            +
                    raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'"
         | 
| 902 919 | 
             
                  end
         | 
| 903 920 | 
             
                  @scheme = new_scheme
         | 
| 904 921 | 
             
                  @scheme = nil if @scheme.to_s.strip.empty?
         | 
| @@ -933,7 +950,7 @@ module Addressable | |
| 933 950 | 
             
                    else
         | 
| 934 951 | 
             
                      Addressable::URI.normalize_component(
         | 
| 935 952 | 
             
                        self.user.strip,
         | 
| 936 | 
            -
                        Addressable::URI:: | 
| 953 | 
            +
                        Addressable::URI::NormalizeCharacterClasses::UNRESERVED
         | 
| 937 954 | 
             
                      )
         | 
| 938 955 | 
             
                    end
         | 
| 939 956 | 
             
                  end
         | 
| @@ -990,7 +1007,7 @@ module Addressable | |
| 990 1007 | 
             
                    else
         | 
| 991 1008 | 
             
                      Addressable::URI.normalize_component(
         | 
| 992 1009 | 
             
                        self.password.strip,
         | 
| 993 | 
            -
                        Addressable::URI:: | 
| 1010 | 
            +
                        Addressable::URI::NormalizeCharacterClasses::UNRESERVED
         | 
| 994 1011 | 
             
                      )
         | 
| 995 1012 | 
             
                    end
         | 
| 996 1013 | 
             
                  end
         | 
| @@ -1114,6 +1131,7 @@ module Addressable | |
| 1114 1131 | 
             
                # @return [String] The host component, normalized.
         | 
| 1115 1132 | 
             
                def normalized_host
         | 
| 1116 1133 | 
             
                  return nil unless self.host
         | 
| 1134 | 
            +
             | 
| 1117 1135 | 
             
                  @normalized_host ||= begin
         | 
| 1118 1136 | 
             
                    if !self.host.strip.empty?
         | 
| 1119 1137 | 
             
                      result = ::Addressable::IDNA.to_ascii(
         | 
| @@ -1125,14 +1143,17 @@ module Addressable | |
| 1125 1143 | 
             
                      end
         | 
| 1126 1144 | 
             
                      result = Addressable::URI.normalize_component(
         | 
| 1127 1145 | 
             
                        result,
         | 
| 1128 | 
            -
                         | 
| 1146 | 
            +
                        NormalizeCharacterClasses::HOST
         | 
| 1147 | 
            +
                      )
         | 
| 1129 1148 | 
             
                      result
         | 
| 1130 1149 | 
             
                    else
         | 
| 1131 1150 | 
             
                      EMPTY_STR.dup
         | 
| 1132 1151 | 
             
                    end
         | 
| 1133 1152 | 
             
                  end
         | 
| 1134 1153 | 
             
                  # All normalized values should be UTF-8
         | 
| 1135 | 
            -
                  @normalized_host | 
| 1154 | 
            +
                  if @normalized_host && !@normalized_host.empty?
         | 
| 1155 | 
            +
                    @normalized_host.force_encoding(Encoding::UTF_8)
         | 
| 1156 | 
            +
                  end
         | 
| 1136 1157 | 
             
                  @normalized_host
         | 
| 1137 1158 | 
             
                end
         | 
| 1138 1159 |  | 
| @@ -1537,7 +1558,7 @@ module Addressable | |
| 1537 1558 | 
             
                    result = path.strip.split(SLASH, -1).map do |segment|
         | 
| 1538 1559 | 
             
                      Addressable::URI.normalize_component(
         | 
| 1539 1560 | 
             
                        segment,
         | 
| 1540 | 
            -
                        Addressable::URI:: | 
| 1561 | 
            +
                        Addressable::URI::NormalizeCharacterClasses::PCHAR
         | 
| 1541 1562 | 
             
                      )
         | 
| 1542 1563 | 
             
                    end.join(SLASH)
         | 
| 1543 1564 |  | 
| @@ -1612,11 +1633,15 @@ module Addressable | |
| 1612 1633 | 
             
                    modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
         | 
| 1613 1634 | 
             
                    # Make sure possible key-value pair delimiters are escaped.
         | 
| 1614 1635 | 
             
                    modified_query_class.sub!("\\&", "").sub!("\\;", "")
         | 
| 1615 | 
            -
                    pairs = ( | 
| 1616 | 
            -
                    pairs.delete_if(&:empty?) if flags.include?(:compacted)
         | 
| 1636 | 
            +
                    pairs = (query || "").split("&", -1)
         | 
| 1637 | 
            +
                    pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted)
         | 
| 1617 1638 | 
             
                    pairs.sort! if flags.include?(:sorted)
         | 
| 1618 1639 | 
             
                    component = pairs.map do |pair|
         | 
| 1619 | 
            -
                      Addressable::URI.normalize_component( | 
| 1640 | 
            +
                      Addressable::URI.normalize_component(
         | 
| 1641 | 
            +
                        pair,
         | 
| 1642 | 
            +
                        Addressable::URI::NormalizeCharacterClasses::QUERY,
         | 
| 1643 | 
            +
                        "+"
         | 
| 1644 | 
            +
                      )
         | 
| 1620 1645 | 
             
                    end.join("&")
         | 
| 1621 1646 | 
             
                    component == "" ? nil : component
         | 
| 1622 1647 | 
             
                  end
         | 
| @@ -1675,11 +1700,13 @@ module Addressable | |
| 1675 1700 | 
             
                    # so it's best to make all changes in-place.
         | 
| 1676 1701 | 
             
                    pair[0] = URI.unencode_component(pair[0])
         | 
| 1677 1702 | 
             
                    if pair[1].respond_to?(:to_str)
         | 
| 1703 | 
            +
                      value = pair[1].to_str
         | 
| 1678 1704 | 
             
                      # I loathe the fact that I have to do this. Stupid HTML 4.01.
         | 
| 1679 1705 | 
             
                      # Treating '+' as a space was just an unbelievably bad idea.
         | 
| 1680 1706 | 
             
                      # There was nothing wrong with '%20'!
         | 
| 1681 1707 | 
             
                      # If it ain't broke, don't fix it!
         | 
| 1682 | 
            -
                       | 
| 1708 | 
            +
                      value = value.tr("+", " ") if ["http", "https", nil].include?(scheme)
         | 
| 1709 | 
            +
                      pair[1] = URI.unencode_component(value)
         | 
| 1683 1710 | 
             
                    end
         | 
| 1684 1711 | 
             
                    if return_type == Hash
         | 
| 1685 1712 | 
             
                      accu[pair[0]] = pair[1]
         | 
| @@ -1810,7 +1837,7 @@ module Addressable | |
| 1810 1837 | 
             
                  @normalized_fragment ||= begin
         | 
| 1811 1838 | 
             
                    component = Addressable::URI.normalize_component(
         | 
| 1812 1839 | 
             
                      self.fragment,
         | 
| 1813 | 
            -
                      Addressable::URI:: | 
| 1840 | 
            +
                      Addressable::URI::NormalizeCharacterClasses::FRAGMENT
         | 
| 1814 1841 | 
             
                    )
         | 
| 1815 1842 | 
             
                    component == "" ? nil : component
         | 
| 1816 1843 | 
             
                  end
         |