Skip to content

Commit 03c5cc8

Browse files
youdie006jeremyevans
authored andcommitted
Only allow "T" or a space as the RFC 3339 separator
Time.rfc3339's pattern used [T\s], so it accepted a tab, newline, vertical tab, form feed or carriage return between the date and the time. Time.xmlschema's pattern has a bare T. RFC 3339 section 5.6 defines the separator as "T" and only notes that an application may use a space for readability. The other \s characters are not permitted by either. Since Ruby 3.2 the pattern also disagrees with what the code does with the string it matched. _xmlschema hands it to Time.new, which rejects those five characters, so the documented ArgumentError never gets raised and Time.new's internal message escapes instead: Time.rfc3339("2011-10-05\t22:26:12Z") #=> ArgumentError: "+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" # expected for utc_offset: 22:26:12Z Narrowing the class to [T ] makes the pattern agree with the RFC, with Time.xmlschema, and with what _xmlschema can actually parse, so these inputs now raise "invalid rfc3339 format:" as documented.
1 parent 26d7190 commit 03c5cc8

2 files changed

Lines changed: 24 additions & 1 deletion

File tree

‎lib/time.rb‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ def xmlschema(time)
658658
def rfc3339(time)
659659
pattern = /\A\s*
660660
(-?\d{4})-(\d\d)-(\d\d)
661-
[T\s]
661+
[T ]
662662
(\d\d):(\d\d):(\d\d)
663663
(\.\d+)?
664664
(Z|[+-]\d\d:\d\d)

‎test/test_time.rb‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,29 @@ def test_huge_precision
607607
define_method(test.sub(/xmlschema/, 'rfc3339')) {__send__(sub, :rfc3339)}
608608
end
609609

610+
def test_rfc3339_separator
611+
# RFC 3339 section 5.6 defines the separator as "T", and only notes that an
612+
# application may use a space for readability. The other \s characters are
613+
# not permitted, and Time.xmlschema has never accepted any of them.
614+
t = Time.utc(2011, 10, 5, 22, 26, 12)
615+
assert_equal(t, Time.rfc3339("2011-10-05T22:26:12Z"))
616+
assert_equal(t, Time.rfc3339("2011-10-05 22:26:12Z"))
617+
618+
["\t", "\n", "\v", "\f", "\r"].each do |sep|
619+
s = "2011-10-05#{sep}22:26:12Z"
620+
e = assert_raise(ArgumentError, "separator #{sep.inspect}") { Time.rfc3339(s) }
621+
assert_match(/invalid rfc3339 format/, e.message, "separator #{sep.inspect}")
622+
end
623+
624+
# Time.xmlschema keeps rejecting every separator but "T".
625+
assert_equal(t, Time.xmlschema("2011-10-05T22:26:12Z"))
626+
["\t", "\n", "\v", "\f", "\r", " "].each do |sep|
627+
assert_raise(ArgumentError, "separator #{sep.inspect}") do
628+
Time.xmlschema("2011-10-05#{sep}22:26:12Z")
629+
end
630+
end
631+
end
632+
610633
def test_parse_with_various_object
611634
d = Date.new(2010, 10, 28)
612635
dt = DateTime.new(2010, 10, 28)

0 commit comments

Comments
 (0)