addressable 2.3.8 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of addressable might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/Gemfile +13 -13
- data/README.md +4 -4
- data/Rakefile +3 -3
- data/addressable.gemspec +10 -18
- data/lib/addressable.rb +2 -0
- data/lib/addressable/idna/pure.rb +2 -3
- data/lib/addressable/template.rb +131 -18
- data/lib/addressable/uri.rb +187 -124
- data/lib/addressable/version.rb +2 -2
- data/spec/addressable/idna_spec.rb +16 -0
- data/spec/addressable/rack_mount_compat_spec.rb +104 -0
- data/spec/addressable/security_spec.rb +57 -0
- data/spec/addressable/template_spec.rb +50 -3
- data/spec/addressable/uri_spec.rb +168 -9
- data/spec/spec_helper.rb +10 -1
- data/tasks/gem.rake +4 -5
- data/tasks/rspec.rake +6 -28
- metadata +11 -63
- data/website/index.html +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 77783a5c4c07f7a0862f0efaeb2619a278e32391
|
4
|
+
data.tar.gz: 8edbb65fa242ce03cf2403c192d2358da64a095b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3345827151e1d04e5c532cca1e8e63337b0ce9d9f0e276861ed6be95b114827f68d5f74e5bea857db1faaf7a70a928159436f5e51cbbecc4a6db64145d28ea2
|
7
|
+
data.tar.gz: 86e4d5c946972502c8ac79bf2582d0d6894db23fa2e285c69b8dae0d1e16fcad447e7f8f393eeb9e9891f0a30e0971f864449b6dfaf4104bee080cfb3dfe4af4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# Addressable 2.4.0
|
2
|
+
- support for 1.8.x dropped
|
3
|
+
- double quotes in a host now raises an error
|
4
|
+
- newlines in host will no longer get unescaped during normalization
|
5
|
+
- stricter handling of bogus scheme values
|
6
|
+
- stricter handling of encoded port values
|
7
|
+
- calling `require 'addressable'` will now load both the URI and Template files
|
8
|
+
- assigning to the `hostname` component with an `IPAddr` object is now supported
|
9
|
+
- assigning to the `origin` component is now supported
|
10
|
+
- fixed minor bug where an exception would be thrown for a missing ACE suffix
|
11
|
+
- better partial expansion of URI templates
|
12
|
+
|
1
13
|
# Addressable 2.3.8
|
2
14
|
- fix warnings
|
3
15
|
- update dependency gems
|
data/Gemfile
CHANGED
@@ -2,26 +2,26 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
+
gem 'rake', '~> 10.4', '>= 10.4.2'
|
6
|
+
|
7
|
+
group :test do
|
8
|
+
gem 'rspec', '~> 3.0'
|
9
|
+
gem 'rspec-its', '~> 1.1'
|
10
|
+
end
|
11
|
+
|
5
12
|
group :development do
|
6
|
-
gem '
|
13
|
+
gem 'launchy', '~> 2.4', '>= 2.4.3'
|
7
14
|
gem 'redcarpet', :platform => :mri_19
|
8
|
-
gem '
|
15
|
+
gem 'yard'
|
9
16
|
end
|
10
17
|
|
11
18
|
group :test, :development do
|
19
|
+
gem 'simplecov', :require => false
|
12
20
|
gem 'coveralls', :require => false, :platforms => [
|
13
21
|
:ruby_19, :ruby_20, :ruby_21, :rbx, :jruby
|
14
22
|
]
|
23
|
+
# Used to test compatibility.
|
24
|
+
gem 'rack-mount', git: 'https://github.com/sporkmonger/rack-mount.git', require: 'rack/mount'
|
15
25
|
end
|
16
26
|
|
17
|
-
gem 'idn', :platform => :
|
18
|
-
gem 'idn-ruby', :platform => :mri_19
|
19
|
-
|
20
|
-
platforms :ruby_18 do
|
21
|
-
gem 'mime-types', '~> 1.25'
|
22
|
-
gem 'rest-client', '~> 1.6.8'
|
23
|
-
end
|
24
|
-
|
25
|
-
platforms :rbx do
|
26
|
-
gem 'rubysl-openssl', '2.2.1'
|
27
|
-
end
|
27
|
+
gem 'idn-ruby', :platform => [:mri_19, :mri_20, :mri_21, :mri_22]
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Addressable
|
2
2
|
|
3
3
|
<dl>
|
4
|
-
<dt>Homepage</dt><dd><a href="
|
4
|
+
<dt>Homepage</dt><dd><a href="https://github.com/sporkmonger/addressable">github.com/sporkmonger/addressable</a></dd>
|
5
5
|
<dt>Author</dt><dd><a href="mailto:bob@sporkmonger.com">Bob Aman</a></dd>
|
6
6
|
<dt>Copyright</dt><dd>Copyright © 2006-2015 Bob Aman</dd>
|
7
7
|
<dt>License</dt><dd>Apache 2.0</dd>
|
@@ -68,7 +68,7 @@ template.expand({
|
|
68
68
|
})
|
69
69
|
#=> #<Addressable::URI:0xc9d95c URI:http://example.com/?foo=bar&color=red>
|
70
70
|
|
71
|
-
template = Addressable::Template.new("http://example.com/{?one,two,three}
|
71
|
+
template = Addressable::Template.new("http://example.com/{?one,two,three}")
|
72
72
|
template.partial_expand({"one" => "1", "three" => 3}).pattern
|
73
73
|
#=> "http://example.com/?one=1{&two}&three=3"
|
74
74
|
|
@@ -100,6 +100,6 @@ idn gem:
|
|
100
100
|
|
101
101
|
```console
|
102
102
|
$ sudo apt-get install idn # Debian/Ubuntu
|
103
|
-
$
|
104
|
-
$
|
103
|
+
$ brew install libidn # OS X
|
104
|
+
$ gem install idn-ruby
|
105
105
|
```
|
data/Rakefile
CHANGED
@@ -19,11 +19,11 @@ TEXT
|
|
19
19
|
|
20
20
|
PKG_FILES = FileList[
|
21
21
|
"lib/**/*", "spec/**/*", "vendor/**/*", "data/**/*",
|
22
|
-
"tasks/**/*",
|
22
|
+
"tasks/**/*",
|
23
23
|
"[A-Z]*", "Rakefile"
|
24
|
-
].exclude(/
|
24
|
+
].exclude(/pkg/).exclude(/database\.yml/).
|
25
|
+
exclude(/Gemfile\.lock/).exclude(/[_\.]git$/)
|
25
26
|
|
26
|
-
RCOV_ENABLED = (RUBY_PLATFORM != "java" && RUBY_VERSION =~ /^1\.8/)
|
27
27
|
task :default => "spec"
|
28
28
|
|
29
29
|
WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
|
data/addressable.gemspec
CHANGED
@@ -1,42 +1,34 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: addressable 2.
|
2
|
+
# stub: addressable 2.4.0 ruby lib
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "addressable"
|
6
|
-
s.version = "2.
|
6
|
+
s.version = "2.4.0"
|
7
7
|
|
8
8
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
9
9
|
s.require_paths = ["lib"]
|
10
10
|
s.authors = ["Bob Aman"]
|
11
|
-
s.date = "2015-
|
11
|
+
s.date = "2015-12-07"
|
12
12
|
s.description = "Addressable is a replacement for the URI implementation that is part of\nRuby's standard library. It more closely conforms to the relevant RFCs and\nadds support for IRIs and URI templates.\n"
|
13
13
|
s.email = "bob@sporkmonger.com"
|
14
14
|
s.extra_rdoc_files = ["README.md"]
|
15
|
-
s.files = ["CHANGELOG.md", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "addressable.gemspec", "data/unicode.data", "lib/addressable/idna.rb", "lib/addressable/idna/native.rb", "lib/addressable/idna/pure.rb", "lib/addressable/template.rb", "lib/addressable/uri.rb", "lib/addressable/version.rb", "spec/addressable/idna_spec.rb", "spec/addressable/net_http_compat_spec.rb", "spec/addressable/template_spec.rb", "spec/addressable/uri_spec.rb", "spec/spec_helper.rb", "tasks/clobber.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/metrics.rake", "tasks/rspec.rake", "tasks/yard.rake"
|
15
|
+
s.files = ["CHANGELOG.md", "Gemfile", "LICENSE.txt", "README.md", "Rakefile", "addressable.gemspec", "data/unicode.data", "lib/addressable.rb", "lib/addressable/idna.rb", "lib/addressable/idna/native.rb", "lib/addressable/idna/pure.rb", "lib/addressable/template.rb", "lib/addressable/uri.rb", "lib/addressable/version.rb", "spec/addressable/idna_spec.rb", "spec/addressable/net_http_compat_spec.rb", "spec/addressable/rack_mount_compat_spec.rb", "spec/addressable/security_spec.rb", "spec/addressable/template_spec.rb", "spec/addressable/uri_spec.rb", "spec/spec_helper.rb", "tasks/clobber.rake", "tasks/gem.rake", "tasks/git.rake", "tasks/metrics.rake", "tasks/rspec.rake", "tasks/yard.rake"]
|
16
16
|
s.homepage = "https://github.com/sporkmonger/addressable"
|
17
|
-
s.licenses = ["Apache
|
17
|
+
s.licenses = ["Apache-2.0"]
|
18
18
|
s.rdoc_options = ["--main", "README.md"]
|
19
|
-
s.
|
19
|
+
s.required_ruby_version = Gem::Requirement.new(">= 1.9.0")
|
20
|
+
s.rubygems_version = "2.5.0"
|
20
21
|
s.summary = "URI Implementation"
|
21
22
|
|
22
23
|
if s.respond_to? :specification_version then
|
23
24
|
s.specification_version = 4
|
24
25
|
|
25
26
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
26
|
-
s.add_development_dependency(%q<
|
27
|
-
s.add_development_dependency(%q<rspec>, ["~> 3.0"])
|
28
|
-
s.add_development_dependency(%q<rspec-its>, ["~> 1.1"])
|
29
|
-
s.add_development_dependency(%q<launchy>, [">= 2.4.3", "~> 2.4"])
|
27
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0"])
|
30
28
|
else
|
31
|
-
s.add_dependency(%q<
|
32
|
-
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
33
|
-
s.add_dependency(%q<rspec-its>, ["~> 1.1"])
|
34
|
-
s.add_dependency(%q<launchy>, [">= 2.4.3", "~> 2.4"])
|
29
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
35
30
|
end
|
36
31
|
else
|
37
|
-
s.add_dependency(%q<
|
38
|
-
s.add_dependency(%q<rspec>, ["~> 3.0"])
|
39
|
-
s.add_dependency(%q<rspec-its>, ["~> 1.1"])
|
40
|
-
s.add_dependency(%q<launchy>, [">= 2.4.3", "~> 2.4"])
|
32
|
+
s.add_dependency(%q<bundler>, ["~> 1.0"])
|
41
33
|
end
|
42
34
|
end
|
data/lib/addressable.rb
ADDED
@@ -93,7 +93,7 @@ module Addressable
|
|
93
93
|
input = input.to_s unless input.is_a?(String)
|
94
94
|
parts = input.split('.')
|
95
95
|
parts.map! do |part|
|
96
|
-
if part =~ /^#{ACE_PREFIX}/
|
96
|
+
if part =~ /^#{ACE_PREFIX}(.+)/
|
97
97
|
punycode_decode(part[/^#{ACE_PREFIX}(.+)/, 1])
|
98
98
|
else
|
99
99
|
part
|
@@ -175,7 +175,6 @@ module Addressable
|
|
175
175
|
|
176
176
|
p = []
|
177
177
|
ucs4_to_utf8 = lambda do |ch|
|
178
|
-
# For some reason, rcov likes to drop BUS errors here.
|
179
178
|
if ch < 128
|
180
179
|
p << ch
|
181
180
|
elsif ch < 2048
|
@@ -488,7 +487,7 @@ module Addressable
|
|
488
487
|
outlen.times do |j|
|
489
488
|
c = output[j]
|
490
489
|
unless c >= 0 && c <= 127
|
491
|
-
raise
|
490
|
+
raise StandardError, "Invalid output char."
|
492
491
|
end
|
493
492
|
unless PUNYCODE_PRINT_ASCII[c]
|
494
493
|
raise PunycodeBadInput, "Input is invalid."
|
data/lib/addressable/template.rb
CHANGED
@@ -234,7 +234,18 @@ module Addressable
|
|
234
234
|
if !pattern.respond_to?(:to_str)
|
235
235
|
raise TypeError, "Can't convert #{pattern.class} into String."
|
236
236
|
end
|
237
|
-
@pattern = pattern.to_str.freeze
|
237
|
+
@pattern = pattern.to_str.dup.freeze
|
238
|
+
end
|
239
|
+
|
240
|
+
##
|
241
|
+
# Freeze URI, initializing instance variables.
|
242
|
+
#
|
243
|
+
# @return [Addressable::URI] The frozen URI object.
|
244
|
+
def freeze
|
245
|
+
self.variables
|
246
|
+
self.variable_defaults
|
247
|
+
self.named_captures
|
248
|
+
super
|
238
249
|
end
|
239
250
|
|
240
251
|
##
|
@@ -592,6 +603,7 @@ module Addressable
|
|
592
603
|
@variables ||= ordered_variable_defaults.map { |var, val| var }.uniq
|
593
604
|
end
|
594
605
|
alias_method :keys, :variables
|
606
|
+
alias_method :names, :variables
|
595
607
|
|
596
608
|
##
|
597
609
|
# Returns a mapping of variables to their default values specified
|
@@ -603,9 +615,75 @@ module Addressable
|
|
603
615
|
Hash[*ordered_variable_defaults.reject { |k, v| v.nil? }.flatten]
|
604
616
|
end
|
605
617
|
|
618
|
+
##
|
619
|
+
# Coerces a template into a `Regexp` object. This regular expression will
|
620
|
+
# behave very similarly to the actual template, and should match the same
|
621
|
+
# URI values, but it cannot fully handle, for example, values that would
|
622
|
+
# extract to an `Array`.
|
623
|
+
#
|
624
|
+
# @return [Regexp] A regular expression which should match the template.
|
625
|
+
def to_regexp
|
626
|
+
_, source = parse_template_pattern(pattern)
|
627
|
+
Regexp.new(source)
|
628
|
+
end
|
629
|
+
|
630
|
+
##
|
631
|
+
# Returns the source of the coerced `Regexp`.
|
632
|
+
#
|
633
|
+
# @return [String] The source of the `Regexp` given by {#to_regexp}.
|
634
|
+
#
|
635
|
+
# @api private
|
636
|
+
def source
|
637
|
+
self.to_regexp.source
|
638
|
+
end
|
639
|
+
|
640
|
+
##
|
641
|
+
# Returns the named captures of the coerced `Regexp`.
|
642
|
+
#
|
643
|
+
# @return [Hash] The named captures of the `Regexp` given by {#to_regexp}.
|
644
|
+
#
|
645
|
+
# @api private
|
646
|
+
def named_captures
|
647
|
+
self.to_regexp.named_captures
|
648
|
+
end
|
649
|
+
|
650
|
+
##
|
651
|
+
# Generates a route result for a given set of parameters.
|
652
|
+
# Should only be used by rack-mount.
|
653
|
+
#
|
654
|
+
# @param params [Hash] The set of parameters used to expand the template.
|
655
|
+
# @param recall [Hash] Default parameters used to expand the template.
|
656
|
+
# @param options [Hash] Either a `:processor` or a `:parameterize` block.
|
657
|
+
#
|
658
|
+
# @api private
|
659
|
+
def generate(params={}, recall={}, options={})
|
660
|
+
merged = recall.merge(params)
|
661
|
+
if options[:processor]
|
662
|
+
processor = options[:processor]
|
663
|
+
elsif options[:parameterize]
|
664
|
+
# TODO: This is sending me into fits trying to shoe-horn this into
|
665
|
+
# the existing API. I think I've got this backwards and processors
|
666
|
+
# should be a set of 4 optional blocks named :validate, :transform,
|
667
|
+
# :match, and :restore. Having to use a singleton here is a huge
|
668
|
+
# code smell.
|
669
|
+
processor = Object.new
|
670
|
+
class <<processor
|
671
|
+
attr_accessor :block
|
672
|
+
def transform(name, value)
|
673
|
+
block.call(name, value)
|
674
|
+
end
|
675
|
+
end
|
676
|
+
processor.block = options[:parameterize]
|
677
|
+
else
|
678
|
+
processor = nil
|
679
|
+
end
|
680
|
+
result = self.expand(merged, processor)
|
681
|
+
result.to_s if result
|
682
|
+
end
|
683
|
+
|
606
684
|
private
|
607
685
|
def ordered_variable_defaults
|
608
|
-
@ordered_variable_defaults ||=
|
686
|
+
@ordered_variable_defaults ||= begin
|
609
687
|
expansions, _ = parse_template_pattern(pattern)
|
610
688
|
expansions.map do |capture|
|
611
689
|
_, _, varlist = *capture.match(EXPRESSION)
|
@@ -613,7 +691,7 @@ module Addressable
|
|
613
691
|
varspec[VARSPEC, 1]
|
614
692
|
end
|
615
693
|
end.flatten
|
616
|
-
|
694
|
+
end
|
617
695
|
end
|
618
696
|
|
619
697
|
|
@@ -642,19 +720,54 @@ module Addressable
|
|
642
720
|
# @return [String] The expanded expression
|
643
721
|
def transform_partial_capture(mapping, capture, processor = nil)
|
644
722
|
_, operator, varlist = *capture.match(EXPRESSION)
|
645
|
-
|
646
|
-
varlist.split(',')
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
723
|
+
|
724
|
+
vars = varlist.split(',')
|
725
|
+
|
726
|
+
if '?' == operator
|
727
|
+
# partial expansion of form style query variables sometimes requires a
|
728
|
+
# slight reordering of the variables to produce a valid url.
|
729
|
+
first_to_expand = vars.find { |varspec|
|
730
|
+
_, name, _ = *varspec.match(VARSPEC)
|
731
|
+
mapping.key? name
|
732
|
+
}
|
733
|
+
|
734
|
+
vars = [first_to_expand] + vars.reject {|varspec| varspec == first_to_expand} if first_to_expand
|
735
|
+
end
|
736
|
+
|
737
|
+
vars
|
738
|
+
.zip(operator_sequence(operator).take(vars.length))
|
739
|
+
.reduce("") do |acc, (varspec, op)|
|
740
|
+
_, name, _ = *varspec.match(VARSPEC)
|
741
|
+
|
742
|
+
acc << if mapping.key? name
|
743
|
+
transform_capture(mapping, "{#{op}#{varspec}}", processor)
|
744
|
+
else
|
745
|
+
"{#{op}#{varspec}}"
|
746
|
+
end
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
##
|
751
|
+
# Creates a lazy Enumerator of the operators that should be used to expand
|
752
|
+
# variables in a varlist starting with `operator`. For example, an operator
|
753
|
+
# `"?"` results in the sequence `"?","&","&"...`
|
754
|
+
#
|
755
|
+
# @param [String] operator from which to generate a sequence
|
756
|
+
#
|
757
|
+
# @return [Enumerator] sequence of operators
|
758
|
+
def operator_sequence(operator)
|
759
|
+
rest_operator = if "?" == operator
|
760
|
+
"&"
|
761
|
+
else
|
762
|
+
operator
|
763
|
+
end
|
764
|
+
head_operator = operator
|
765
|
+
|
766
|
+
Enumerator.new do |y|
|
767
|
+
y << head_operator.to_s
|
768
|
+
while true
|
769
|
+
y << rest_operator.to_s
|
655
770
|
end
|
656
|
-
is_first = false
|
657
|
-
acc
|
658
771
|
end
|
659
772
|
end
|
660
773
|
|
@@ -899,7 +1012,7 @@ module Addressable
|
|
899
1012
|
|
900
1013
|
result = processor && processor.respond_to?(:match) ? processor.match(name) : nil
|
901
1014
|
if result
|
902
|
-
"(
|
1015
|
+
"(?<#{name}>#{ result })"
|
903
1016
|
else
|
904
1017
|
group = case operator
|
905
1018
|
when '+'
|
@@ -920,9 +1033,9 @@ module Addressable
|
|
920
1033
|
"#{ UNRESERVED }*?"
|
921
1034
|
end
|
922
1035
|
if modifier == '*'
|
923
|
-
"(
|
1036
|
+
"(?<#{name}>#{group}(?:#{joiner}?#{group})*)?"
|
924
1037
|
else
|
925
|
-
"(
|
1038
|
+
"(?<#{name}>#{group})?"
|
926
1039
|
end
|
927
1040
|
end
|
928
1041
|
end.join("#{joiner}?")
|
data/lib/addressable/uri.rb
CHANGED
@@ -19,10 +19,6 @@
|
|
19
19
|
require "addressable/version"
|
20
20
|
require "addressable/idna"
|
21
21
|
|
22
|
-
if RUBY_VERSION =~ /^1.8/
|
23
|
-
warn('Support for Ruby 1.8.x in Addressable is deprecated.')
|
24
|
-
end
|
25
|
-
|
26
22
|
##
|
27
23
|
# Addressable is a library for processing links and URIs.
|
28
24
|
module Addressable
|
@@ -48,6 +44,7 @@ module Addressable
|
|
48
44
|
UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
|
49
45
|
PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
|
50
46
|
SCHEME = ALPHA + DIGIT + "\\-\\+\\."
|
47
|
+
HOST = ALPHA + DIGIT + "\\-\\.\\[\\:\\]"
|
51
48
|
AUTHORITY = PCHAR
|
52
49
|
PATH = PCHAR + "\\/"
|
53
50
|
QUERY = PCHAR + "\\/\\?"
|
@@ -724,9 +721,9 @@ module Addressable
|
|
724
721
|
).gsub("%20", "+")
|
725
722
|
]
|
726
723
|
end
|
727
|
-
return
|
724
|
+
return escaped_form_values.map do |(key, value)|
|
728
725
|
"#{key}=#{value}"
|
729
|
-
end
|
726
|
+
end.join("&")
|
730
727
|
end
|
731
728
|
|
732
729
|
##
|
@@ -835,7 +832,7 @@ module Addressable
|
|
835
832
|
#
|
836
833
|
# @return [String] The scheme component.
|
837
834
|
def scheme
|
838
|
-
return
|
835
|
+
return defined?(@scheme) ? @scheme : nil
|
839
836
|
end
|
840
837
|
|
841
838
|
##
|
@@ -843,7 +840,8 @@ module Addressable
|
|
843
840
|
#
|
844
841
|
# @return [String] The scheme component, normalized.
|
845
842
|
def normalized_scheme
|
846
|
-
self.scheme
|
843
|
+
return nil unless self.scheme
|
844
|
+
@normalized_scheme ||= begin
|
847
845
|
if self.scheme =~ /^\s*ssh\+svn\s*$/i
|
848
846
|
"svn+ssh"
|
849
847
|
else
|
@@ -852,7 +850,7 @@ module Addressable
|
|
852
850
|
Addressable::URI::CharacterClasses::SCHEME
|
853
851
|
)
|
854
852
|
end
|
855
|
-
end
|
853
|
+
end
|
856
854
|
end
|
857
855
|
|
858
856
|
##
|
@@ -865,16 +863,15 @@ module Addressable
|
|
865
863
|
elsif new_scheme
|
866
864
|
new_scheme = new_scheme.to_str
|
867
865
|
end
|
868
|
-
if new_scheme && new_scheme !~
|
869
|
-
raise InvalidURIError, "Invalid scheme format
|
866
|
+
if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
|
867
|
+
raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
|
870
868
|
end
|
871
869
|
@scheme = new_scheme
|
872
870
|
@scheme = nil if @scheme.to_s.strip.empty?
|
873
871
|
|
874
|
-
# Reset
|
875
|
-
|
876
|
-
|
877
|
-
@hash = nil
|
872
|
+
# Reset dependent values
|
873
|
+
remove_instance_variable(:@normalized_scheme) if defined?(@normalized_scheme)
|
874
|
+
remove_composite_values
|
878
875
|
|
879
876
|
# Ensure we haven't created an invalid URI
|
880
877
|
validate()
|
@@ -885,7 +882,7 @@ module Addressable
|
|
885
882
|
#
|
886
883
|
# @return [String] The user component.
|
887
884
|
def user
|
888
|
-
return
|
885
|
+
return defined?(@user) ? @user : nil
|
889
886
|
end
|
890
887
|
|
891
888
|
##
|
@@ -893,7 +890,9 @@ module Addressable
|
|
893
890
|
#
|
894
891
|
# @return [String] The user component, normalized.
|
895
892
|
def normalized_user
|
896
|
-
self.user
|
893
|
+
return nil unless self.user
|
894
|
+
return @normalized_user if defined?(@normalized_user)
|
895
|
+
@normalized_user ||= begin
|
897
896
|
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
898
897
|
(!self.password || self.password.strip.empty?)
|
899
898
|
nil
|
@@ -903,7 +902,7 @@ module Addressable
|
|
903
902
|
Addressable::URI::CharacterClasses::UNRESERVED
|
904
903
|
)
|
905
904
|
end
|
906
|
-
end
|
905
|
+
end
|
907
906
|
end
|
908
907
|
|
909
908
|
##
|
@@ -921,13 +920,12 @@ module Addressable
|
|
921
920
|
@user = EMPTY_STR if @user.nil?
|
922
921
|
end
|
923
922
|
|
924
|
-
# Reset
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
|
930
|
-
@hash = nil
|
923
|
+
# Reset dependent values
|
924
|
+
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
925
|
+
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
926
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
927
|
+
remove_instance_variable(:@normalized_user) if defined?(@normalized_user)
|
928
|
+
remove_composite_values
|
931
929
|
|
932
930
|
# Ensure we haven't created an invalid URI
|
933
931
|
validate()
|
@@ -938,7 +936,7 @@ module Addressable
|
|
938
936
|
#
|
939
937
|
# @return [String] The password component.
|
940
938
|
def password
|
941
|
-
return
|
939
|
+
return defined?(@password) ? @password : nil
|
942
940
|
end
|
943
941
|
|
944
942
|
##
|
@@ -946,7 +944,9 @@ module Addressable
|
|
946
944
|
#
|
947
945
|
# @return [String] The password component, normalized.
|
948
946
|
def normalized_password
|
949
|
-
self.password
|
947
|
+
return nil unless self.password
|
948
|
+
return @normalized_password if defined?(@normalized_password)
|
949
|
+
@normalized_password ||= begin
|
950
950
|
if self.normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
951
951
|
(!self.user || self.user.strip.empty?)
|
952
952
|
nil
|
@@ -956,7 +956,7 @@ module Addressable
|
|
956
956
|
Addressable::URI::CharacterClasses::UNRESERVED
|
957
957
|
)
|
958
958
|
end
|
959
|
-
end
|
959
|
+
end
|
960
960
|
end
|
961
961
|
|
962
962
|
##
|
@@ -976,13 +976,12 @@ module Addressable
|
|
976
976
|
@user = EMPTY_STR if @user.nil?
|
977
977
|
end
|
978
978
|
|
979
|
-
# Reset
|
980
|
-
|
981
|
-
|
982
|
-
|
983
|
-
|
984
|
-
|
985
|
-
@hash = nil
|
979
|
+
# Reset dependent values
|
980
|
+
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
981
|
+
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
982
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
983
|
+
remove_instance_variable(:@normalized_password) if defined?(@normalized_password)
|
984
|
+
remove_composite_values
|
986
985
|
|
987
986
|
# Ensure we haven't created an invalid URI
|
988
987
|
validate()
|
@@ -996,13 +995,13 @@ module Addressable
|
|
996
995
|
def userinfo
|
997
996
|
current_user = self.user
|
998
997
|
current_password = self.password
|
999
|
-
(current_user || current_password) && @userinfo ||=
|
998
|
+
(current_user || current_password) && @userinfo ||= begin
|
1000
999
|
if current_user && current_password
|
1001
1000
|
"#{current_user}:#{current_password}"
|
1002
1001
|
elsif current_user && !current_password
|
1003
1002
|
"#{current_user}"
|
1004
1003
|
end
|
1005
|
-
end
|
1004
|
+
end
|
1006
1005
|
end
|
1007
1006
|
|
1008
1007
|
##
|
@@ -1010,7 +1009,9 @@ module Addressable
|
|
1010
1009
|
#
|
1011
1010
|
# @return [String] The userinfo component, normalized.
|
1012
1011
|
def normalized_userinfo
|
1013
|
-
self.userinfo
|
1012
|
+
return nil unless self.userinfo
|
1013
|
+
return @normalized_userinfo if defined?(@normalized_userinfo)
|
1014
|
+
@normalized_userinfo ||= begin
|
1014
1015
|
current_user = self.normalized_user
|
1015
1016
|
current_password = self.normalized_password
|
1016
1017
|
if !current_user && !current_password
|
@@ -1020,7 +1021,7 @@ module Addressable
|
|
1020
1021
|
elsif current_user && !current_password
|
1021
1022
|
"#{current_user}"
|
1022
1023
|
end
|
1023
|
-
end
|
1024
|
+
end
|
1024
1025
|
end
|
1025
1026
|
|
1026
1027
|
##
|
@@ -1044,10 +1045,9 @@ module Addressable
|
|
1044
1045
|
self.password = new_password
|
1045
1046
|
self.user = new_user
|
1046
1047
|
|
1047
|
-
# Reset
|
1048
|
-
|
1049
|
-
|
1050
|
-
@hash = nil
|
1048
|
+
# Reset dependent values
|
1049
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
1050
|
+
remove_composite_values
|
1051
1051
|
|
1052
1052
|
# Ensure we haven't created an invalid URI
|
1053
1053
|
validate()
|
@@ -1058,7 +1058,7 @@ module Addressable
|
|
1058
1058
|
#
|
1059
1059
|
# @return [String] The host component.
|
1060
1060
|
def host
|
1061
|
-
return
|
1061
|
+
return defined?(@host) ? @host : nil
|
1062
1062
|
end
|
1063
1063
|
|
1064
1064
|
##
|
@@ -1066,7 +1066,8 @@ module Addressable
|
|
1066
1066
|
#
|
1067
1067
|
# @return [String] The host component, normalized.
|
1068
1068
|
def normalized_host
|
1069
|
-
self.host
|
1069
|
+
return nil unless self.host
|
1070
|
+
@normalized_host ||= begin
|
1070
1071
|
if !self.host.strip.empty?
|
1071
1072
|
result = ::Addressable::IDNA.to_ascii(
|
1072
1073
|
URI.unencode_component(self.host.strip.downcase)
|
@@ -1075,11 +1076,14 @@ module Addressable
|
|
1075
1076
|
# Single trailing dots are unnecessary.
|
1076
1077
|
result = result[0...-1]
|
1077
1078
|
end
|
1079
|
+
result = Addressable::URI.normalize_component(
|
1080
|
+
result,
|
1081
|
+
CharacterClasses::HOST)
|
1078
1082
|
result
|
1079
1083
|
else
|
1080
1084
|
EMPTY_STR
|
1081
1085
|
end
|
1082
|
-
end
|
1086
|
+
end
|
1083
1087
|
end
|
1084
1088
|
|
1085
1089
|
##
|
@@ -1094,17 +1098,16 @@ module Addressable
|
|
1094
1098
|
|
1095
1099
|
unreserved = CharacterClasses::UNRESERVED
|
1096
1100
|
sub_delims = CharacterClasses::SUB_DELIMS
|
1097
|
-
if
|
1101
|
+
if !@host.nil? && (@host =~ /[<>{}\/\?\#\@"[[:space:]]]/ ||
|
1098
1102
|
(@host[/^\[(.*)\]$/, 1] != nil && @host[/^\[(.*)\]$/, 1] !~
|
1099
1103
|
Regexp.new("^[#{unreserved}#{sub_delims}:]*$")))
|
1100
1104
|
raise InvalidURIError, "Invalid character in host: '#{@host.to_s}'"
|
1101
1105
|
end
|
1102
1106
|
|
1103
|
-
# Reset
|
1104
|
-
|
1105
|
-
|
1106
|
-
|
1107
|
-
@hash = nil
|
1107
|
+
# Reset dependent values
|
1108
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
1109
|
+
remove_instance_variable(:@normalized_host) if defined?(@normalized_host)
|
1110
|
+
remove_composite_values
|
1108
1111
|
|
1109
1112
|
# Ensure we haven't created an invalid URI
|
1110
1113
|
validate()
|
@@ -1130,7 +1133,10 @@ module Addressable
|
|
1130
1133
|
#
|
1131
1134
|
# @param [String, #to_str] new_hostname The new hostname for this URI.
|
1132
1135
|
def hostname=(new_hostname)
|
1133
|
-
if new_hostname &&
|
1136
|
+
if new_hostname &&
|
1137
|
+
(new_hostname.respond_to?(:ipv4?) || new_hostname.respond_to?(:ipv6?))
|
1138
|
+
new_hostname = new_hostname.to_s
|
1139
|
+
elsif new_hostname && !new_hostname.respond_to?(:to_str)
|
1134
1140
|
raise TypeError, "Can't convert #{new_hostname.class} into String."
|
1135
1141
|
end
|
1136
1142
|
v = new_hostname ? new_hostname.to_str : nil
|
@@ -1144,7 +1150,7 @@ module Addressable
|
|
1144
1150
|
#
|
1145
1151
|
# @return [String] The authority component.
|
1146
1152
|
def authority
|
1147
|
-
self.host && @authority ||=
|
1153
|
+
self.host && @authority ||= begin
|
1148
1154
|
authority = ""
|
1149
1155
|
if self.userinfo != nil
|
1150
1156
|
authority << "#{self.userinfo}@"
|
@@ -1154,7 +1160,7 @@ module Addressable
|
|
1154
1160
|
authority << ":#{self.port}"
|
1155
1161
|
end
|
1156
1162
|
authority
|
1157
|
-
end
|
1163
|
+
end
|
1158
1164
|
end
|
1159
1165
|
|
1160
1166
|
##
|
@@ -1162,7 +1168,8 @@ module Addressable
|
|
1162
1168
|
#
|
1163
1169
|
# @return [String] The authority component, normalized.
|
1164
1170
|
def normalized_authority
|
1165
|
-
self.authority
|
1171
|
+
return nil unless self.authority
|
1172
|
+
@normalized_authority ||= begin
|
1166
1173
|
authority = ""
|
1167
1174
|
if self.normalized_userinfo != nil
|
1168
1175
|
authority << "#{self.normalized_userinfo}@"
|
@@ -1172,7 +1179,7 @@ module Addressable
|
|
1172
1179
|
authority << ":#{self.normalized_port}"
|
1173
1180
|
end
|
1174
1181
|
authority
|
1175
|
-
end
|
1182
|
+
end
|
1176
1183
|
end
|
1177
1184
|
|
1178
1185
|
##
|
@@ -1205,11 +1212,10 @@ module Addressable
|
|
1205
1212
|
self.host = defined?(new_host) ? new_host : nil
|
1206
1213
|
self.port = defined?(new_port) ? new_port : nil
|
1207
1214
|
|
1208
|
-
# Reset
|
1209
|
-
|
1210
|
-
|
1211
|
-
|
1212
|
-
@hash = nil
|
1215
|
+
# Reset dependent values
|
1216
|
+
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
1217
|
+
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
1218
|
+
remove_composite_values
|
1213
1219
|
|
1214
1220
|
# Ensure we haven't created an invalid URI
|
1215
1221
|
validate()
|
@@ -1221,18 +1227,55 @@ module Addressable
|
|
1221
1227
|
#
|
1222
1228
|
# @return [String] The serialized origin.
|
1223
1229
|
def origin
|
1224
|
-
|
1230
|
+
if self.scheme && self.authority
|
1225
1231
|
if self.normalized_port
|
1226
|
-
|
1227
|
-
|
1228
|
-
":#{self.normalized_port}"
|
1229
|
-
)
|
1232
|
+
"#{self.normalized_scheme}://#{self.normalized_host}" +
|
1233
|
+
":#{self.normalized_port}"
|
1230
1234
|
else
|
1231
1235
|
"#{self.normalized_scheme}://#{self.normalized_host}"
|
1232
1236
|
end
|
1233
1237
|
else
|
1234
1238
|
"null"
|
1235
|
-
end
|
1239
|
+
end
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
##
|
1243
|
+
# Sets the origin for this URI, serialized to ASCII, as per
|
1244
|
+
# RFC 6454, section 6.2. This assignment will reset the `userinfo`
|
1245
|
+
# component.
|
1246
|
+
#
|
1247
|
+
# @param [String, #to_str] new_origin The new origin component.
|
1248
|
+
def origin=(new_origin)
|
1249
|
+
if new_origin
|
1250
|
+
if !new_origin.respond_to?(:to_str)
|
1251
|
+
raise TypeError, "Can't convert #{new_origin.class} into String."
|
1252
|
+
end
|
1253
|
+
new_origin = new_origin.to_str
|
1254
|
+
new_scheme = new_origin[/^([^:\/?#]+):\/\//, 1]
|
1255
|
+
unless new_scheme
|
1256
|
+
raise InvalidURIError, 'An origin cannot omit the scheme.'
|
1257
|
+
end
|
1258
|
+
new_host = new_origin[/:\/\/([^\/?#:]+)/, 1]
|
1259
|
+
unless new_host
|
1260
|
+
raise InvalidURIError, 'An origin cannot omit the host.'
|
1261
|
+
end
|
1262
|
+
new_port = new_origin[/:([^:@\[\]\/]*?)$/, 1]
|
1263
|
+
end
|
1264
|
+
|
1265
|
+
self.scheme = defined?(new_scheme) ? new_scheme : nil
|
1266
|
+
self.host = defined?(new_host) ? new_host : nil
|
1267
|
+
self.port = defined?(new_port) ? new_port : nil
|
1268
|
+
self.userinfo = nil
|
1269
|
+
|
1270
|
+
# Reset dependent values
|
1271
|
+
remove_instance_variable(:@userinfo) if defined?(@userinfo)
|
1272
|
+
remove_instance_variable(:@normalized_userinfo) if defined?(@normalized_userinfo)
|
1273
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
1274
|
+
remove_instance_variable(:@normalized_authority) if defined?(@normalized_authority)
|
1275
|
+
remove_composite_values
|
1276
|
+
|
1277
|
+
# Ensure we haven't created an invalid URI
|
1278
|
+
validate()
|
1236
1279
|
end
|
1237
1280
|
|
1238
1281
|
# Returns an array of known ip-based schemes. These schemes typically
|
@@ -1256,7 +1299,7 @@ module Addressable
|
|
1256
1299
|
#
|
1257
1300
|
# @return [Integer] The port component.
|
1258
1301
|
def port
|
1259
|
-
return
|
1302
|
+
return defined?(@port) ? @port : nil
|
1260
1303
|
end
|
1261
1304
|
|
1262
1305
|
##
|
@@ -1264,10 +1307,14 @@ module Addressable
|
|
1264
1307
|
#
|
1265
1308
|
# @return [Integer] The port component, normalized.
|
1266
1309
|
def normalized_port
|
1267
|
-
|
1268
|
-
|
1269
|
-
|
1270
|
-
self.port
|
1310
|
+
return nil unless self.port
|
1311
|
+
return @normalized_port if defined?(@normalized_port)
|
1312
|
+
@normalized_port ||= begin
|
1313
|
+
if URI.port_mapping[self.normalized_scheme] == self.port
|
1314
|
+
nil
|
1315
|
+
else
|
1316
|
+
self.port
|
1317
|
+
end
|
1271
1318
|
end
|
1272
1319
|
end
|
1273
1320
|
|
@@ -1279,6 +1326,11 @@ module Addressable
|
|
1279
1326
|
if new_port != nil && new_port.respond_to?(:to_str)
|
1280
1327
|
new_port = Addressable::URI.unencode_component(new_port.to_str)
|
1281
1328
|
end
|
1329
|
+
|
1330
|
+
if new_port.respond_to?(:valid_encoding?) && !new_port.valid_encoding?
|
1331
|
+
raise InvalidURIError, "Invalid encoding in port"
|
1332
|
+
end
|
1333
|
+
|
1282
1334
|
if new_port != nil && !(new_port.to_s =~ /^\d+$/)
|
1283
1335
|
raise InvalidURIError,
|
1284
1336
|
"Invalid port number: #{new_port.inspect}"
|
@@ -1287,11 +1339,10 @@ module Addressable
|
|
1287
1339
|
@port = new_port.to_s.to_i
|
1288
1340
|
@port = nil if @port == 0
|
1289
1341
|
|
1290
|
-
# Reset
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
@hash = nil
|
1342
|
+
# Reset dependent values
|
1343
|
+
remove_instance_variable(:@authority) if defined?(@authority)
|
1344
|
+
remove_instance_variable(:@normalized_port) if defined?(@normalized_port)
|
1345
|
+
remove_composite_values
|
1295
1346
|
|
1296
1347
|
# Ensure we haven't created an invalid URI
|
1297
1348
|
validate()
|
@@ -1331,12 +1382,12 @@ module Addressable
|
|
1331
1382
|
#
|
1332
1383
|
# @return [String] The components that identify a site.
|
1333
1384
|
def site
|
1334
|
-
(self.scheme || self.authority) && @site ||=
|
1385
|
+
(self.scheme || self.authority) && @site ||= begin
|
1335
1386
|
site_string = ""
|
1336
1387
|
site_string << "#{self.scheme}:" if self.scheme != nil
|
1337
1388
|
site_string << "//#{self.authority}" if self.authority != nil
|
1338
1389
|
site_string
|
1339
|
-
end
|
1390
|
+
end
|
1340
1391
|
end
|
1341
1392
|
|
1342
1393
|
##
|
@@ -1349,7 +1400,8 @@ module Addressable
|
|
1349
1400
|
#
|
1350
1401
|
# @return [String] The normalized components that identify a site.
|
1351
1402
|
def normalized_site
|
1352
|
-
self.site
|
1403
|
+
return nil unless self.site
|
1404
|
+
@normalized_site ||= begin
|
1353
1405
|
site_string = ""
|
1354
1406
|
if self.normalized_scheme != nil
|
1355
1407
|
site_string << "#{self.normalized_scheme}:"
|
@@ -1358,7 +1410,7 @@ module Addressable
|
|
1358
1410
|
site_string << "//#{self.normalized_authority}"
|
1359
1411
|
end
|
1360
1412
|
site_string
|
1361
|
-
end
|
1413
|
+
end
|
1362
1414
|
end
|
1363
1415
|
|
1364
1416
|
##
|
@@ -1388,7 +1440,7 @@ module Addressable
|
|
1388
1440
|
#
|
1389
1441
|
# @return [String] The path component.
|
1390
1442
|
def path
|
1391
|
-
return
|
1443
|
+
return defined?(@path) ? @path : EMPTY_STR
|
1392
1444
|
end
|
1393
1445
|
|
1394
1446
|
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
@@ -1397,7 +1449,7 @@ module Addressable
|
|
1397
1449
|
#
|
1398
1450
|
# @return [String] The path component, normalized.
|
1399
1451
|
def normalized_path
|
1400
|
-
@normalized_path ||=
|
1452
|
+
@normalized_path ||= begin
|
1401
1453
|
path = self.path.to_s
|
1402
1454
|
if self.scheme == nil && path =~ NORMPATH
|
1403
1455
|
# Relative paths with colons in the first segment are ambiguous.
|
@@ -1405,12 +1457,12 @@ module Addressable
|
|
1405
1457
|
end
|
1406
1458
|
# String#split(delimeter, -1) uses the more strict splitting behavior
|
1407
1459
|
# found by default in Python.
|
1408
|
-
result =
|
1460
|
+
result = path.strip.split(SLASH, -1).map do |segment|
|
1409
1461
|
Addressable::URI.normalize_component(
|
1410
1462
|
segment,
|
1411
1463
|
Addressable::URI::CharacterClasses::PCHAR
|
1412
1464
|
)
|
1413
|
-
end
|
1465
|
+
end.join(SLASH)
|
1414
1466
|
|
1415
1467
|
result = URI.normalize_path(result)
|
1416
1468
|
if result.empty? &&
|
@@ -1418,7 +1470,7 @@ module Addressable
|
|
1418
1470
|
result = SLASH
|
1419
1471
|
end
|
1420
1472
|
result
|
1421
|
-
end
|
1473
|
+
end
|
1422
1474
|
end
|
1423
1475
|
|
1424
1476
|
##
|
@@ -1434,10 +1486,9 @@ module Addressable
|
|
1434
1486
|
@path = "/#{@path}"
|
1435
1487
|
end
|
1436
1488
|
|
1437
|
-
# Reset
|
1438
|
-
|
1439
|
-
|
1440
|
-
@hash = nil
|
1489
|
+
# Reset dependent values
|
1490
|
+
remove_instance_variable(:@normalized_path) if defined?(@normalized_path)
|
1491
|
+
remove_composite_values
|
1441
1492
|
end
|
1442
1493
|
|
1443
1494
|
##
|
@@ -1464,7 +1515,7 @@ module Addressable
|
|
1464
1515
|
#
|
1465
1516
|
# @return [String] The query component.
|
1466
1517
|
def query
|
1467
|
-
return
|
1518
|
+
return defined?(@query) ? @query : nil
|
1468
1519
|
end
|
1469
1520
|
|
1470
1521
|
##
|
@@ -1472,15 +1523,19 @@ module Addressable
|
|
1472
1523
|
#
|
1473
1524
|
# @return [String] The query component, normalized.
|
1474
1525
|
def normalized_query(*flags)
|
1475
|
-
|
1476
|
-
|
1477
|
-
|
1478
|
-
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1526
|
+
return nil unless self.query
|
1527
|
+
return @normalized_query if defined?(@normalized_query)
|
1528
|
+
@normalized_query ||= begin
|
1529
|
+
modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
|
1530
|
+
# Make sure possible key-value pair delimiters are escaped.
|
1531
|
+
modified_query_class.sub!("\\&", "").sub!("\\;", "")
|
1532
|
+
pairs = (self.query || "").split("&", -1)
|
1533
|
+
pairs.sort! if flags.include?(:sorted)
|
1534
|
+
component = pairs.map do |pair|
|
1535
|
+
Addressable::URI.normalize_component(pair, modified_query_class, "+")
|
1536
|
+
end.join("&")
|
1537
|
+
component == "" ? nil : component
|
1538
|
+
end
|
1484
1539
|
end
|
1485
1540
|
|
1486
1541
|
##
|
@@ -1493,10 +1548,9 @@ module Addressable
|
|
1493
1548
|
end
|
1494
1549
|
@query = new_query ? new_query.to_str : nil
|
1495
1550
|
|
1496
|
-
# Reset
|
1497
|
-
|
1498
|
-
|
1499
|
-
@hash = nil
|
1551
|
+
# Reset dependent values
|
1552
|
+
remove_instance_variable(:@normalized_query) if defined?(@normalized_query)
|
1553
|
+
remove_composite_values
|
1500
1554
|
end
|
1501
1555
|
|
1502
1556
|
##
|
@@ -1525,9 +1579,9 @@ module Addressable
|
|
1525
1579
|
raise ArgumentError, "Invalid return type. Must be Hash or Array."
|
1526
1580
|
end
|
1527
1581
|
return nil if self.query == nil
|
1528
|
-
split_query =
|
1582
|
+
split_query = self.query.split("&").map do |pair|
|
1529
1583
|
pair.split("=", 2) if pair && !pair.empty?
|
1530
|
-
end
|
1584
|
+
end.compact
|
1531
1585
|
return split_query.inject(empty_accumulator.dup) do |accu, pair|
|
1532
1586
|
# I'd rather use key/value identifiers instead of array lookups,
|
1533
1587
|
# but in this case I really want to maintain the exact pair structure,
|
@@ -1647,9 +1701,8 @@ module Addressable
|
|
1647
1701
|
self.path = path_component
|
1648
1702
|
self.query = query_component
|
1649
1703
|
|
1650
|
-
# Reset
|
1651
|
-
|
1652
|
-
@hash = nil
|
1704
|
+
# Reset dependent values
|
1705
|
+
remove_composite_values
|
1653
1706
|
end
|
1654
1707
|
|
1655
1708
|
##
|
@@ -1657,7 +1710,7 @@ module Addressable
|
|
1657
1710
|
#
|
1658
1711
|
# @return [String] The fragment component.
|
1659
1712
|
def fragment
|
1660
|
-
return
|
1713
|
+
return defined?(@fragment) ? @fragment : nil
|
1661
1714
|
end
|
1662
1715
|
|
1663
1716
|
##
|
@@ -1665,13 +1718,15 @@ module Addressable
|
|
1665
1718
|
#
|
1666
1719
|
# @return [String] The fragment component, normalized.
|
1667
1720
|
def normalized_fragment
|
1668
|
-
self.fragment
|
1721
|
+
return nil unless self.fragment
|
1722
|
+
return @normalized_fragment if defined?(@normalized_fragment)
|
1723
|
+
@normalized_fragment ||= begin
|
1669
1724
|
component = Addressable::URI.normalize_component(
|
1670
1725
|
self.fragment,
|
1671
1726
|
Addressable::URI::CharacterClasses::FRAGMENT
|
1672
1727
|
)
|
1673
1728
|
component == "" ? nil : component
|
1674
|
-
end
|
1729
|
+
end
|
1675
1730
|
end
|
1676
1731
|
|
1677
1732
|
##
|
@@ -1684,10 +1739,9 @@ module Addressable
|
|
1684
1739
|
end
|
1685
1740
|
@fragment = new_fragment ? new_fragment.to_str : nil
|
1686
1741
|
|
1687
|
-
# Reset
|
1688
|
-
|
1689
|
-
|
1690
|
-
@hash = nil
|
1742
|
+
# Reset dependent values
|
1743
|
+
remove_instance_variable(:@normalized_fragment) if defined?(@normalized_fragment)
|
1744
|
+
remove_composite_values
|
1691
1745
|
|
1692
1746
|
# Ensure we haven't created an invalid URI
|
1693
1747
|
validate()
|
@@ -2108,7 +2162,7 @@ module Addressable
|
|
2108
2162
|
#
|
2109
2163
|
# @return [Integer] A hash of the URI.
|
2110
2164
|
def hash
|
2111
|
-
|
2165
|
+
@hash ||= self.to_s.hash * -1
|
2112
2166
|
end
|
2113
2167
|
|
2114
2168
|
##
|
@@ -2191,7 +2245,7 @@ module Addressable
|
|
2191
2245
|
raise InvalidURIError,
|
2192
2246
|
"Cannot assemble URI string with ambiguous path: '#{self.path}'"
|
2193
2247
|
end
|
2194
|
-
@uri_string ||=
|
2248
|
+
@uri_string ||= begin
|
2195
2249
|
uri_string = ""
|
2196
2250
|
uri_string << "#{self.scheme}:" if self.scheme != nil
|
2197
2251
|
uri_string << "//#{self.authority}" if self.authority != nil
|
@@ -2202,7 +2256,7 @@ module Addressable
|
|
2202
2256
|
uri_string.force_encoding(Encoding::UTF_8)
|
2203
2257
|
end
|
2204
2258
|
uri_string
|
2205
|
-
end
|
2259
|
+
end
|
2206
2260
|
end
|
2207
2261
|
|
2208
2262
|
##
|
@@ -2251,7 +2305,7 @@ module Addressable
|
|
2251
2305
|
return nil
|
2252
2306
|
end
|
2253
2307
|
|
2254
|
-
|
2308
|
+
protected
|
2255
2309
|
SELF_REF = '.'
|
2256
2310
|
PARENT = '..'
|
2257
2311
|
|
@@ -2328,9 +2382,9 @@ module Addressable
|
|
2328
2382
|
#
|
2329
2383
|
# @return [Addressable::URI] <code>self</code>.
|
2330
2384
|
def replace_self(uri)
|
2331
|
-
# Reset
|
2385
|
+
# Reset dependent values
|
2332
2386
|
instance_variables.each do |var|
|
2333
|
-
|
2387
|
+
remove_instance_variable(var) if instance_variable_defined?(var)
|
2334
2388
|
end
|
2335
2389
|
|
2336
2390
|
@scheme = uri.scheme
|
@@ -2345,7 +2399,7 @@ module Addressable
|
|
2345
2399
|
end
|
2346
2400
|
|
2347
2401
|
##
|
2348
|
-
# Splits path string with "/"(slash).
|
2402
|
+
# Splits path string with "/" (slash).
|
2349
2403
|
# It is considered that there is empty string after last slash when
|
2350
2404
|
# path ends with slash.
|
2351
2405
|
#
|
@@ -2357,5 +2411,14 @@ module Addressable
|
|
2357
2411
|
splitted << EMPTY_STR if path.end_with? SLASH
|
2358
2412
|
splitted
|
2359
2413
|
end
|
2414
|
+
|
2415
|
+
##
|
2416
|
+
# Resets composite values for the entire URI
|
2417
|
+
#
|
2418
|
+
# @api private
|
2419
|
+
def remove_composite_values
|
2420
|
+
remove_instance_variable(:@uri_string) if defined?(@uri_string)
|
2421
|
+
remove_instance_variable(:@hash) if defined?(@hash)
|
2422
|
+
end
|
2360
2423
|
end
|
2361
2424
|
end
|