addressable 2.2.4 → 2.2.5
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.
- data/CHANGELOG +25 -19
- data/LICENSE +202 -20
- data/README.md +76 -0
- data/lib/addressable/idna.rb +24 -4870
- data/lib/addressable/idna/native.rb +43 -0
- data/lib/addressable/idna/pure.rb +4886 -0
- data/lib/addressable/template.rb +40 -42
- data/lib/addressable/uri.rb +157 -187
- data/lib/addressable/version.rb +13 -19
- data/spec/addressable/idna_spec.rb +43 -22
- data/spec/addressable/template_spec.rb +11 -20
- data/spec/addressable/uri_spec.rb +92 -30
- data/tasks/gem.rake +2 -2
- data/tasks/rdoc.rake +1 -1
- data/tasks/spec.rake +5 -3
- data/tasks/yard.rake +4 -4
- metadata +11 -9
- data/README +0 -60
data/lib/addressable/template.rb
CHANGED
@@ -1,27 +1,21 @@
|
|
1
1
|
# encoding:utf-8
|
2
2
|
#--
|
3
|
-
#
|
3
|
+
# Copyright (C) 2006-2011 Bob Aman
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
# the following conditions:
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
12
8
|
#
|
13
|
-
#
|
14
|
-
# included in all copies or substantial portions of the Software.
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
15
10
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
23
16
|
#++
|
24
17
|
|
18
|
+
|
25
19
|
require "addressable/version"
|
26
20
|
require "addressable/uri"
|
27
21
|
|
@@ -63,7 +57,7 @@ module Addressable
|
|
63
57
|
#
|
64
58
|
# @param [Addressable::URI] uri
|
65
59
|
# The URI that the template was matched against.
|
66
|
-
def initialize(uri, template, mapping)
|
60
|
+
def initialize(uri, template, mapping)
|
67
61
|
@uri = uri.dup.freeze
|
68
62
|
@template = template
|
69
63
|
@mapping = mapping.dup.freeze
|
@@ -154,20 +148,22 @@ module Addressable
|
|
154
148
|
#
|
155
149
|
# @param [#restore, #match] processor
|
156
150
|
# A template processor object may optionally be supplied.
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
# two parameters: [String] name and [String] value
|
161
|
-
# method should reverse any transformations that
|
162
|
-
# value to ensure a valid URI.
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
151
|
+
#
|
152
|
+
# The object should respond to either the <tt>restore</tt> or
|
153
|
+
# <tt>match</tt> messages or both. The <tt>restore</tt> method should
|
154
|
+
# take two parameters: `[String] name` and `[String] value`.
|
155
|
+
# The <tt>restore</tt> method should reverse any transformations that
|
156
|
+
# have been performed on the value to ensure a valid URI.
|
157
|
+
# The <tt>match</tt> method should take a single
|
158
|
+
# parameter: `[String] name`. The <tt>match</tt> method should return
|
159
|
+
# a <tt>String</tt> containing a regular expression capture group for
|
160
|
+
# matching on that particular variable. The default value is `".*?"`.
|
161
|
+
# The <tt>match</tt> method has no effect on multivariate operator
|
162
|
+
# expansions.
|
167
163
|
#
|
168
164
|
# @return [Hash, NilClass]
|
169
|
-
#
|
170
|
-
#
|
165
|
+
# The <tt>Hash</tt> mapping that was extracted from the URI, or
|
166
|
+
# <tt>nil</tt> if the URI didn't match the template.
|
171
167
|
#
|
172
168
|
# @example
|
173
169
|
# class ExampleProcessor
|
@@ -214,20 +210,22 @@ module Addressable
|
|
214
210
|
#
|
215
211
|
# @param [#restore, #match] processor
|
216
212
|
# A template processor object may optionally be supplied.
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
220
|
-
# two parameters: [String] name and [String] value
|
221
|
-
# method should reverse any transformations that
|
222
|
-
# value to ensure a valid URI.
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
213
|
+
#
|
214
|
+
# The object should respond to either the <tt>restore</tt> or
|
215
|
+
# <tt>match</tt> messages or both. The <tt>restore</tt> method should
|
216
|
+
# take two parameters: `[String] name` and `[String] value`.
|
217
|
+
# The <tt>restore</tt> method should reverse any transformations that
|
218
|
+
# have been performed on the value to ensure a valid URI.
|
219
|
+
# The <tt>match</tt> method should take a single
|
220
|
+
# parameter: `[String] name`. The <tt>match</tt> method should return
|
221
|
+
# a <tt>String</tt> containing a regular expression capture group for
|
222
|
+
# matching on that particular variable. The default value is `".*?"`.
|
223
|
+
# The <tt>match</tt> method has no effect on multivariate operator
|
224
|
+
# expansions.
|
227
225
|
#
|
228
226
|
# @return [Hash, NilClass]
|
229
|
-
#
|
230
|
-
#
|
227
|
+
# The <tt>Hash</tt> mapping that was extracted from the URI, or
|
228
|
+
# <tt>nil</tt> if the URI didn't match the template.
|
231
229
|
#
|
232
230
|
# @example
|
233
231
|
# class ExampleProcessor
|
data/lib/addressable/uri.rb
CHANGED
@@ -1,30 +1,26 @@
|
|
1
1
|
# encoding:utf-8
|
2
2
|
#--
|
3
|
-
#
|
3
|
+
# Copyright (C) 2006-2011 Bob Aman
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
9
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
11
|
-
# the following conditions:
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
12
8
|
#
|
13
|
-
#
|
14
|
-
# included in all copies or substantial portions of the Software.
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
15
10
|
#
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
23
16
|
#++
|
24
17
|
|
18
|
+
|
25
19
|
require "addressable/version"
|
26
20
|
require "addressable/idna"
|
27
21
|
|
22
|
+
##
|
23
|
+
# Addressable is a library for processing links and URIs.
|
28
24
|
module Addressable
|
29
25
|
##
|
30
26
|
# This is an implementation of a URI parser based on
|
@@ -54,6 +50,11 @@ module Addressable
|
|
54
50
|
FRAGMENT = PCHAR + "\\/\\?"
|
55
51
|
end
|
56
52
|
|
53
|
+
SLASH = '/'
|
54
|
+
EMPTYSTR = ''
|
55
|
+
|
56
|
+
URIREGEX = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
|
57
|
+
|
57
58
|
##
|
58
59
|
# Returns a URI object based on the parsed string.
|
59
60
|
#
|
@@ -67,7 +68,7 @@ module Addressable
|
|
67
68
|
# If we were given nil, return nil.
|
68
69
|
return nil unless uri
|
69
70
|
# If a URI object is passed, just return itself.
|
70
|
-
return uri if uri.kind_of?(self)
|
71
|
+
return uri.dup if uri.kind_of?(self)
|
71
72
|
|
72
73
|
# If a URI object of the Ruby standard library variety is passed,
|
73
74
|
# convert it to a string, then parse the string.
|
@@ -77,16 +78,15 @@ module Addressable
|
|
77
78
|
uri = uri.to_s
|
78
79
|
end
|
79
80
|
|
80
|
-
if !uri.respond_to?(:to_str)
|
81
|
-
raise TypeError, "Can't convert #{uri.class} into String."
|
82
|
-
end
|
83
81
|
# Otherwise, convert to a String
|
84
|
-
|
82
|
+
begin
|
83
|
+
uri = uri.to_str
|
84
|
+
rescue TypeError, NoMethodError
|
85
|
+
raise TypeError, "Can't convert #{uri.class} into String."
|
86
|
+
end if not uri.is_a? String
|
85
87
|
|
86
88
|
# This Regexp supplied as an example in RFC 3986, and it works great.
|
87
|
-
|
88
|
-
/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/
|
89
|
-
scan = uri.scan(uri_regex)
|
89
|
+
scan = uri.scan(URIREGEX)
|
90
90
|
fragments = scan[0]
|
91
91
|
scheme = fragments[1]
|
92
92
|
authority = fragments[3]
|
@@ -104,10 +104,10 @@ module Addressable
|
|
104
104
|
user = userinfo.strip[/^([^:]*):?/, 1]
|
105
105
|
password = userinfo.strip[/:(.*)$/, 1]
|
106
106
|
end
|
107
|
-
host = authority.gsub(/^([^\[\]]*)@/,
|
107
|
+
host = authority.gsub(/^([^\[\]]*)@/, EMPTYSTR).gsub(/:([^:@\[\]]*?)$/, EMPTYSTR)
|
108
108
|
port = authority[/:([^:@\[\]]*?)$/, 1]
|
109
109
|
end
|
110
|
-
if port ==
|
110
|
+
if port == EMPTYSTR
|
111
111
|
port = nil
|
112
112
|
end
|
113
113
|
|
@@ -141,7 +141,7 @@ module Addressable
|
|
141
141
|
# If we were given nil, return nil.
|
142
142
|
return nil unless uri
|
143
143
|
# If a URI object is passed, just return itself.
|
144
|
-
return uri if uri.kind_of?(self)
|
144
|
+
return uri.dup if uri.kind_of?(self)
|
145
145
|
if !uri.respond_to?(:to_str)
|
146
146
|
raise TypeError, "Can't convert #{uri.class} into String."
|
147
147
|
end
|
@@ -169,7 +169,7 @@ module Addressable
|
|
169
169
|
if new_host
|
170
170
|
parsed.defer_validation do
|
171
171
|
new_path = parsed.path.gsub(
|
172
|
-
Regexp.new("^" + Regexp.escape(new_host)),
|
172
|
+
Regexp.new("^" + Regexp.escape(new_host)), EMPTYSTR)
|
173
173
|
parsed.host = new_host
|
174
174
|
parsed.path = new_path
|
175
175
|
parsed.scheme = hints[:scheme] unless parsed.scheme
|
@@ -219,8 +219,8 @@ module Addressable
|
|
219
219
|
# Otherwise, convert to a String
|
220
220
|
path = path.to_str.strip
|
221
221
|
|
222
|
-
path.gsub!(/^file:\/?\/?/,
|
223
|
-
path =
|
222
|
+
path.gsub!(/^file:\/?\/?/, EMPTYSTR) if path =~ /^file:\/?\/?/
|
223
|
+
path = SLASH + path if path =~ /^([a-zA-Z])[\|:]/
|
224
224
|
uri = self.parse(path)
|
225
225
|
|
226
226
|
if uri.scheme == nil
|
@@ -228,17 +228,17 @@ module Addressable
|
|
228
228
|
uri.path.gsub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
|
229
229
|
"/#{$1.downcase}:/"
|
230
230
|
end
|
231
|
-
uri.path.gsub!(/\\/,
|
231
|
+
uri.path.gsub!(/\\/, SLASH)
|
232
232
|
if File.exists?(uri.path) &&
|
233
233
|
File.stat(uri.path).directory?
|
234
|
-
uri.path.gsub!(/\/$/,
|
234
|
+
uri.path.gsub!(/\/$/, EMPTYSTR)
|
235
235
|
uri.path = uri.path + '/'
|
236
236
|
end
|
237
237
|
|
238
238
|
# If the path is absolute, set the scheme and host.
|
239
239
|
if uri.path =~ /^\//
|
240
240
|
uri.scheme = "file"
|
241
|
-
uri.host =
|
241
|
+
uri.host = EMPTYSTR
|
242
242
|
end
|
243
243
|
uri.normalize!
|
244
244
|
end
|
@@ -305,10 +305,13 @@ module Addressable
|
|
305
305
|
def self.encode_component(component, character_class=
|
306
306
|
CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
|
307
307
|
return nil if component.nil?
|
308
|
-
|
308
|
+
|
309
|
+
begin
|
310
|
+
component = component.to_str
|
311
|
+
rescue TypeError, NoMethodError
|
309
312
|
raise TypeError, "Can't convert #{component.class} into String."
|
310
|
-
end
|
311
|
-
|
313
|
+
end if !component.is_a? String
|
314
|
+
|
312
315
|
if ![String, Regexp].include?(character_class.class)
|
313
316
|
raise TypeError,
|
314
317
|
"Expected String or Regexp, got #{character_class.inspect}"
|
@@ -323,7 +326,7 @@ module Addressable
|
|
323
326
|
component.force_encoding(Encoding::ASCII_8BIT)
|
324
327
|
end
|
325
328
|
return component.gsub(character_class) do |sequence|
|
326
|
-
(sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
|
329
|
+
(sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
|
327
330
|
end
|
328
331
|
end
|
329
332
|
|
@@ -351,15 +354,18 @@ module Addressable
|
|
351
354
|
# The return type is determined by the <code>returning</code> parameter.
|
352
355
|
def self.unencode(uri, returning=String)
|
353
356
|
return nil if uri.nil?
|
354
|
-
|
357
|
+
|
358
|
+
begin
|
359
|
+
uri = uri.to_str
|
360
|
+
rescue NoMethodError, TypeError
|
355
361
|
raise TypeError, "Can't convert #{uri.class} into String."
|
356
|
-
end
|
362
|
+
end if !uri.is_a? String
|
357
363
|
if ![String, ::Addressable::URI].include?(returning)
|
358
364
|
raise TypeError,
|
359
365
|
"Expected Class (String or Addressable::URI), " +
|
360
366
|
"got #{returning.inspect}"
|
361
367
|
end
|
362
|
-
result = uri.
|
368
|
+
result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
|
363
369
|
sequence[1..3].to_i(16).chr
|
364
370
|
end
|
365
371
|
result.force_encoding("utf-8") if result.respond_to?(:force_encoding)
|
@@ -387,10 +393,10 @@ module Addressable
|
|
387
393
|
# is passed, the <code>String</code> must be formatted as a regular
|
388
394
|
# expression character class. (Do not include the surrounding square
|
389
395
|
# brackets.) For example, <code>"b-zB-Z0-9"</code> would cause
|
390
|
-
# everything but the letters 'b' through 'z' and the numbers '0'
|
391
|
-
#
|
392
|
-
# value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A
|
393
|
-
# useful <code>String</code> values may be found in the
|
396
|
+
# everything but the letters 'b' through 'z' and the numbers '0'
|
397
|
+
# through '9' to be percent encoded. If a <code>Regexp</code> is passed,
|
398
|
+
# the value <code>/[^b-zB-Z0-9]/</code> would have the same effect. A
|
399
|
+
# set of useful <code>String</code> values may be found in the
|
394
400
|
# <code>Addressable::URI::CharacterClasses</code> module. The default
|
395
401
|
# value is the reserved plus unreserved character classes specified in
|
396
402
|
# <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
|
@@ -412,10 +418,13 @@ module Addressable
|
|
412
418
|
def self.normalize_component(component, character_class=
|
413
419
|
CharacterClasses::RESERVED + CharacterClasses::UNRESERVED)
|
414
420
|
return nil if component.nil?
|
415
|
-
|
421
|
+
|
422
|
+
begin
|
423
|
+
component = component.to_str
|
424
|
+
rescue NoMethodError, TypeError
|
416
425
|
raise TypeError, "Can't convert #{component.class} into String."
|
417
|
-
end
|
418
|
-
|
426
|
+
end if !component.is_a? String
|
427
|
+
|
419
428
|
if ![String, Regexp].include?(character_class.class)
|
420
429
|
raise TypeError,
|
421
430
|
"Expected String or Regexp, got #{character_class.inspect}"
|
@@ -458,15 +467,19 @@ module Addressable
|
|
458
467
|
# The return type is determined by the <code>returning</code> parameter.
|
459
468
|
def self.encode(uri, returning=String)
|
460
469
|
return nil if uri.nil?
|
461
|
-
|
470
|
+
|
471
|
+
begin
|
472
|
+
uri = uri.to_str
|
473
|
+
rescue NoMethodError, TypeError
|
462
474
|
raise TypeError, "Can't convert #{uri.class} into String."
|
463
|
-
end
|
475
|
+
end if !uri.is_a? String
|
476
|
+
|
464
477
|
if ![String, ::Addressable::URI].include?(returning)
|
465
478
|
raise TypeError,
|
466
479
|
"Expected Class (String or Addressable::URI), " +
|
467
480
|
"got #{returning.inspect}"
|
468
481
|
end
|
469
|
-
uri_object = uri.kind_of?(self) ? uri : self.parse(uri
|
482
|
+
uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
|
470
483
|
encoded_uri = Addressable::URI.new(
|
471
484
|
:scheme => self.encode_component(uri_object.scheme,
|
472
485
|
Addressable::URI::CharacterClasses::SCHEME),
|
@@ -507,15 +520,18 @@ module Addressable
|
|
507
520
|
# The encoded URI.
|
508
521
|
# The return type is determined by the <code>returning</code> parameter.
|
509
522
|
def self.normalized_encode(uri, returning=String)
|
510
|
-
|
523
|
+
begin
|
524
|
+
uri = uri.to_str
|
525
|
+
rescue NoMethodError, TypeError
|
511
526
|
raise TypeError, "Can't convert #{uri.class} into String."
|
512
|
-
end
|
527
|
+
end if !uri.is_a? String
|
528
|
+
|
513
529
|
if ![String, ::Addressable::URI].include?(returning)
|
514
530
|
raise TypeError,
|
515
531
|
"Expected Class (String or Addressable::URI), " +
|
516
532
|
"got #{returning.inspect}"
|
517
533
|
end
|
518
|
-
uri_object = uri.kind_of?(self) ? uri : self.parse(uri
|
534
|
+
uri_object = uri.kind_of?(self) ? uri : self.parse(uri)
|
519
535
|
components = {
|
520
536
|
:scheme => self.unencode_component(uri_object.scheme),
|
521
537
|
:user => self.unencode_component(uri_object.user),
|
@@ -719,9 +735,6 @@ module Addressable
|
|
719
735
|
#
|
720
736
|
# @param [String, #to_str] new_scheme The new scheme component.
|
721
737
|
def scheme=(new_scheme)
|
722
|
-
# Check for frozenness
|
723
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
724
|
-
|
725
738
|
if new_scheme && !new_scheme.respond_to?(:to_str)
|
726
739
|
raise TypeError, "Can't convert #{new_scheme.class} into String."
|
727
740
|
elsif new_scheme
|
@@ -731,7 +744,7 @@ module Addressable
|
|
731
744
|
raise InvalidURIError, "Invalid scheme format."
|
732
745
|
end
|
733
746
|
@scheme = new_scheme
|
734
|
-
@scheme = nil if @scheme.to_s.strip
|
747
|
+
@scheme = nil if @scheme.to_s.strip.empty?
|
735
748
|
|
736
749
|
# Reset dependant values
|
737
750
|
@normalized_scheme = nil
|
@@ -757,8 +770,8 @@ module Addressable
|
|
757
770
|
def normalized_user
|
758
771
|
@normalized_user ||= (begin
|
759
772
|
if self.user
|
760
|
-
if normalized_scheme =~ /https?/ && self.user.strip
|
761
|
-
(!self.password || self.password.strip
|
773
|
+
if normalized_scheme =~ /https?/ && self.user.strip.empty? &&
|
774
|
+
(!self.password || self.password.strip.empty?)
|
762
775
|
nil
|
763
776
|
else
|
764
777
|
Addressable::URI.normalize_component(
|
@@ -777,9 +790,6 @@ module Addressable
|
|
777
790
|
#
|
778
791
|
# @param [String, #to_str] new_user The new user component.
|
779
792
|
def user=(new_user)
|
780
|
-
# Check for frozenness
|
781
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
782
|
-
|
783
793
|
if new_user && !new_user.respond_to?(:to_str)
|
784
794
|
raise TypeError, "Can't convert #{new_user.class} into String."
|
785
795
|
end
|
@@ -788,7 +798,7 @@ module Addressable
|
|
788
798
|
# You can't have a nil user with a non-nil password
|
789
799
|
@password ||= nil
|
790
800
|
if @password != nil
|
791
|
-
@user =
|
801
|
+
@user = EMPTYSTR if @user.nil?
|
792
802
|
end
|
793
803
|
|
794
804
|
# Reset dependant values
|
@@ -818,8 +828,8 @@ module Addressable
|
|
818
828
|
def normalized_password
|
819
829
|
@normalized_password ||= (begin
|
820
830
|
if self.password
|
821
|
-
if normalized_scheme =~ /https?/ && self.password.strip
|
822
|
-
(!self.user || self.user.strip
|
831
|
+
if normalized_scheme =~ /https?/ && self.password.strip.empty? &&
|
832
|
+
(!self.user || self.user.strip.empty?)
|
823
833
|
nil
|
824
834
|
else
|
825
835
|
Addressable::URI.normalize_component(
|
@@ -838,9 +848,6 @@ module Addressable
|
|
838
848
|
#
|
839
849
|
# @param [String, #to_str] new_password The new password component.
|
840
850
|
def password=(new_password)
|
841
|
-
# Check for frozenness
|
842
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
843
|
-
|
844
851
|
if new_password && !new_password.respond_to?(:to_str)
|
845
852
|
raise TypeError, "Can't convert #{new_password.class} into String."
|
846
853
|
end
|
@@ -850,7 +857,7 @@ module Addressable
|
|
850
857
|
@password ||= nil
|
851
858
|
@user ||= nil
|
852
859
|
if @password != nil
|
853
|
-
@user =
|
860
|
+
@user = EMPTYSTR if @user.nil?
|
854
861
|
end
|
855
862
|
|
856
863
|
# Reset dependant values
|
@@ -907,9 +914,6 @@ module Addressable
|
|
907
914
|
#
|
908
915
|
# @param [String, #to_str] new_userinfo The new userinfo component.
|
909
916
|
def userinfo=(new_userinfo)
|
910
|
-
# Check for frozenness
|
911
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
912
|
-
|
913
917
|
if new_userinfo && !new_userinfo.respond_to?(:to_str)
|
914
918
|
raise TypeError, "Can't convert #{new_userinfo.class} into String."
|
915
919
|
end
|
@@ -950,9 +954,9 @@ module Addressable
|
|
950
954
|
def normalized_host
|
951
955
|
@normalized_host ||= (begin
|
952
956
|
if self.host != nil
|
953
|
-
if self.host.strip
|
957
|
+
if !self.host.strip.empty?
|
954
958
|
result = ::Addressable::IDNA.to_ascii(
|
955
|
-
|
959
|
+
URI.unencode_component(self.host.strip.downcase)
|
956
960
|
)
|
957
961
|
if result[-1..-1] == "."
|
958
962
|
# Trailing dots are unnecessary
|
@@ -960,7 +964,7 @@ module Addressable
|
|
960
964
|
end
|
961
965
|
result
|
962
966
|
else
|
963
|
-
|
967
|
+
EMPTYSTR
|
964
968
|
end
|
965
969
|
else
|
966
970
|
nil
|
@@ -973,9 +977,6 @@ module Addressable
|
|
973
977
|
#
|
974
978
|
# @param [String, #to_str] new_host The new host component.
|
975
979
|
def host=(new_host)
|
976
|
-
# Check for frozenness
|
977
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
978
|
-
|
979
980
|
if new_host && !new_host.respond_to?(:to_str)
|
980
981
|
raise TypeError, "Can't convert #{new_host.class} into String."
|
981
982
|
end
|
@@ -1041,9 +1042,6 @@ module Addressable
|
|
1041
1042
|
#
|
1042
1043
|
# @param [String, #to_str] new_authority The new authority component.
|
1043
1044
|
def authority=(new_authority)
|
1044
|
-
# Check for frozenness
|
1045
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1046
|
-
|
1047
1045
|
if new_authority
|
1048
1046
|
if !new_authority.respond_to?(:to_str)
|
1049
1047
|
raise TypeError, "Can't convert #{new_authority.class} into String."
|
@@ -1055,7 +1053,7 @@ module Addressable
|
|
1055
1053
|
new_password = new_userinfo.strip[/:(.*)$/, 1]
|
1056
1054
|
end
|
1057
1055
|
new_host =
|
1058
|
-
new_authority.gsub(/^([^\[\]]*)@/,
|
1056
|
+
new_authority.gsub(/^([^\[\]]*)@/, EMPTYSTR).gsub(/:([^:@\[\]]*?)$/, EMPTYSTR)
|
1059
1057
|
new_port =
|
1060
1058
|
new_authority[/:([^:@\[\]]*?)$/, 1]
|
1061
1059
|
end
|
@@ -1141,7 +1139,7 @@ module Addressable
|
|
1141
1139
|
# @return [Integer] The port component, normalized.
|
1142
1140
|
def normalized_port
|
1143
1141
|
@normalized_port ||= (begin
|
1144
|
-
if
|
1142
|
+
if URI.port_mapping[normalized_scheme] == self.port
|
1145
1143
|
nil
|
1146
1144
|
else
|
1147
1145
|
self.port
|
@@ -1154,9 +1152,6 @@ module Addressable
|
|
1154
1152
|
#
|
1155
1153
|
# @param [String, Integer, #to_s] new_port The new port component.
|
1156
1154
|
def port=(new_port)
|
1157
|
-
# Check for frozenness
|
1158
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1159
|
-
|
1160
1155
|
if new_port != nil && new_port.respond_to?(:to_str)
|
1161
1156
|
new_port = Addressable::URI.unencode_component(new_port.to_str)
|
1162
1157
|
end
|
@@ -1189,7 +1184,7 @@ module Addressable
|
|
1189
1184
|
@inferred_port ||= (begin
|
1190
1185
|
if port.to_i == 0
|
1191
1186
|
if scheme
|
1192
|
-
|
1187
|
+
URI.port_mapping[scheme.strip.downcase]
|
1193
1188
|
else
|
1194
1189
|
nil
|
1195
1190
|
end
|
@@ -1274,33 +1269,35 @@ module Addressable
|
|
1274
1269
|
#
|
1275
1270
|
# @return [String] The path component.
|
1276
1271
|
def path
|
1277
|
-
@path ||=
|
1272
|
+
@path ||= EMPTYSTR
|
1278
1273
|
return @path
|
1279
1274
|
end
|
1280
1275
|
|
1276
|
+
NORMPATH = /^(?!\/)[^\/:]*:.*$/
|
1281
1277
|
##
|
1282
1278
|
# The path component for this URI, normalized.
|
1283
1279
|
#
|
1284
1280
|
# @return [String] The path component, normalized.
|
1285
1281
|
def normalized_path
|
1286
1282
|
@normalized_path ||= (begin
|
1287
|
-
if self.scheme == nil && self.path != nil && self.path
|
1288
|
-
self.path =~
|
1283
|
+
if self.scheme == nil && self.path != nil && !self.path.empty? &&
|
1284
|
+
self.path =~ NORMPATH
|
1289
1285
|
# Relative paths with colons in the first segment are ambiguous.
|
1290
1286
|
self.path.sub!(":", "%2F")
|
1291
1287
|
end
|
1292
1288
|
# String#split(delimeter, -1) uses the more strict splitting behavior
|
1293
1289
|
# found by default in Python.
|
1294
|
-
result = (self.path.strip.split(
|
1290
|
+
result = (self.path.strip.split(SLASH, -1).map do |segment|
|
1295
1291
|
Addressable::URI.normalize_component(
|
1296
1292
|
segment,
|
1297
1293
|
Addressable::URI::CharacterClasses::PCHAR
|
1298
1294
|
)
|
1299
|
-
end).join(
|
1300
|
-
|
1301
|
-
|
1295
|
+
end).join(SLASH)
|
1296
|
+
|
1297
|
+
result = URI.normalize_path(result)
|
1298
|
+
if result.empty? &&
|
1302
1299
|
["http", "https", "ftp", "tftp"].include?(self.normalized_scheme)
|
1303
|
-
result =
|
1300
|
+
result = SLASH
|
1304
1301
|
end
|
1305
1302
|
result
|
1306
1303
|
end)
|
@@ -1311,14 +1308,11 @@ module Addressable
|
|
1311
1308
|
#
|
1312
1309
|
# @param [String, #to_str] new_path The new path component.
|
1313
1310
|
def path=(new_path)
|
1314
|
-
# Check for frozenness
|
1315
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1316
|
-
|
1317
1311
|
if new_path && !new_path.respond_to?(:to_str)
|
1318
1312
|
raise TypeError, "Can't convert #{new_path.class} into String."
|
1319
1313
|
end
|
1320
|
-
@path = (new_path ||
|
1321
|
-
if
|
1314
|
+
@path = (new_path || EMPTYSTR).to_str
|
1315
|
+
if !@path.empty? && @path[0..0] != SLASH && host != nil
|
1322
1316
|
@path = "/#{@path}"
|
1323
1317
|
end
|
1324
1318
|
|
@@ -1334,7 +1328,7 @@ module Addressable
|
|
1334
1328
|
# @return [String] The path's basename.
|
1335
1329
|
def basename
|
1336
1330
|
# Path cannot be nil
|
1337
|
-
return File.basename(self.path).gsub(/;[^\/]*$/,
|
1331
|
+
return File.basename(self.path).gsub(/;[^\/]*$/, EMPTYSTR)
|
1338
1332
|
end
|
1339
1333
|
|
1340
1334
|
##
|
@@ -1362,10 +1356,12 @@ module Addressable
|
|
1362
1356
|
def normalized_query
|
1363
1357
|
@normalized_query ||= (begin
|
1364
1358
|
if self.query
|
1365
|
-
|
1366
|
-
|
1367
|
-
|
1368
|
-
|
1359
|
+
(self.query.split("&", -1).map do |pair|
|
1360
|
+
Addressable::URI.normalize_component(
|
1361
|
+
pair,
|
1362
|
+
Addressable::URI::CharacterClasses::QUERY.sub("\\&", "")
|
1363
|
+
)
|
1364
|
+
end).join("&")
|
1369
1365
|
else
|
1370
1366
|
nil
|
1371
1367
|
end
|
@@ -1377,9 +1373,6 @@ module Addressable
|
|
1377
1373
|
#
|
1378
1374
|
# @param [String, #to_str] new_query The new query component.
|
1379
1375
|
def query=(new_query)
|
1380
|
-
# Check for frozenness
|
1381
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1382
|
-
|
1383
1376
|
if new_query && !new_query.respond_to?(:to_str)
|
1384
1377
|
raise TypeError, "Can't convert #{new_query.class} into String."
|
1385
1378
|
end
|
@@ -1450,12 +1443,12 @@ module Addressable
|
|
1450
1443
|
return nil if self.query == nil
|
1451
1444
|
empty_accumulator = :flat_array == options[:notation] ? [] : {}
|
1452
1445
|
return ((self.query.split("&").map do |pair|
|
1453
|
-
pair.split("=", 2) if pair && pair
|
1446
|
+
pair.split("=", 2) if pair && !pair.empty?
|
1454
1447
|
end).compact.inject(empty_accumulator.dup) do |accumulator, (key, value)|
|
1455
1448
|
value = true if value.nil?
|
1456
|
-
key =
|
1449
|
+
key = URI.unencode_component(key)
|
1457
1450
|
if value != true
|
1458
|
-
value =
|
1451
|
+
value = URI.unencode_component(value.gsub(/\+/, " "))
|
1459
1452
|
end
|
1460
1453
|
if options[:notation] == :flat
|
1461
1454
|
if accumulator[key]
|
@@ -1503,8 +1496,6 @@ module Addressable
|
|
1503
1496
|
#
|
1504
1497
|
# @param [Hash, #to_hash, Array] new_query_values The new query values.
|
1505
1498
|
def query_values=(new_query_values)
|
1506
|
-
# Check for frozenness
|
1507
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1508
1499
|
if new_query_values == nil
|
1509
1500
|
self.query = nil
|
1510
1501
|
return nil
|
@@ -1531,7 +1522,7 @@ module Addressable
|
|
1531
1522
|
stack = []
|
1532
1523
|
e = lambda do |component|
|
1533
1524
|
component = component.to_s if component.kind_of?(Symbol)
|
1534
|
-
|
1525
|
+
URI.encode_component(component, CharacterClasses::UNRESERVED)
|
1535
1526
|
end
|
1536
1527
|
new_query_values.each do |key, value|
|
1537
1528
|
if value.kind_of?(Hash)
|
@@ -1569,8 +1560,8 @@ module Addressable
|
|
1569
1560
|
def request_uri
|
1570
1561
|
return nil if self.absolute? && self.scheme !~ /^https?$/
|
1571
1562
|
return (
|
1572
|
-
(self.path
|
1573
|
-
(self.query ? "?#{self.query}" :
|
1563
|
+
(!self.path.empty? ? self.path : SLASH) +
|
1564
|
+
(self.query ? "?#{self.query}" : EMPTYSTR)
|
1574
1565
|
)
|
1575
1566
|
end
|
1576
1567
|
|
@@ -1590,7 +1581,7 @@ module Addressable
|
|
1590
1581
|
path_component = new_request_uri[/^([^\?]*)\?(?:.*)$/, 1]
|
1591
1582
|
query_component = new_request_uri[/^(?:[^\?]*)\?(.*)$/, 1]
|
1592
1583
|
path_component = path_component.to_s
|
1593
|
-
path_component = (path_component
|
1584
|
+
path_component = (!path_component.empty? ? path_component : SLASH)
|
1594
1585
|
self.path = path_component
|
1595
1586
|
self.query = query_component
|
1596
1587
|
|
@@ -1629,9 +1620,6 @@ module Addressable
|
|
1629
1620
|
#
|
1630
1621
|
# @param [String, #to_str] new_fragment The new fragment component.
|
1631
1622
|
def fragment=(new_fragment)
|
1632
|
-
# Check for frozenness
|
1633
|
-
raise TypeError, "Can't modify frozen URI." if self.frozen?
|
1634
|
-
|
1635
1623
|
if new_fragment && !new_fragment.respond_to?(:to_str)
|
1636
1624
|
raise TypeError, "Can't convert #{new_fragment.class} into String."
|
1637
1625
|
end
|
@@ -1654,7 +1642,7 @@ module Addressable
|
|
1654
1642
|
# <code>false</code> otherwise.
|
1655
1643
|
def ip_based?
|
1656
1644
|
if self.scheme
|
1657
|
-
return
|
1645
|
+
return URI.ip_based_schemes.include?(
|
1658
1646
|
self.scheme.strip.downcase)
|
1659
1647
|
end
|
1660
1648
|
return false
|
@@ -1690,11 +1678,11 @@ module Addressable
|
|
1690
1678
|
if !uri.respond_to?(:to_str)
|
1691
1679
|
raise TypeError, "Can't convert #{uri.class} into String."
|
1692
1680
|
end
|
1693
|
-
if !uri.kind_of?(
|
1681
|
+
if !uri.kind_of?(URI)
|
1694
1682
|
# Otherwise, convert to a String, then parse.
|
1695
|
-
uri =
|
1683
|
+
uri = URI.parse(uri.to_str)
|
1696
1684
|
end
|
1697
|
-
if uri.to_s
|
1685
|
+
if uri.to_s.empty?
|
1698
1686
|
return self.dup
|
1699
1687
|
end
|
1700
1688
|
|
@@ -1714,7 +1702,7 @@ module Addressable
|
|
1714
1702
|
joined_password = uri.password
|
1715
1703
|
joined_host = uri.host
|
1716
1704
|
joined_port = uri.port
|
1717
|
-
joined_path =
|
1705
|
+
joined_path = URI.normalize_path(uri.path)
|
1718
1706
|
joined_query = uri.query
|
1719
1707
|
else
|
1720
1708
|
if uri.authority != nil
|
@@ -1722,10 +1710,10 @@ module Addressable
|
|
1722
1710
|
joined_password = uri.password
|
1723
1711
|
joined_host = uri.host
|
1724
1712
|
joined_port = uri.port
|
1725
|
-
joined_path =
|
1713
|
+
joined_path = URI.normalize_path(uri.path)
|
1726
1714
|
joined_query = uri.query
|
1727
1715
|
else
|
1728
|
-
if uri.path == nil || uri.path
|
1716
|
+
if uri.path == nil || uri.path.empty?
|
1729
1717
|
joined_path = self.path
|
1730
1718
|
if uri.query != nil
|
1731
1719
|
joined_query = uri.query
|
@@ -1733,29 +1721,29 @@ module Addressable
|
|
1733
1721
|
joined_query = self.query
|
1734
1722
|
end
|
1735
1723
|
else
|
1736
|
-
if uri.path[0..0] ==
|
1737
|
-
joined_path =
|
1724
|
+
if uri.path[0..0] == SLASH
|
1725
|
+
joined_path = URI.normalize_path(uri.path)
|
1738
1726
|
else
|
1739
1727
|
base_path = self.path.dup
|
1740
|
-
base_path =
|
1741
|
-
base_path =
|
1728
|
+
base_path = EMPTYSTR if base_path == nil
|
1729
|
+
base_path = URI.normalize_path(base_path)
|
1742
1730
|
|
1743
1731
|
# Section 5.2.3 of RFC 3986
|
1744
1732
|
#
|
1745
1733
|
# Removes the right-most path segment from the base path.
|
1746
1734
|
if base_path =~ /\//
|
1747
|
-
base_path.gsub!(/\/[^\/]+$/,
|
1735
|
+
base_path.gsub!(/\/[^\/]+$/, SLASH)
|
1748
1736
|
else
|
1749
|
-
base_path =
|
1737
|
+
base_path = EMPTYSTR
|
1750
1738
|
end
|
1751
1739
|
|
1752
1740
|
# If the base path is empty and an authority segment has been
|
1753
|
-
# defined, use a base path of
|
1754
|
-
if base_path
|
1755
|
-
base_path =
|
1741
|
+
# defined, use a base path of SLASH
|
1742
|
+
if base_path.empty? && self.authority != nil
|
1743
|
+
base_path = SLASH
|
1756
1744
|
end
|
1757
1745
|
|
1758
|
-
joined_path =
|
1746
|
+
joined_path = URI.normalize_path(base_path + uri.path)
|
1759
1747
|
end
|
1760
1748
|
joined_query = uri.query
|
1761
1749
|
end
|
@@ -1883,7 +1871,7 @@ module Addressable
|
|
1883
1871
|
# @return [Addressable::URI]
|
1884
1872
|
# The normalized relative URI that is equivalent to the original URI.
|
1885
1873
|
def route_from(uri)
|
1886
|
-
uri =
|
1874
|
+
uri = URI.parse(uri).normalize
|
1887
1875
|
normalized_self = self.normalize
|
1888
1876
|
if normalized_self.relative?
|
1889
1877
|
raise ArgumentError, "Expected absolute URI, got: #{self.to_s}"
|
@@ -1908,9 +1896,9 @@ module Addressable
|
|
1908
1896
|
components[:query] = nil
|
1909
1897
|
end
|
1910
1898
|
else
|
1911
|
-
if uri.path !=
|
1899
|
+
if uri.path != SLASH
|
1912
1900
|
components[:path].gsub!(
|
1913
|
-
Regexp.new("^" + Regexp.escape(uri.path)),
|
1901
|
+
Regexp.new("^" + Regexp.escape(uri.path)), EMPTYSTR)
|
1914
1902
|
end
|
1915
1903
|
end
|
1916
1904
|
end
|
@@ -1941,7 +1929,7 @@ module Addressable
|
|
1941
1929
|
# @return [Addressable::URI]
|
1942
1930
|
# The normalized relative URI that is equivalent to the supplied URI.
|
1943
1931
|
def route_to(uri)
|
1944
|
-
return
|
1932
|
+
return URI.parse(uri).route_from(self)
|
1945
1933
|
end
|
1946
1934
|
|
1947
1935
|
##
|
@@ -1959,7 +1947,7 @@ module Addressable
|
|
1959
1947
|
# URI scheme.
|
1960
1948
|
if normalized_scheme == "feed"
|
1961
1949
|
if self.to_s =~ /^feed:\/*http:\/*/
|
1962
|
-
return
|
1950
|
+
return URI.parse(
|
1963
1951
|
self.to_s[/^feed:\/*(http:\/*.*)/, 1]
|
1964
1952
|
).normalize
|
1965
1953
|
end
|
@@ -2030,7 +2018,7 @@ module Addressable
|
|
2030
2018
|
# <code>true</code> if the URIs are equivalent, <code>false</code>
|
2031
2019
|
# otherwise.
|
2032
2020
|
def ==(uri)
|
2033
|
-
return false unless uri.kind_of?(
|
2021
|
+
return false unless uri.kind_of?(URI)
|
2034
2022
|
return self.normalize.to_s == uri.normalize.to_s
|
2035
2023
|
end
|
2036
2024
|
|
@@ -2044,7 +2032,7 @@ module Addressable
|
|
2044
2032
|
# <code>true</code> if the URIs are equivalent, <code>false</code>
|
2045
2033
|
# otherwise.
|
2046
2034
|
def eql?(uri)
|
2047
|
-
return false unless uri.kind_of?(
|
2035
|
+
return false unless uri.kind_of?(URI)
|
2048
2036
|
return self.to_s == uri.to_s
|
2049
2037
|
end
|
2050
2038
|
|
@@ -2075,28 +2063,6 @@ module Addressable
|
|
2075
2063
|
return duplicated_uri
|
2076
2064
|
end
|
2077
2065
|
|
2078
|
-
##
|
2079
|
-
# Freezes the URI object.
|
2080
|
-
#
|
2081
|
-
# @return [Addressable::URI] The frozen URI.
|
2082
|
-
def freeze
|
2083
|
-
# Unfortunately, because of the memoized implementation of many of the
|
2084
|
-
# URI methods, the default freeze method will cause unexpected errors.
|
2085
|
-
# As an alternative, we freeze the string representation of the URI
|
2086
|
-
# instead. This should generally produce the desired effect.
|
2087
|
-
self.to_s.freeze
|
2088
|
-
return self
|
2089
|
-
end
|
2090
|
-
|
2091
|
-
##
|
2092
|
-
# Determines if the URI is frozen.
|
2093
|
-
#
|
2094
|
-
# @return [TrueClass, FalseClass]
|
2095
|
-
# <code>true</code> if the URI is frozen, <code>false</code> otherwise.
|
2096
|
-
def frozen?
|
2097
|
-
self.to_s.frozen?
|
2098
|
-
end
|
2099
|
-
|
2100
2066
|
##
|
2101
2067
|
# Omits components from a URI.
|
2102
2068
|
#
|
@@ -2185,7 +2151,7 @@ module Addressable
|
|
2185
2151
|
#
|
2186
2152
|
# @return [String] The URI object's state, as a <code>String</code>.
|
2187
2153
|
def inspect
|
2188
|
-
sprintf("#<%s:%#0x URI:%s>",
|
2154
|
+
sprintf("#<%s:%#0x URI:%s>", URI.to_s, self.object_id, self.to_s)
|
2189
2155
|
end
|
2190
2156
|
|
2191
2157
|
##
|
@@ -2212,30 +2178,34 @@ module Addressable
|
|
2212
2178
|
# @param [String] path The path to normalize.
|
2213
2179
|
#
|
2214
2180
|
# @return [String] The normalized path.
|
2181
|
+
|
2182
|
+
PARENT1 = '.'
|
2183
|
+
PARENT2 = '..'
|
2184
|
+
|
2185
|
+
NPATH1 = /\/\.\/|\/\.$/
|
2186
|
+
NPATH2 = /\/([^\/]+)\/\.\.\/|\/([^\/]+)\/\.\.$/
|
2187
|
+
NPATH3 = /^\.\.?\/?/
|
2188
|
+
NPATH4 = /^\/\.\.?\/|^(\/\.\.?)+\/?$/
|
2189
|
+
|
2215
2190
|
def self.normalize_path(path)
|
2216
2191
|
# Section 5.2.4 of RFC 3986
|
2217
2192
|
|
2218
2193
|
return nil if path.nil?
|
2219
2194
|
normalized_path = path.dup
|
2220
|
-
previous_state = normalized_path.dup
|
2221
2195
|
begin
|
2222
|
-
|
2223
|
-
normalized_path.gsub!(
|
2224
|
-
|
2225
|
-
parent = normalized_path
|
2226
|
-
if parent !=
|
2227
|
-
|
2228
|
-
|
2229
|
-
parent = normalized_path[/\/([^\/]+)\/\.\.$/, 1]
|
2230
|
-
if parent != "." && parent != ".."
|
2231
|
-
normalized_path.gsub!(/\/#{parent}\/\.\.$/, "/")
|
2196
|
+
mod = nil
|
2197
|
+
mod ||= normalized_path.gsub!(NPATH1, SLASH)
|
2198
|
+
|
2199
|
+
parent = normalized_path.match(NPATH2)
|
2200
|
+
if parent && ((parent[1] != PARENT1 && parent[1] != PARENT2) \
|
2201
|
+
|| (parent[2] != PARENT1 && parent[2] != PARENT2))
|
2202
|
+
mod ||= normalized_path.gsub!(/\/#{parent[1]}\/\.\.\/|(\/#{parent[2]}\/\.\.$)/, SLASH)
|
2232
2203
|
end
|
2233
|
-
normalized_path.gsub!(/^\.\.?\/?/, "")
|
2234
|
-
normalized_path.gsub!(/^\/\.\.?\//, "/")
|
2235
2204
|
|
2236
|
-
|
2237
|
-
normalized_path.gsub!(
|
2238
|
-
end until
|
2205
|
+
mod ||= normalized_path.gsub!(NPATH3, EMPTYSTR)
|
2206
|
+
mod ||= normalized_path.gsub!(NPATH4, SLASH)
|
2207
|
+
end until mod.nil?
|
2208
|
+
|
2239
2209
|
return normalized_path
|
2240
2210
|
end
|
2241
2211
|
|
@@ -2244,8 +2214,8 @@ module Addressable
|
|
2244
2214
|
def validate
|
2245
2215
|
return if !!@validation_deferred
|
2246
2216
|
if self.scheme != nil &&
|
2247
|
-
(self.host == nil || self.host
|
2248
|
-
(self.path == nil || self.path
|
2217
|
+
(self.host == nil || self.host.empty?) &&
|
2218
|
+
(self.path == nil || self.path.empty?)
|
2249
2219
|
raise InvalidURIError,
|
2250
2220
|
"Absolute URI missing hierarchical segment: '#{self.to_s}'"
|
2251
2221
|
end
|
@@ -2256,7 +2226,7 @@ module Addressable
|
|
2256
2226
|
raise InvalidURIError, "Hostname not supplied: '#{self.to_s}'"
|
2257
2227
|
end
|
2258
2228
|
end
|
2259
|
-
if self.path != nil && self.path
|
2229
|
+
if self.path != nil && !self.path.empty? && self.path[0..0] != SLASH &&
|
2260
2230
|
self.authority != nil
|
2261
2231
|
raise InvalidURIError,
|
2262
2232
|
"Cannot have a relative path with an authority set: '#{self.to_s}'"
|