From 31272ab431d79e2dc63b80885ab82546210cd780 Mon Sep 17 00:00:00 2001 From: Richard Nguyen Date: Sun, 10 May 2020 23:57:17 -0700 Subject: [PATCH] Fix date format in headers to use 2-digit day of month (#10259) Motivation: `Date`, `Expires`, and `Set-Cookie` headers are being generated with a 1-digit day of month, e.g. `Sun, 6 Nov 1994 08:49:37 GMT`. RFC 2616 specifies that `Date` and `Expires` headers should use "a fixed-length subset of that defined by RFC 1123" which includes a 2-digit day of month. RFC6265 is lax in it's specification of the `Set-Cookie` header and permits a 2-digit day of month. See: https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html See: https://tools.ietf.org/html/rfc1123#page-55 See: https://tools.ietf.org/html/rfc6265#section-5.1.1 Modifications: - Update `DateFormatter` to correctly implement RFC 2616 headers Result: ``` Date: Sun, 06 Nov 1994 08:49:37 GMT Expires: Sun, 06 Nov 1994 08:49:37 GMT Set-Cookie: id=a3fWa; Expires=Sun, 06 Nov 1994 08:49:37 GMT ``` --- .../io/netty/handler/codec/DateFormatter.java | 8 +- .../handler/codec/DateFormatterTest.java | 91 ++++++++++--------- 2 files changed, 54 insertions(+), 45 deletions(-) diff --git a/codec/src/main/java/io/netty/handler/codec/DateFormatter.java b/codec/src/main/java/io/netty/handler/codec/DateFormatter.java index c1b5e46df6..dca6887f42 100644 --- a/codec/src/main/java/io/netty/handler/codec/DateFormatter.java +++ b/codec/src/main/java/io/netty/handler/codec/DateFormatter.java @@ -38,10 +38,12 @@ import java.util.TimeZone; * If you're looking for a date format that validates day of week, or supports other timezones, consider using * java.util.DateTimeFormatter.RFC_1123_DATE_TIME. * - * On the formatting side, it uses RFC1123 format. + * On the formatting side, it uses a subset of RFC1123 (2 digit day-of-month and 4 digit year) as per RFC2616. + * This subset supports RFC6265. * * @see RFC6265 for the parsing side - * @see RFC1123 for the encoding side. + * @see RFC1123 and + * RFC2616 for the encoding side. */ public final class DateFormatter { @@ -429,7 +431,7 @@ public final class DateFormatter { cal.setTime(date); sb.append(DAY_OF_WEEK_TO_SHORT_NAME[cal.get(Calendar.DAY_OF_WEEK) - 1]).append(", "); - sb.append(cal.get(Calendar.DAY_OF_MONTH)).append(' '); + appendZeroLeftPadded(cal.get(Calendar.DAY_OF_MONTH), sb).append(' '); sb.append(CALENDAR_MONTH_TO_SHORT_NAME[cal.get(Calendar.MONTH)]).append(' '); sb.append(cal.get(Calendar.YEAR)).append(' '); appendZeroLeftPadded(cal.get(Calendar.HOUR_OF_DAY), sb).append(':'); diff --git a/codec/src/test/java/io/netty/handler/codec/DateFormatterTest.java b/codec/src/test/java/io/netty/handler/codec/DateFormatterTest.java index e833fdfb60..6c1f5d09c6 100644 --- a/codec/src/test/java/io/netty/handler/codec/DateFormatterTest.java +++ b/codec/src/test/java/io/netty/handler/codec/DateFormatterTest.java @@ -43,90 +43,97 @@ public class DateFormatterTest { @Test public void testParseWithDashSeparatorSingleDigitDay() { - assertEquals(DATE, parseHttpDate("Sunday, 06-Nov-94 08:49:37 GMT")); - } - - @Test - public void testParseWithSingleDoubleDigitDay() { assertEquals(DATE, parseHttpDate("Sunday, 6-Nov-94 08:49:37 GMT")); } + @Test + public void testParseWithDashSeparatorDoubleDigitDay() { + assertEquals(DATE, parseHttpDate("Sunday, 06-Nov-94 08:49:37 GMT")); + } + @Test public void testParseWithoutGMT() { - assertEquals(DATE, parseHttpDate("Sun Nov 6 08:49:37 1994")); + assertEquals(DATE, parseHttpDate("Sun Nov 06 08:49:37 1994")); } @Test public void testParseWithFunkyTimezone() { - assertEquals(DATE, parseHttpDate("Sun Nov 6 08:49:37 1994 -0000")); + assertEquals(DATE, parseHttpDate("Sun Nov 06 08:49:37 1994 -0000")); } @Test public void testParseWithSingleDigitHourMinutesAndSecond() { - assertEquals(DATE, parseHttpDate("Sunday, 6-Nov-94 8:49:37 GMT")); + assertEquals(DATE, parseHttpDate("Sunday, 06-Nov-94 8:49:37 GMT")); } @Test public void testParseWithSingleDigitTime() { - assertEquals(DATE, parseHttpDate("Sunday, 6 Nov 1994 8:49:37 GMT")); + assertEquals(DATE, parseHttpDate("Sunday, 06 Nov 1994 8:49:37 GMT")); Date _08_09_37 = new Date(TIMESTAMP - 40 * 60 * 1000); - assertEquals(_08_09_37, parseHttpDate("Sunday, 6 Nov 1994 8:9:37 GMT")); - assertEquals(_08_09_37, parseHttpDate("Sunday, 6 Nov 1994 8:09:37 GMT")); + assertEquals(_08_09_37, parseHttpDate("Sunday, 06 Nov 1994 8:9:37 GMT")); + assertEquals(_08_09_37, parseHttpDate("Sunday, 06 Nov 1994 8:09:37 GMT")); Date _08_09_07 = new Date(TIMESTAMP - (40 * 60 + 30) * 1000); - assertEquals(_08_09_07, parseHttpDate("Sunday, 6 Nov 1994 8:9:7 GMT")); - assertEquals(_08_09_07, parseHttpDate("Sunday, 6 Nov 1994 8:9:07 GMT")); + assertEquals(_08_09_07, parseHttpDate("Sunday, 06 Nov 1994 8:9:7 GMT")); + assertEquals(_08_09_07, parseHttpDate("Sunday, 06 Nov 1994 8:9:07 GMT")); } @Test public void testParseMidnight() { - assertEquals(new Date(784080000000L), parseHttpDate("Sunday, 6 Nov 1994 00:00:00 GMT")); + assertEquals(new Date(784080000000L), parseHttpDate("Sunday, 06 Nov 1994 00:00:00 GMT")); } @Test public void testParseInvalidInput() { // missing field assertNull(parseHttpDate("Sun, Nov 1994 08:49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 1994 08:49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 08:49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 :49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08::37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08:49: GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08:49 GMT")); + assertNull(parseHttpDate("Sun, 06 1994 08:49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 08:49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 :49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08::37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08:49: GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08:49 GMT")); //invalid value - assertNull(parseHttpDate("Sun, 6 FOO 1994 08:49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 FOO 1994 08:49:37 GMT")); assertNull(parseHttpDate("Sun, 36 Nov 1994 08:49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 28:49:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08:69:37 GMT")); - assertNull(parseHttpDate("Sun, 6 Nov 1994 08:49:67 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 28:49:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08:69:37 GMT")); + assertNull(parseHttpDate("Sun, 06 Nov 1994 08:49:67 GMT")); //wrong number of digits in timestamp - assertNull(parseHttpDate("Sunday, 6 Nov 1994 0:0:000 GMT")); - assertNull(parseHttpDate("Sunday, 6 Nov 1994 0:000:0 GMT")); - assertNull(parseHttpDate("Sunday, 6 Nov 1994 000:0:0 GMT")); + assertNull(parseHttpDate("Sunday, 06 Nov 1994 0:0:000 GMT")); + assertNull(parseHttpDate("Sunday, 06 Nov 1994 0:000:0 GMT")); + assertNull(parseHttpDate("Sunday, 06 Nov 1994 000:0:0 GMT")); } @Test public void testFormat() { - assertEquals("Sun, 6 Nov 1994 08:49:37 GMT", format(DATE)); + assertEquals("Sun, 06 Nov 1994 08:49:37 GMT", format(DATE)); + } + + @Test + public void testAppend() { + StringBuilder sb = new StringBuilder(); + append(DATE, sb); + assertEquals("Sun, 06 Nov 1994 08:49:37 GMT", sb.toString()); } @Test public void testParseAllMonths() { - assertEquals(Calendar.JANUARY, getMonth(parseHttpDate("Sun, 6 Jan 1994 08:49:37 GMT"))); - assertEquals(Calendar.FEBRUARY, getMonth(parseHttpDate("Sun, 6 Feb 1994 08:49:37 GMT"))); - assertEquals(Calendar.MARCH, getMonth(parseHttpDate("Sun, 6 Mar 1994 08:49:37 GMT"))); - assertEquals(Calendar.APRIL, getMonth(parseHttpDate("Sun, 6 Apr 1994 08:49:37 GMT"))); - assertEquals(Calendar.MAY, getMonth(parseHttpDate("Sun, 6 May 1994 08:49:37 GMT"))); - assertEquals(Calendar.JUNE, getMonth(parseHttpDate("Sun, 6 Jun 1994 08:49:37 GMT"))); - assertEquals(Calendar.JULY, getMonth(parseHttpDate("Sun, 6 Jul 1994 08:49:37 GMT"))); - assertEquals(Calendar.AUGUST, getMonth(parseHttpDate("Sun, 6 Aug 1994 08:49:37 GMT"))); - assertEquals(Calendar.SEPTEMBER, getMonth(parseHttpDate("Sun, 6 Sep 1994 08:49:37 GMT"))); - assertEquals(Calendar.OCTOBER, getMonth(parseHttpDate("Sun Oct 6 08:49:37 1994"))); - assertEquals(Calendar.NOVEMBER, getMonth(parseHttpDate("Sun Nov 6 08:49:37 1994"))); - assertEquals(Calendar.DECEMBER, getMonth(parseHttpDate("Sun Dec 6 08:49:37 1994"))); + assertEquals(Calendar.JANUARY, getMonth(parseHttpDate("Sun, 06 Jan 1994 08:49:37 GMT"))); + assertEquals(Calendar.FEBRUARY, getMonth(parseHttpDate("Sun, 06 Feb 1994 08:49:37 GMT"))); + assertEquals(Calendar.MARCH, getMonth(parseHttpDate("Sun, 06 Mar 1994 08:49:37 GMT"))); + assertEquals(Calendar.APRIL, getMonth(parseHttpDate("Sun, 06 Apr 1994 08:49:37 GMT"))); + assertEquals(Calendar.MAY, getMonth(parseHttpDate("Sun, 06 May 1994 08:49:37 GMT"))); + assertEquals(Calendar.JUNE, getMonth(parseHttpDate("Sun, 06 Jun 1994 08:49:37 GMT"))); + assertEquals(Calendar.JULY, getMonth(parseHttpDate("Sun, 06 Jul 1994 08:49:37 GMT"))); + assertEquals(Calendar.AUGUST, getMonth(parseHttpDate("Sun, 06 Aug 1994 08:49:37 GMT"))); + assertEquals(Calendar.SEPTEMBER, getMonth(parseHttpDate("Sun, 06 Sep 1994 08:49:37 GMT"))); + assertEquals(Calendar.OCTOBER, getMonth(parseHttpDate("Sun Oct 06 08:49:37 1994"))); + assertEquals(Calendar.NOVEMBER, getMonth(parseHttpDate("Sun Nov 06 08:49:37 1994"))); + assertEquals(Calendar.DECEMBER, getMonth(parseHttpDate("Sun Dec 06 08:49:37 1994"))); } private static int getMonth(Date referenceDate) {