mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 08:24:13 +00:00
Parse RFC 9651-like date headers
RFC 9651 specifies @«timestamp» as a new format for date headers. The Deprecation header as specified in RFC 9745, for example, makes use of it. Make sure this can be parsed using `HttpHeaders#getFirstDate` and `HttpHeaders#getFirstZonedDateTime` Signed-off-by: Raphael Schweikert <any@sabberworm.com>
This commit is contained in:
committed by
Brian Clozel
parent
815911b39c
commit
130b0ec50c
@@ -29,7 +29,9 @@ import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeFormatterBuilder;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.time.temporal.ChronoField;
|
||||
import java.util.AbstractSet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
@@ -435,7 +437,9 @@ public class HttpHeaders implements Serializable {
|
||||
private static final DateTimeFormatter[] DATE_PARSERS = new DateTimeFormatter[] {
|
||||
DateTimeFormatter.RFC_1123_DATE_TIME,
|
||||
DateTimeFormatter.ofPattern("EEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
|
||||
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.US).withZone(GMT)
|
||||
DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss yyyy", Locale.US).withZone(GMT),
|
||||
// RFC 9651: Structured Field Values for HTTP
|
||||
new DateTimeFormatterBuilder().appendLiteral('@').appendValue(ChronoField.INSTANT_SECONDS).toFormatter(Locale.US).withZone(GMT)
|
||||
};
|
||||
|
||||
|
||||
@@ -1621,7 +1625,7 @@ public class HttpHeaders implements Serializable {
|
||||
// No header value sent at all
|
||||
return null;
|
||||
}
|
||||
if (headerValue.length() >= 3) {
|
||||
if (headerValue.length() >= 3 || headerValue.startsWith("@")) {
|
||||
// Short "0" or "-1" like values are never valid HTTP date headers...
|
||||
// Let's only bother with DateTimeFormatter parsing for long enough values.
|
||||
|
||||
|
||||
@@ -36,6 +36,9 @@ import java.util.TimeZone;
|
||||
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -654,6 +657,36 @@ class HttpHeadersTests {
|
||||
assertThat(authorization).isEqualTo("Bearer foo");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@CsvSource(value = {
|
||||
"@0,0",
|
||||
"@1,1000",
|
||||
"@10,10000",
|
||||
"@-1,-1000",
|
||||
"@1659578233,1659578233000", // Example from RFC
|
||||
"@-62135596800,-62135596800000", // Example from RFC
|
||||
"@253402214400,253402214400000", // Example from RFC
|
||||
})
|
||||
void rfc9651Dates_valid(String value, long timestampMillis) {
|
||||
headers.set("Deprecation", value);
|
||||
assertThat(headers.getFirstDate("Deprecation")).isEqualTo(timestampMillis);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"@",
|
||||
" @1",
|
||||
"@ 1",
|
||||
"@0000-",
|
||||
"@15+",
|
||||
"@12p",
|
||||
"@0x15",
|
||||
})
|
||||
void rfc9651Dates_invalid(String value) {
|
||||
headers.set("Deprecation", value);
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> headers.getFirstDate("Deprecation"));
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
class MapEntriesTests {
|
||||
|
||||
Reference in New Issue
Block a user