addressable 2.6.0 → 2.8.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 }