addressable 2.6.0 → 2.8.1

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.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # encoding:utf-8
4
3
  #--
5
4
  # Copyright (C) Bob Aman
6
5
  #
@@ -38,20 +37,35 @@ module Addressable
38
37
  ##
39
38
  # Container for the character classes specified in
40
39
  # <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
40
+ #
41
+ # Note: Concatenated and interpolated `String`s are not affected by the
42
+ # `frozen_string_literal` directive and must be frozen explicitly.
43
+ #
44
+ # Interpolated `String`s *were* frozen this way before Ruby 3.0:
45
+ # https://bugs.ruby-lang.org/issues/17104
41
46
  module CharacterClasses
42
47
  ALPHA = "a-zA-Z"
43
48
  DIGIT = "0-9"
44
49
  GEN_DELIMS = "\\:\\/\\?\\#\\[\\]\\@"
45
50
  SUB_DELIMS = "\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\="
46
- RESERVED = GEN_DELIMS + SUB_DELIMS
47
- UNRESERVED = ALPHA + DIGIT + "\\-\\.\\_\\~"
48
- PCHAR = UNRESERVED + SUB_DELIMS + "\\:\\@"
49
- SCHEME = ALPHA + DIGIT + "\\-\\+\\."
50
- HOST = UNRESERVED + SUB_DELIMS + "\\[\\:\\]"
51
- AUTHORITY = PCHAR
52
- PATH = PCHAR + "\\/"
53
- QUERY = PCHAR + "\\/\\?"
54
- FRAGMENT = PCHAR + "\\/\\?"
51
+ RESERVED = (GEN_DELIMS + SUB_DELIMS).freeze
52
+ UNRESERVED = (ALPHA + DIGIT + "\\-\\.\\_\\~").freeze
53
+ PCHAR = (UNRESERVED + SUB_DELIMS + "\\:\\@").freeze
54
+ SCHEME = (ALPHA + DIGIT + "\\-\\+\\.").freeze
55
+ HOST = (UNRESERVED + SUB_DELIMS + "\\[\\:\\]").freeze
56
+ AUTHORITY = (PCHAR + "\\[\\:\\]").freeze
57
+ PATH = (PCHAR + "\\/").freeze
58
+ QUERY = (PCHAR + "\\/\\?").freeze
59
+ FRAGMENT = (PCHAR + "\\/\\?").freeze
60
+ end
61
+
62
+ module NormalizeCharacterClasses
63
+ HOST = /[^#{CharacterClasses::HOST}]/
64
+ UNRESERVED = /[^#{CharacterClasses::UNRESERVED}]/
65
+ PCHAR = /[^#{CharacterClasses::PCHAR}]/
66
+ SCHEME = /[^#{CharacterClasses::SCHEME}]/
67
+ FRAGMENT = /[^#{CharacterClasses::FRAGMENT}]/
68
+ QUERY = %r{[^a-zA-Z0-9\-\.\_\~\!\$\'\(\)\*\+\,\=\:\@\/\?%]|%(?!2B|2b)}
55
69
  end
56
70
 
57
71
  SLASH = '/'
@@ -73,7 +87,7 @@ module Addressable
73
87
  "wais" => 210,
74
88
  "ldap" => 389,
75
89
  "prospero" => 1525
76
- }
90
+ }.freeze
77
91
 
78
92
  ##
79
93
  # Returns a URI object based on the parsed string.
@@ -207,7 +221,7 @@ module Addressable
207
221
  fragments = match.captures
208
222
  authority = fragments[3]
209
223
  if authority && authority.length > 0
210
- new_authority = authority.gsub(/\\/, '/').gsub(/ /, '%20')
224
+ new_authority = authority.tr("\\", "/").gsub(" ", "%20")
211
225
  # NOTE: We want offset 4, not 3!
212
226
  offset = match.offset(4)
213
227
  uri = uri.dup
@@ -218,8 +232,9 @@ module Addressable
218
232
  parsed = self.parse(hints[:scheme] + "://" + uri)
219
233
  end
220
234
  if parsed.path.include?(".")
221
- new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
222
- if new_host
235
+ if parsed.path[/\b@\b/]
236
+ parsed.scheme = "mailto" unless parsed.scheme
237
+ elsif new_host = parsed.path[/^([^\/]+\.[^\/]*)/, 1]
223
238
  parsed.defer_validation do
224
239
  new_path = parsed.path.sub(
225
240
  Regexp.new("^" + Regexp.escape(new_host)), EMPTY_STR)
@@ -281,15 +296,15 @@ module Addressable
281
296
  uri.path.sub!(/^\/?([a-zA-Z])[\|:][\\\/]/) do
282
297
  "/#{$1.downcase}:/"
283
298
  end
284
- uri.path.gsub!(/\\/, SLASH)
299
+ uri.path.tr!("\\", SLASH)
285
300
  if File.exist?(uri.path) &&
286
301
  File.stat(uri.path).directory?
287
- uri.path.sub!(/\/$/, EMPTY_STR)
302
+ uri.path.chomp!(SLASH)
288
303
  uri.path = uri.path + '/'
289
304
  end
290
305
 
291
306
  # If the path is absolute, set the scheme and host.
292
- if uri.path =~ /^\//
307
+ if uri.path.start_with?(SLASH)
293
308
  uri.scheme = "file"
294
309
  uri.host = EMPTY_STR
295
310
  end
@@ -326,6 +341,21 @@ module Addressable
326
341
  return result
327
342
  end
328
343
 
344
+ ##
345
+ # Tables used to optimize encoding operations in `self.encode_component`
346
+ # and `self.normalize_component`
347
+ SEQUENCE_ENCODING_TABLE = Hash.new do |hash, sequence|
348
+ hash[sequence] = sequence.unpack("C*").map do |c|
349
+ format("%02x", c)
350
+ end.join
351
+ end
352
+
353
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE = Hash.new do |hash, sequence|
354
+ hash[sequence] = sequence.unpack("C*").map do |c|
355
+ format("%%%02X", c)
356
+ end.join
357
+ end
358
+
329
359
  ##
330
360
  # Percent encodes a URI component.
331
361
  #
@@ -392,18 +422,20 @@ module Addressable
392
422
  component.force_encoding(Encoding::ASCII_8BIT)
393
423
  # Avoiding gsub! because there are edge cases with frozen strings
394
424
  component = component.gsub(character_class) do |sequence|
395
- (sequence.unpack('C*').map { |c| "%" + ("%02x" % c).upcase }).join
425
+ SEQUENCE_UPCASED_PERCENT_ENCODING_TABLE[sequence]
396
426
  end
397
427
  if upcase_encoded.length > 0
398
- component = component.gsub(/%(#{upcase_encoded.chars.map do |char|
399
- char.unpack('C*').map { |c| '%02x' % c }.join
400
- end.join('|')})/i) { |s| s.upcase }
428
+ upcase_encoded_chars = upcase_encoded.chars.map do |char|
429
+ SEQUENCE_ENCODING_TABLE[char]
430
+ end
431
+ component = component.gsub(/%(#{upcase_encoded_chars.join('|')})/,
432
+ &:upcase)
401
433
  end
402
434
  return component
403
435
  end
404
436
 
405
437
  class << self
406
- alias_method :encode_component, :encode_component
438
+ alias_method :escape_component, :encode_component
407
439
  end
408
440
 
409
441
  ##
@@ -442,15 +474,13 @@ module Addressable
442
474
  "Expected Class (String or Addressable::URI), " +
443
475
  "got #{return_type.inspect}"
444
476
  end
445
- uri = uri.dup
446
- # Seriously, only use UTF-8. I'm really not kidding!
447
- uri.force_encoding("utf-8")
448
- leave_encoded = leave_encoded.dup.force_encoding("utf-8")
449
- result = uri.gsub(/%[0-9a-f]{2}/iu) do |sequence|
477
+
478
+ result = uri.gsub(/%[0-9a-f]{2}/i) do |sequence|
450
479
  c = sequence[1..3].to_i(16).chr
451
- c.force_encoding("utf-8")
480
+ c.force_encoding(sequence.encoding)
452
481
  leave_encoded.include?(c) ? sequence : c
453
482
  end
483
+
454
484
  result.force_encoding("utf-8")
455
485
  if return_type == String
456
486
  return result
@@ -530,13 +560,17 @@ module Addressable
530
560
  leave_re = if leave_encoded.length > 0
531
561
  character_class = "#{character_class}%" unless character_class.include?('%')
532
562
 
533
- "|%(?!#{leave_encoded.chars.map do |char|
534
- seq = char.unpack('C*').map { |c| '%02x' % c }.join
563
+ "|%(?!#{leave_encoded.chars.flat_map do |char|
564
+ seq = SEQUENCE_ENCODING_TABLE[char]
535
565
  [seq.upcase, seq.downcase]
536
- end.flatten.join('|')})"
566
+ end.join('|')})"
537
567
  end
538
568
 
539
- character_class = /[^#{character_class}]#{leave_re}/
569
+ character_class = if leave_re
570
+ /[^#{character_class}]#{leave_re}/
571
+ else
572
+ /[^#{character_class}]/
573
+ end
540
574
  end
541
575
  # We can't perform regexps on invalid UTF sequences, but
542
576
  # here we need to, so switch to ASCII.
@@ -860,12 +894,12 @@ module Addressable
860
894
  else
861
895
  Addressable::URI.normalize_component(
862
896
  self.scheme.strip.downcase,
863
- Addressable::URI::CharacterClasses::SCHEME
897
+ Addressable::URI::NormalizeCharacterClasses::SCHEME
864
898
  )
865
899
  end
866
900
  end
867
901
  # All normalized values should be UTF-8
868
- @normalized_scheme.force_encoding(Encoding::UTF_8) if @normalized_scheme
902
+ force_utf8_encoding_if_needed(@normalized_scheme)
869
903
  @normalized_scheme
870
904
  end
871
905
 
@@ -880,7 +914,7 @@ module Addressable
880
914
  new_scheme = new_scheme.to_str
881
915
  end
882
916
  if new_scheme && new_scheme !~ /\A[a-z][a-z0-9\.\+\-]*\z/i
883
- raise InvalidURIError, "Invalid scheme format: #{new_scheme}"
917
+ raise InvalidURIError, "Invalid scheme format: '#{new_scheme}'"
884
918
  end
885
919
  @scheme = new_scheme
886
920
  @scheme = nil if @scheme.to_s.strip.empty?
@@ -915,12 +949,12 @@ module Addressable
915
949
  else
916
950
  Addressable::URI.normalize_component(
917
951
  self.user.strip,
918
- Addressable::URI::CharacterClasses::UNRESERVED
952
+ Addressable::URI::NormalizeCharacterClasses::UNRESERVED
919
953
  )
920
954
  end
921
955
  end
922
956
  # All normalized values should be UTF-8
923
- @normalized_user.force_encoding(Encoding::UTF_8) if @normalized_user
957
+ force_utf8_encoding_if_needed(@normalized_user)
924
958
  @normalized_user
925
959
  end
926
960
 
@@ -972,14 +1006,12 @@ module Addressable
972
1006
  else
973
1007
  Addressable::URI.normalize_component(
974
1008
  self.password.strip,
975
- Addressable::URI::CharacterClasses::UNRESERVED
1009
+ Addressable::URI::NormalizeCharacterClasses::UNRESERVED
976
1010
  )
977
1011
  end
978
1012
  end
979
1013
  # All normalized values should be UTF-8
980
- if @normalized_password
981
- @normalized_password.force_encoding(Encoding::UTF_8)
982
- end
1014
+ force_utf8_encoding_if_needed(@normalized_password)
983
1015
  @normalized_password
984
1016
  end
985
1017
 
@@ -1047,9 +1079,7 @@ module Addressable
1047
1079
  end
1048
1080
  end
1049
1081
  # All normalized values should be UTF-8
1050
- if @normalized_userinfo
1051
- @normalized_userinfo.force_encoding(Encoding::UTF_8)
1052
- end
1082
+ force_utf8_encoding_if_needed(@normalized_userinfo)
1053
1083
  @normalized_userinfo
1054
1084
  end
1055
1085
 
@@ -1096,6 +1126,7 @@ module Addressable
1096
1126
  # @return [String] The host component, normalized.
1097
1127
  def normalized_host
1098
1128
  return nil unless self.host
1129
+
1099
1130
  @normalized_host ||= begin
1100
1131
  if !self.host.strip.empty?
1101
1132
  result = ::Addressable::IDNA.to_ascii(
@@ -1107,14 +1138,15 @@ module Addressable
1107
1138
  end
1108
1139
  result = Addressable::URI.normalize_component(
1109
1140
  result,
1110
- CharacterClasses::HOST)
1141
+ NormalizeCharacterClasses::HOST
1142
+ )
1111
1143
  result
1112
1144
  else
1113
1145
  EMPTY_STR.dup
1114
1146
  end
1115
1147
  end
1116
1148
  # All normalized values should be UTF-8
1117
- @normalized_host.force_encoding(Encoding::UTF_8) if @normalized_host
1149
+ force_utf8_encoding_if_needed(@normalized_host)
1118
1150
  @normalized_host
1119
1151
  end
1120
1152
 
@@ -1172,7 +1204,7 @@ module Addressable
1172
1204
  # Returns the top-level domain for this host.
1173
1205
  #
1174
1206
  # @example
1175
- # Addressable::URI.parse("www.example.co.uk").tld # => "co.uk"
1207
+ # Addressable::URI.parse("http://www.example.co.uk").tld # => "co.uk"
1176
1208
  def tld
1177
1209
  PublicSuffix.parse(self.host, ignore_private: true).tld
1178
1210
  end
@@ -1182,7 +1214,7 @@ module Addressable
1182
1214
  #
1183
1215
  # @param [String, #to_str] new_tld The new top-level domain.
1184
1216
  def tld=(new_tld)
1185
- replaced_tld = domain.sub(/#{tld}\z/, new_tld)
1217
+ replaced_tld = host.sub(/#{tld}\z/, new_tld)
1186
1218
  self.host = PublicSuffix::Domain.new(replaced_tld).to_s
1187
1219
  end
1188
1220
 
@@ -1190,7 +1222,7 @@ module Addressable
1190
1222
  # Returns the public suffix domain for this host.
1191
1223
  #
1192
1224
  # @example
1193
- # Addressable::URI.parse("www.example.co.uk").domain # => "example.co.uk"
1225
+ # Addressable::URI.parse("http://www.example.co.uk").domain # => "example.co.uk"
1194
1226
  def domain
1195
1227
  PublicSuffix.domain(self.host, ignore_private: true)
1196
1228
  end
@@ -1232,9 +1264,7 @@ module Addressable
1232
1264
  authority
1233
1265
  end
1234
1266
  # All normalized values should be UTF-8
1235
- if @normalized_authority
1236
- @normalized_authority.force_encoding(Encoding::UTF_8)
1237
- end
1267
+ force_utf8_encoding_if_needed(@normalized_authority)
1238
1268
  @normalized_authority
1239
1269
  end
1240
1270
 
@@ -1468,7 +1498,7 @@ module Addressable
1468
1498
  site_string
1469
1499
  end
1470
1500
  # All normalized values should be UTF-8
1471
- @normalized_site.force_encoding(Encoding::UTF_8) if @normalized_site
1501
+ force_utf8_encoding_if_needed(@normalized_site)
1472
1502
  @normalized_site
1473
1503
  end
1474
1504
 
@@ -1519,7 +1549,7 @@ module Addressable
1519
1549
  result = path.strip.split(SLASH, -1).map do |segment|
1520
1550
  Addressable::URI.normalize_component(
1521
1551
  segment,
1522
- Addressable::URI::CharacterClasses::PCHAR
1552
+ Addressable::URI::NormalizeCharacterClasses::PCHAR
1523
1553
  )
1524
1554
  end.join(SLASH)
1525
1555
 
@@ -1531,7 +1561,7 @@ module Addressable
1531
1561
  result
1532
1562
  end
1533
1563
  # All normalized values should be UTF-8
1534
- @normalized_path.force_encoding(Encoding::UTF_8) if @normalized_path
1564
+ force_utf8_encoding_if_needed(@normalized_path)
1535
1565
  @normalized_path
1536
1566
  end
1537
1567
 
@@ -1594,15 +1624,20 @@ module Addressable
1594
1624
  modified_query_class = Addressable::URI::CharacterClasses::QUERY.dup
1595
1625
  # Make sure possible key-value pair delimiters are escaped.
1596
1626
  modified_query_class.sub!("\\&", "").sub!("\\;", "")
1597
- pairs = (self.query || "").split("&", -1)
1627
+ pairs = (query || "").split("&", -1)
1628
+ pairs.delete_if(&:empty?).uniq! if flags.include?(:compacted)
1598
1629
  pairs.sort! if flags.include?(:sorted)
1599
1630
  component = pairs.map do |pair|
1600
- Addressable::URI.normalize_component(pair, modified_query_class, "+")
1631
+ Addressable::URI.normalize_component(
1632
+ pair,
1633
+ Addressable::URI::NormalizeCharacterClasses::QUERY,
1634
+ "+"
1635
+ )
1601
1636
  end.join("&")
1602
1637
  component == "" ? nil : component
1603
1638
  end
1604
1639
  # All normalized values should be UTF-8
1605
- @normalized_query.force_encoding(Encoding::UTF_8) if @normalized_query
1640
+ force_utf8_encoding_if_needed(@normalized_query)
1606
1641
  @normalized_query
1607
1642
  end
1608
1643
 
@@ -1656,11 +1691,13 @@ module Addressable
1656
1691
  # so it's best to make all changes in-place.
1657
1692
  pair[0] = URI.unencode_component(pair[0])
1658
1693
  if pair[1].respond_to?(:to_str)
1694
+ value = pair[1].to_str
1659
1695
  # I loathe the fact that I have to do this. Stupid HTML 4.01.
1660
1696
  # Treating '+' as a space was just an unbelievably bad idea.
1661
1697
  # There was nothing wrong with '%20'!
1662
1698
  # If it ain't broke, don't fix it!
1663
- pair[1] = URI.unencode_component(pair[1].to_str.gsub(/\+/, " "))
1699
+ value = value.tr("+", " ") if ["http", "https", nil].include?(scheme)
1700
+ pair[1] = URI.unencode_component(value)
1664
1701
  end
1665
1702
  if return_type == Hash
1666
1703
  accu[pair[0]] = pair[1]
@@ -1791,14 +1828,12 @@ module Addressable
1791
1828
  @normalized_fragment ||= begin
1792
1829
  component = Addressable::URI.normalize_component(
1793
1830
  self.fragment,
1794
- Addressable::URI::CharacterClasses::FRAGMENT
1831
+ Addressable::URI::NormalizeCharacterClasses::FRAGMENT
1795
1832
  )
1796
1833
  component == "" ? nil : component
1797
1834
  end
1798
1835
  # All normalized values should be UTF-8
1799
- if @normalized_fragment
1800
- @normalized_fragment.force_encoding(Encoding::UTF_8)
1801
- end
1836
+ force_utf8_encoding_if_needed(@normalized_fragment)
1802
1837
  @normalized_fragment
1803
1838
  end
1804
1839
 
@@ -1917,7 +1952,7 @@ module Addressable
1917
1952
  # Section 5.2.3 of RFC 3986
1918
1953
  #
1919
1954
  # Removes the right-most path segment from the base path.
1920
- if base_path =~ /\//
1955
+ if base_path.include?(SLASH)
1921
1956
  base_path.sub!(/\/[^\/]+$/, SLASH)
1922
1957
  else
1923
1958
  base_path = EMPTY_STR
@@ -2367,10 +2402,10 @@ module Addressable
2367
2402
  #
2368
2403
  # @param [Proc] block
2369
2404
  # A set of operations to perform on a given URI.
2370
- def defer_validation(&block)
2371
- raise LocalJumpError, "No block given." unless block
2405
+ def defer_validation
2406
+ raise LocalJumpError, "No block given." unless block_given?
2372
2407
  @validation_deferred = true
2373
- block.call()
2408
+ yield
2374
2409
  @validation_deferred = false
2375
2410
  validate
2376
2411
  return nil
@@ -2394,30 +2429,35 @@ module Addressable
2394
2429
  def self.normalize_path(path)
2395
2430
  # Section 5.2.4 of RFC 3986
2396
2431
 
2397
- return nil if path.nil?
2432
+ return if path.nil?
2398
2433
  normalized_path = path.dup
2399
- begin
2400
- mod = nil
2434
+ loop do
2401
2435
  mod ||= normalized_path.gsub!(RULE_2A, SLASH)
2402
2436
 
2403
2437
  pair = normalized_path.match(RULE_2B_2C)
2404
- parent, current = pair[1], pair[2] if pair
2438
+ if pair
2439
+ parent = pair[1]
2440
+ current = pair[2]
2441
+ else
2442
+ parent = nil
2443
+ current = nil
2444
+ end
2445
+
2446
+ regexp = "/#{Regexp.escape(parent.to_s)}/\\.\\./|"
2447
+ regexp += "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2448
+
2405
2449
  if pair && ((parent != SELF_REF && parent != PARENT) ||
2406
2450
  (current != SELF_REF && current != PARENT))
2407
- mod ||= normalized_path.gsub!(
2408
- Regexp.new(
2409
- "/#{Regexp.escape(parent.to_s)}/\\.\\./|" +
2410
- "(/#{Regexp.escape(current.to_s)}/\\.\\.$)"
2411
- ), SLASH
2412
- )
2451
+ mod ||= normalized_path.gsub!(Regexp.new(regexp), SLASH)
2413
2452
  end
2414
2453
 
2415
2454
  mod ||= normalized_path.gsub!(RULE_2D, EMPTY_STR)
2416
2455
  # Non-standard, removes prefixed dotted segments from path.
2417
2456
  mod ||= normalized_path.gsub!(RULE_PREFIXED_PARENT, SLASH)
2418
- end until mod.nil?
2457
+ break if mod.nil?
2458
+ end
2419
2459
 
2420
- return normalized_path
2460
+ normalized_path
2421
2461
  end
2422
2462
 
2423
2463
  ##
@@ -2506,5 +2546,15 @@ module Addressable
2506
2546
  remove_instance_variable(:@uri_string) if defined?(@uri_string)
2507
2547
  remove_instance_variable(:@hash) if defined?(@hash)
2508
2548
  end
2549
+
2550
+ ##
2551
+ # Converts the string to be UTF-8 if it is not already UTF-8
2552
+ #
2553
+ # @api private
2554
+ def force_utf8_encoding_if_needed(str)
2555
+ if str && str.encoding != Encoding::UTF_8
2556
+ str.force_encoding(Encoding::UTF_8)
2557
+ end
2558
+ end
2509
2559
  end
2510
2560
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # encoding:utf-8
4
3
  #--
5
4
  # Copyright (C) Bob Aman
6
5
  #
@@ -23,8 +22,8 @@ if !defined?(Addressable::VERSION)
23
22
  module Addressable
24
23
  module VERSION
25
24
  MAJOR = 2
26
- MINOR = 6
27
- TINY = 0
25
+ MINOR = 8
26
+ TINY = 1
28
27
 
29
28
  STRING = [MAJOR, MINOR, TINY].join('.')
30
29
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # coding: utf-8
4
3
  # Copyright (C) Bob Aman
5
4
  #
6
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -294,7 +293,9 @@ begin
294
293
  it_should_behave_like "converting from unicode to ASCII"
295
294
  it_should_behave_like "converting from ASCII to unicode"
296
295
  end
297
- rescue LoadError
296
+ rescue LoadError => error
297
+ raise error if ENV["CI"] && TestHelper.native_supported?
298
+
298
299
  # Cannot test the native implementation without libidn support.
299
300
  warn('Could not load native IDN implementation.')
300
301
  end
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # coding: utf-8
4
3
  # Copyright (C) Bob Aman
5
4
  #
6
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # coding: utf-8
4
3
  # Copyright (C) Bob Aman
5
4
  #
6
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # coding: utf-8
4
3
  # Copyright (C) Bob Aman
5
4
  #
6
5
  # Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,6 +18,7 @@
19
18
  require "spec_helper"
20
19
 
21
20
  require "bigdecimal"
21
+ require "timeout"
22
22
  require "addressable/template"
23
23
 
24
24
  shared_examples_for 'expands' do |tests|
@@ -77,6 +77,15 @@ describe "==" do
77
77
  end
78
78
  end
79
79
 
80
+ describe "#to_regexp" do
81
+ it "does not match the first line of multiline strings" do
82
+ uri = "https://www.example.com/bar"
83
+ template = Addressable::Template.new(uri)
84
+ expect(template.match(uri)).not_to be_nil
85
+ expect(template.match("#{uri}\ngarbage")).to be_nil
86
+ end
87
+ end
88
+
80
89
  describe "Type conversion" do
81
90
  subject {
82
91
  {
@@ -1340,6 +1349,14 @@ describe Addressable::Template do
1340
1349
  expect(subject).not_to match("foo_bar*")
1341
1350
  expect(subject).not_to match("foo_bar:20")
1342
1351
  end
1352
+
1353
+ it 'should parse in a reasonable time' do
1354
+ expect do
1355
+ Timeout.timeout(0.1) do
1356
+ expect(subject).not_to match("0"*25 + "!")
1357
+ end
1358
+ end.not_to raise_error
1359
+ end
1343
1360
  end
1344
1361
  context "VARIABLE_LIST" do
1345
1362
  subject { Addressable::Template::VARIABLE_LIST }