| | | 1 | | // Licensed to the .NET Foundation under one or more agreements. |
| | | 2 | | // The .NET Foundation licenses this file to you under the MIT license. |
| | | 3 | | |
| | | 4 | | using System.Globalization; |
| | | 5 | | |
| | | 6 | | namespace System.Net |
| | | 7 | | { |
| | | 8 | | internal static class HttpDateParser |
| | | 9 | | { |
| | 1 | 10 | | private static readonly string[] s_dateFormats = new string[] { |
| | 1 | 11 | | // "r", // RFC 1123, required output format but too strict for input |
| | 1 | 12 | | "ddd, d MMM yyyy H:m:s 'GMT'", // RFC 1123 (r, except it allows both 1 and 01 for date and time) |
| | 1 | 13 | | "ddd, d MMM yyyy H:m:s 'UTC'", // RFC 1123, UTC |
| | 1 | 14 | | "ddd, d MMM yyyy H:m:s", // RFC 1123, no zone - assume GMT |
| | 1 | 15 | | "d MMM yyyy H:m:s 'GMT'", // RFC 1123, no day-of-week |
| | 1 | 16 | | "d MMM yyyy H:m:s 'UTC'", // RFC 1123, UTC, no day-of-week |
| | 1 | 17 | | "d MMM yyyy H:m:s", // RFC 1123, no day-of-week, no zone |
| | 1 | 18 | | "ddd, d MMM yy H:m:s 'GMT'", // RFC 1123, short year |
| | 1 | 19 | | "ddd, d MMM yy H:m:s 'UTC'", // RFC 1123, UTC, short year |
| | 1 | 20 | | "ddd, d MMM yy H:m:s", // RFC 1123, short year, no zone |
| | 1 | 21 | | "d MMM yy H:m:s 'GMT'", // RFC 1123, no day-of-week, short year |
| | 1 | 22 | | "d MMM yy H:m:s 'UTC'", // RFC 1123, UTC, no day-of-week, short year |
| | 1 | 23 | | "d MMM yy H:m:s", // RFC 1123, no day-of-week, short year, no zone |
| | 1 | 24 | | |
| | 1 | 25 | | "dddd, d'-'MMM'-'yy H:m:s 'GMT'", // RFC 850 |
| | 1 | 26 | | "dddd, d'-'MMM'-'yy H:m:s 'UTC'", // RFC 850, UTC |
| | 1 | 27 | | "dddd, d'-'MMM'-'yy H:m:s zzz", // RFC 850, offset |
| | 1 | 28 | | "dddd, d'-'MMM'-'yy H:m:s", // RFC 850 no zone |
| | 1 | 29 | | "ddd MMM d H:m:s yyyy", // ANSI C's asctime() format |
| | 1 | 30 | | |
| | 1 | 31 | | "ddd, d MMM yyyy H:m:s zzz", // RFC 5322 |
| | 1 | 32 | | "ddd, d MMM yyyy H:m:s", // RFC 5322 no zone |
| | 1 | 33 | | "d MMM yyyy H:m:s zzz", // RFC 5322 no day-of-week |
| | 1 | 34 | | "d MMM yyyy H:m:s", // RFC 5322 no day-of-week, no zone |
| | 1 | 35 | | }; |
| | | 36 | | |
| | | 37 | | internal static bool TryParse(ReadOnlySpan<char> input, out DateTimeOffset result) |
| | 96 | 38 | | { |
| | | 39 | | // None of the relevant patterns have whitespace at the beginning or end, so trim the input of |
| | | 40 | | // any whitespace. We can then use strict "r" matching, or if we have to fall back to trying |
| | | 41 | | // lots of patterns, only allow inner whitespace rather than leading or trailing whitespace. |
| | 96 | 42 | | input = input.Trim(); |
| | | 43 | | |
| | | 44 | | // First try strict parsing for "r" with no options, as it's an order of magnitude faster than general parsi |
| | | 45 | | // any individual format in s_dateFormats, allocation-free, and also likely to succeed. If it doesn't, then |
| | | 46 | | // fall back to trying each of the various date formats listed earlier, in order, to be accomodating and |
| | | 47 | | // accept a wide variety of old formats. |
| | 96 | 48 | | return |
| | 96 | 49 | | DateTimeOffset.TryParseExact(input, "r", DateTimeFormatInfo.InvariantInfo, DateTimeStyles.None, out resu |
| | 96 | 50 | | DateTimeOffset.TryParseExact(input, s_dateFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.Allo |
| | 96 | 51 | | } |
| | | 52 | | } |
| | | 53 | | } |