Skip to content

Commit fb33e84

Browse files
committed
Restore 2 digit days format in HttpHeaders
As recommended by RFC 7231, this commit restore using 2 digit days when formatting dates while still using DateTimeFormatter.RFC_1123_DATE_TIME for parsing. Closes gh-22611
1 parent 24e277d commit fb33e84

File tree

6 files changed

+32
-33
lines changed

6 files changed

+32
-33
lines changed

spring-test/src/test/java/org/springframework/mock/web/MockHttpServletResponseTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -169,7 +169,7 @@ public void cookies() {
169169
response.addCookie(cookie);
170170

171171
assertEquals("foo=bar; Path=/path; Domain=example.com; " +
172-
"Max-Age=0; Expires=Thu, 1 Jan 1970 00:00:00 GMT; " +
172+
"Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT; " +
173173
"Secure; HttpOnly", response.getHeader(HttpHeaders.SET_COOKIE));
174174
}
175175

spring-web/src/main/java/org/springframework/http/HttpHeaders.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -391,12 +391,18 @@ public class HttpHeaders implements MultiValueMap<String, String>, Serializable
391391
private static final ZoneId GMT = ZoneId.of("GMT");
392392

393393
/**
394-
* Date formats with time zone as specified in the HTTP RFC.
394+
* Date formats with time zone as specified in the HTTP RFC to use for formatting.
395395
* @see <a href="https://tools.ietf.org/html/rfc7231#section-7.1.1.1">Section 7.1.1.1 of RFC 7231</a>
396396
*/
397-
private static final DateTimeFormatter[] DATE_FORMATTERS = new DateTimeFormatter[] {
397+
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US).withZone(GMT);
398+
399+
/**
400+
* Date formats with time zone as specified in the HTTP RFC to use for parsing.
401+
* @see <a href="https://tools.ietf.org/html/rfc7231#section-7.1.1.1">Section 7.1.1.1 of RFC 7231</a>
402+
*/
403+
private static final DateTimeFormatter[] DATE_PARSERS = new DateTimeFormatter[] {
398404
DateTimeFormatter.RFC_1123_DATE_TIME,
399-
DateTimeFormatter.ofPattern("EEEE, dd-MMM-yy HH:mm:ss zz", Locale.US),
405+
DateTimeFormatter.ofPattern("EEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
400406
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.US).withZone(GMT)
401407
};
402408

@@ -1211,7 +1217,7 @@ public List<String> getVary() {
12111217
* @since 5.0
12121218
*/
12131219
public void setZonedDateTime(String headerName, ZonedDateTime date) {
1214-
set(headerName, DATE_FORMATTERS[0].format(date));
1220+
set(headerName, DATE_FORMATTER.format(date));
12151221
}
12161222

12171223
/**
@@ -1296,7 +1302,7 @@ private ZonedDateTime getFirstZonedDateTime(String headerName, boolean rejectInv
12961302
headerValue = headerValue.substring(0, parametersIndex);
12971303
}
12981304

1299-
for (DateTimeFormatter dateFormatter : DATE_FORMATTERS) {
1305+
for (DateTimeFormatter dateFormatter : DATE_PARSERS) {
13001306
try {
13011307
return ZonedDateTime.parse(headerValue, dateFormatter);
13021308
}
@@ -1562,7 +1568,7 @@ public static HttpHeaders readOnlyHttpHeaders(HttpHeaders headers) {
15621568
static String formatDate(long date) {
15631569
Instant instant = Instant.ofEpochMilli(date);
15641570
ZonedDateTime time = ZonedDateTime.ofInstant(instant, GMT);
1565-
return DATE_FORMATTERS[0].format(time);
1571+
return DATE_FORMATTER.format(time);
15661572
}
15671573

15681574
}

spring-web/src/test/java/org/springframework/http/HttpHeadersTests.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
2121
import java.net.URISyntaxException;
2222
import java.nio.charset.Charset;
2323
import java.nio.charset.StandardCharsets;
24-
import java.time.DateTimeException;
2524
import java.time.ZoneId;
2625
import java.time.ZonedDateTime;
2726
import java.util.ArrayList;
@@ -37,7 +36,6 @@
3736
import org.hamcrest.Matchers;
3837
import org.junit.Test;
3938

40-
import static java.time.format.DateTimeFormatter.*;
4139
import static org.hamcrest.Matchers.*;
4240
import static org.junit.Assert.*;
4341

@@ -298,11 +296,6 @@ public void expiresZonedDateTime() {
298296
assertEquals("Invalid Expires header", "Thu, 18 Dec 2008 10:20:00 GMT", headers.getFirst("expires"));
299297
}
300298

301-
@Test(expected = DateTimeException.class) // SPR-16560
302-
public void expiresLargeDate() {
303-
headers.setExpires(Long.MAX_VALUE);
304-
}
305-
306299
@Test // SPR-10648 (example is from INT-3063)
307300
public void expiresInvalidDate() {
308301
headers.set("Expires", "-1");
@@ -495,37 +488,37 @@ public void contentLanguageSerialized() {
495488

496489
@Test
497490
public void firstDate() {
498-
headers.setDate(HttpHeaders.DATE, 1229595600000L);
499-
assertThat(headers.getFirstDate(HttpHeaders.DATE), is(1229595600000L));
491+
headers.setDate(HttpHeaders.DATE, 1496370120000L);
492+
assertThat(headers.getFirstDate(HttpHeaders.DATE), is(1496370120000L));
500493

501494
headers.clear();
502495

503-
headers.add(HttpHeaders.DATE, "Thu, 18 Dec 2008 10:20:00 GMT");
496+
headers.add(HttpHeaders.DATE, "Fri, 02 Jun 2017 02:22:00 GMT");
504497
headers.add(HttpHeaders.DATE, "Sat, 18 Dec 2010 10:20:00 GMT");
505-
assertThat(headers.getFirstDate(HttpHeaders.DATE), is(1229595600000L));
498+
assertThat(headers.getFirstDate(HttpHeaders.DATE), is(1496370120000L));
506499
}
507500

508501
@Test
509502
public void firstZonedDateTime() {
510-
ZonedDateTime date = ZonedDateTime.of(2017, 6, 22, 22, 22, 0, 0, ZoneId.of("GMT"));
503+
ZonedDateTime date = ZonedDateTime.of(2017, 6, 2, 2, 22, 0, 0, ZoneId.of("GMT"));
511504
headers.setZonedDateTime(HttpHeaders.DATE, date);
512-
assertThat(headers.getFirst(HttpHeaders.DATE), is("Thu, 22 Jun 2017 22:22:00 GMT"));
505+
assertThat(headers.getFirst(HttpHeaders.DATE), is("Fri, 02 Jun 2017 02:22:00 GMT"));
513506
assertTrue(headers.getFirstZonedDateTime(HttpHeaders.DATE).isEqual(date));
514507

515508
headers.clear();
516509
ZonedDateTime otherDate = ZonedDateTime.of(2010, 12, 18, 10, 20, 0, 0, ZoneId.of("GMT"));
517-
headers.add(HttpHeaders.DATE, RFC_1123_DATE_TIME.format(date));
518-
headers.add(HttpHeaders.DATE, RFC_1123_DATE_TIME.format(otherDate));
510+
headers.add(HttpHeaders.DATE, "Fri, 02 Jun 2017 02:22:00 GMT");
511+
headers.add(HttpHeaders.DATE, "Sat, 18 Dec 2010 10:20:00 GMT");
519512
assertTrue(headers.getFirstZonedDateTime(HttpHeaders.DATE).isEqual(date));
520513

521514
// obsolete RFC 850 format
522515
headers.clear();
523-
headers.set(HttpHeaders.DATE, "Thursday, 22-Jun-17 22:22:00 GMT");
516+
headers.set(HttpHeaders.DATE, "Friday, 02-Jun-17 02:22:00 GMT");
524517
assertTrue(headers.getFirstZonedDateTime(HttpHeaders.DATE).isEqual(date));
525518

526519
// ANSI C's asctime() format
527520
headers.clear();
528-
headers.set(HttpHeaders.DATE, "Thu Jun 22 22:22:00 2017");
521+
headers.set(HttpHeaders.DATE, "Fri Jun 02 02:22:00 2017");
529522
assertTrue(headers.getFirstZonedDateTime(HttpHeaders.DATE).isEqual(date));
530523
}
531524

spring-web/src/test/java/org/springframework/http/RequestEntityTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -115,7 +115,7 @@ public void headers() throws URISyntaxException {
115115

116116
assertEquals("text/plain", responseHeaders.getFirst("Accept"));
117117
assertEquals("utf-8", responseHeaders.getFirst("Accept-Charset"));
118-
assertEquals("Thu, 1 Jan 1970 00:00:12 GMT", responseHeaders.getFirst("If-Modified-Since"));
118+
assertEquals("Thu, 01 Jan 1970 00:00:12 GMT", responseHeaders.getFirst("If-Modified-Since"));
119119
assertEquals(ifNoneMatch, responseHeaders.getFirst("If-None-Match"));
120120
assertEquals(String.valueOf(contentLength), responseHeaders.getFirst("Content-Length"));
121121
assertEquals(contentType.toString(), responseHeaders.getFirst("Content-Type"));

spring-web/src/test/java/org/springframework/http/ResponseCookieTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -62,10 +62,10 @@ public void maxAge() {
6262

6363
@Test
6464
public void maxAge0() {
65-
assertEquals("id=1fWa; Max-Age=0; Expires=Thu, 1 Jan 1970 00:00:00 GMT",
65+
assertEquals("id=1fWa; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT",
6666
ResponseCookie.from("id", "1fWa").maxAge(Duration.ofSeconds(0)).build().toString());
6767

68-
assertEquals("id=1fWa; Max-Age=0; Expires=Thu, 1 Jan 1970 00:00:00 GMT",
68+
assertEquals("id=1fWa; Max-Age=0; Expires=Thu, 01 Jan 1970 00:00:00 GMT",
6969
ResponseCookie.from("id", "1fWa").maxAge(0).build().toString());
7070
}
7171

spring-web/src/test/java/org/springframework/http/ResponseEntityTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -160,7 +160,7 @@ public void headers() throws URISyntaxException {
160160
HttpHeaders responseHeaders = responseEntity.getHeaders();
161161

162162
assertEquals("GET", responseHeaders.getFirst("Allow"));
163-
assertEquals("Thu, 1 Jan 1970 00:00:12 GMT",
163+
assertEquals("Thu, 01 Jan 1970 00:00:12 GMT",
164164
responseHeaders.getFirst("Last-Modified"));
165165
assertEquals(location.toASCIIString(),
166166
responseHeaders.getFirst("Location"));

0 commit comments

Comments
 (0)