diff --git a/lib/mail/elements/received_element.rb b/lib/mail/elements/received_element.rb index b9198ec64..0f55cfb2f 100644 --- a/lib/mail/elements/received_element.rb +++ b/lib/mail/elements/received_element.rb @@ -25,11 +25,11 @@ def to_s(*args) private def datetime_for(received) - ::DateTime.parse("#{received.date} #{received.time}") - rescue ArgumentError => e - raise e unless e.message == 'invalid date' - warn "WARNING: Invalid date field for received element (#{received.date} #{received.time}): #{e.class}: #{e.message}" - nil + Utilities.parse_date_time("#{received.date} #{received.time}").tap do |datetime| + unless datetime + warn "WARNING: Invalid date field for received element (#{received.date} #{received.time})" + end + end end end end diff --git a/lib/mail/fields/common_date_field.rb b/lib/mail/fields/common_date_field.rb index 0c98db05d..2be89ec49 100644 --- a/lib/mail/fields/common_date_field.rb +++ b/lib/mail/fields/common_date_field.rb @@ -2,26 +2,24 @@ module Mail class CommonDateField < NamedStructuredField #:nodoc: - def self.singular? - true - end + class << self + def singular? + true + end - def self.normalize_datetime(string) - if Utilities.blank?(string) - datetime = ::DateTime.now - else - stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ') - begin - datetime = ::DateTime.parse(stripped) - rescue ArgumentError => e - raise unless 'invalid date' == e.message + def normalize_datetime(string) + if Utilities.blank?(string) + datetime = ::DateTime.now + else + stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ') + datetime = Utilities.parse_date_time(stripped) end - end - if datetime - datetime.strftime('%a, %d %b %Y %H:%M:%S %z') - else - string + if datetime + datetime.strftime('%a, %d %b %Y %H:%M:%S %z') + else + string + end end end @@ -31,9 +29,7 @@ def initialize(value = nil, charset = nil) # Returns a date time object of the parsed date def date_time - ::DateTime.parse("#{element.date_string} #{element.time_string}") - rescue ArgumentError => e - raise e unless e.message == 'invalid date' + Utilities.parse_date_time("#{element.date_string} #{element.time_string}") end def default diff --git a/lib/mail/utilities.rb b/lib/mail/utilities.rb index b17117c67..5b47e5ee5 100644 --- a/lib/mail/utilities.rb +++ b/lib/mail/utilities.rb @@ -222,6 +222,21 @@ def underscoreize( str ) str.to_s.downcase.tr(Constants::HYPHEN, Constants::UNDERSCORE) end + # Parses a string into a DateTime object, returning nil + # if the string provided is not a valid date or if its + # size exceeds Ruby's default input length limit for + # parsing dates + # + # Example: + # + # DateTime.parse("2022-12-07 20:57:43 +0100") #=> + # DateTime.parse("invalid") #=> nil + def parse_date_time(string) + ::DateTime.parse(string) + rescue ArgumentError => e + raise unless e.message =~ /\A(invalid date|string length \(\d+\) exceeds the limit \d+)\z/ + end + def map_lines( str, &block ) str.each_line.map(&block) end diff --git a/spec/mail/fields/date_field_spec.rb b/spec/mail/fields/date_field_spec.rb index ed15a420a..86a4d59f3 100644 --- a/spec/mail/fields/date_field_spec.rb +++ b/spec/mail/fields/date_field_spec.rb @@ -66,5 +66,11 @@ field = Mail::DateField.new("12 Aug 2009 30:00:02 GMT") expect(field.date_time).to be_nil end + + it "should handle too long invalid date" do + # field = Mail::DateField.new("12 Aug 2009 30:00:02 GMT") + field = Mail::DateField.new("Wed, 23 Jan 2019 30:51:32 -0500") + expect(field.date_time).to be_nil + end end end diff --git a/spec/mail/fields/received_field_spec.rb b/spec/mail/fields/received_field_spec.rb index edfd460e1..f0670fff8 100644 --- a/spec/mail/fields/received_field_spec.rb +++ b/spec/mail/fields/received_field_spec.rb @@ -55,4 +55,13 @@ expect(t.date_time).to eq nil expect(t.formatted_date).to eq nil end + + it "should handle too long invalid date" do + t = Mail::ReceivedField.new("mail.example.com (192.168.1.1) by mail.example.com with (esmtp) id (qid) for ; Mon, (envelope-from ) 29 Jul 2013 23:12:46 +0900") + + expect(t.name).to eq "Received" + expect(t.info).to eq "mail.example.com (192.168.1.1) by mail.example.com with (esmtp) id (qid) for " + expect(t.date_time).to eq nil + expect(t.formatted_date).to eq nil + end end