EWSoftware / PDI

A Personal Data Interchange (PDI) library that implements the vCard (RFC 2426), vCalendar, and iCalendar (RFC 2445) specifications including recurrence pattern generation
Microsoft Public License
64 stars 26 forks source link

Propose defensive code for dates outside range of System.DateTime #6

Closed patril closed 5 years ago

patril commented 7 years ago

We encountered an issue where Google calendar ICS data contained an event on 12/30/0000. We have no idea how this happened on Google's end, but it might have something to do with the fact that the event is recurring. We tried viewing the calendar several ways, but none of the ICS clients allows us to view that date to see the event. However, it always appears in the data, causing the parsing of the entire calendar to fail. Specifically, in EWSoftware.PDI.DateUtils.FromISO8601String(string, bool). convertedDate is set to new DateTime(year, month, day).

We'd like to propose skipping the event altogether if year/month/day would exceed DateTime.MinValue or DateTime.MaxValue. The event would not be available in the parsed calendar, but the alternative is the current exception that causes the entire calendar to fail. We would assume that any date outside the range of System.DateTime is bad data.

The specific VEVENT property that has a bad value is RECURRENCE-ID:

RECURRENCE-ID:00001230T040000Z

As a workaround, we're replacing all occurrences of RECURRENCE-ID:0000 with RECURRENCE-ID:1900 prior to calling EWSoftware.PDI.Parser.VCalendarParser.ParseFromString(string).

[xUnit.net 00:00:00.6249122]       EWSoftware.PDI.Parser.PDIParserException : Unexpected error while parsing PDI data stream
[xUnit.net 00:00:00.6255522]       ---- System.ArgumentOutOfRangeException : Year, Month, and Day parameters describe an un-representable DateTime.
[xUnit.net 00:00:00.6305786]         C:\Projects\EWSoftware\PDI\Source\EWSPDI\DateUtils.cs(752,0): at EWSoftware.PDI.DateUtils.FromISO8601String(String dateTimeText, Boolean toLocalTime)
[xUnit.net 00:00:00.6308781]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIProperties\BaseDateTimeProperty.cs(228,0): at EWSoftware.PDI.Properties.BaseDateTimeProperty.set_Value(String value)
[xUnit.net 00:00:00.6312581]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIProperties\BaseDateTimeProperty.cs(244,0): at EWSoftware.PDI.Properties.BaseDateTimeProperty.set_EncodedValue(String value)
[xUnit.net 00:00:00.6315817]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIParser\VCalendarParser.cs(893,0): at EWSoftware.PDI.Parser.VCalendarParser.VEventParser(String propertyName, StringCollection parameters, String propertyValue)
[xUnit.net 00:00:00.6318930]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIParser\VCalendarParser.cs(526,0): at EWSoftware.PDI.Parser.VCalendarParser.PropertyParser(String propertyName, StringCollection parameters, String propertyValue)
[xUnit.net 00:00:00.6326890]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIParser\PDIParser.cs(305,0): at EWSoftware.PDI.Parser.PDIParser.ProcessCharacter(Char ch)
[xUnit.net 00:00:00.6331422]         C:\Projects\EWSoftware\PDI\Source\EWSPDIData\PDIParser\PDIParser.cs(516,0): at EWSoftware.PDI.Parser.PDIParser.ParseReader(TextReader tr)
EWSoftware commented 7 years ago

I think it's probably better to range check the year value and adjust it if it's out of bounds. If the event is not wanted, it can be removed by the caller. With a date so low or high it likely won't show up on the calendar anyway unless the recurrence actually generates dates in the range you're looking at.