Skip to content

Commit 377f2a2

Browse files
authored
Use RFC 822 format for marshalling date shapes (#3452)
* Use RFC 822 format for marshalling date shapes * Explicitly set ResolverStyle and Chronology
1 parent b1f8989 commit 377f2a2

File tree

11 files changed

+138
-11
lines changed

11 files changed

+138
-11
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"category": "AWS SDK for Java v2",
3+
"contributor": "dave-fn",
4+
"type": "bugfix",
5+
"description": "Build headers with two-digit day of month to meet RFC 822 reporting requirement"
6+
}

core/aws-core/src/test/java/software/amazon/awssdk/awscore/exception/AwsServiceExceptionTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ public void assertSkewed(int clientSideTimeOffset,
8787
int statusCode,
8888
Instant serverDate) {
8989
AwsServiceException exception = exception(clientSideTimeOffset, errorCode, statusCode,
90-
DateUtils.formatRfc1123Date(serverDate));
90+
DateUtils.formatRfc822Date(serverDate));
9191
assertThat(exception.isClockSkewException()).isTrue();
9292
}
9393

@@ -96,7 +96,7 @@ public void assertNotSkewed(int clientSideTimeOffset,
9696
int statusCode,
9797
Instant serverDate) {
9898
AwsServiceException exception = exception(clientSideTimeOffset, errorCode, statusCode,
99-
DateUtils.formatRfc1123Date(serverDate));
99+
DateUtils.formatRfc822Date(serverDate));
100100
assertThat(exception.isClockSkewException()).isFalse();
101101
}
102102

core/aws-core/src/test/java/software/amazon/awssdk/awscore/retry/AwsRetryPolicyTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ private Consumer<RetryPolicyContext.Builder> applyErrorCode(String errorCode) {
125125

126126
private Consumer<RetryPolicyContext.Builder> applyErrorCode(String errorCode, Duration clockSkew, Instant dateHeader) {
127127
SdkHttpFullResponse response = SdkHttpFullResponse.builder()
128-
.putHeader("Date", DateUtils.formatRfc1123Date(dateHeader))
128+
.putHeader("Date", DateUtils.formatRfc822Date(dateHeader))
129129
.build();
130130

131131
AwsErrorDetails errorDetails = AwsErrorDetails.builder()

core/protocols/aws-json-protocol/src/main/java/software/amazon/awssdk/protocols/json/internal/marshall/SimpleTypeJsonMarshaller.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public void marshall(Boolean val, StructuredJsonGenerator jsonGenerator, JsonMar
113113
jsonGenerator.writeNumber(DateUtils.formatUnixTimestampInstant(val));
114114
break;
115115
case RFC_822:
116-
jsonGenerator.writeValue(DateUtils.formatRfc1123Date(val));
116+
jsonGenerator.writeValue(DateUtils.formatRfc822Date(val));
117117
break;
118118
case ISO_8601:
119119
jsonGenerator.writeValue(DateUtils.formatIso8601Date(val));

core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/InstantToString.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public String convert(Instant val, SdkField<Instant> sdkField) {
5151
case ISO_8601:
5252
return DateUtils.formatIso8601Date(val);
5353
case RFC_822:
54-
return DateUtils.formatRfc1123Date(val);
54+
return DateUtils.formatRfc822Date(val);
5555
case UNIX_TIMESTAMP:
5656
return DateUtils.formatUnixTimestampInstant(val);
5757
default:

core/protocols/protocol-core/src/main/java/software/amazon/awssdk/protocols/core/StringToInstant.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public Instant convert(String value, SdkField<Instant> field) {
5555
case UNIX_TIMESTAMP_MILLIS:
5656
return safeParseDate(DateUtils::parseUnixTimestampMillisInstant).apply(value);
5757
case RFC_822:
58-
return DateUtils.parseRfc1123Date(value);
58+
return DateUtils.parseRfc822Date(value);
5959
default:
6060
throw SdkClientException.create("Unrecognized timestamp format - " + format);
6161
}

core/sdk-core/src/main/java/software/amazon/awssdk/core/retry/ClockSkew.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public static Optional<Instant> getServerTime(SdkHttpResponse serviceResponse) {
7676
log.debug(() -> "Reported service date: " + serverDate);
7777

7878
try {
79-
return Optional.of(DateUtils.parseRfc1123Date(serverDate));
79+
return Optional.of(DateUtils.parseRfc822Date(serverDate));
8080
} catch (RuntimeException e) {
8181
log.warn(() -> "Unable to parse clock skew offset from response: " + serverDate, e);
8282
return Optional.empty();

core/sdk-core/src/test/java/software/amazon/awssdk/core/internal/retry/ClockSkewAdjusterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public void badDateTranslatesToZero() {
4747

4848
private SdkHttpFullResponse responseWithDateOffset(int value, ChronoUnit unit) {
4949
return SdkHttpFullResponse.builder()
50-
.putHeader("Date", DateUtils.formatRfc1123Date(Instant.now().plus(value, unit)))
50+
.putHeader("Date", DateUtils.formatRfc822Date(Instant.now().plus(value, unit)))
5151
.build();
5252
}
5353

test/protocol-tests/src/test/java/software/amazon/awssdk/protocol/tests/clockskew/ClockSkewAdjustmentTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ private void stubForResponse(Instant serviceTime, int statusCode, String errorCo
166166
.willReturn(aResponse()
167167
.withStatus(statusCode)
168168
.withHeader("x-amzn-ErrorType", errorCode)
169-
.withHeader("Date", DateUtils.formatRfc1123Date(serviceTime))
169+
.withHeader("Date", DateUtils.formatRfc822Date(serviceTime))
170170
.withBody("{}")));
171171
}
172172

@@ -180,7 +180,7 @@ private void stubForClockSkewFailureThenSuccess(Instant serviceTime, int statusC
180180
.willReturn(aResponse()
181181
.withStatus(statusCode)
182182
.withHeader("x-amzn-ErrorType", errorCode)
183-
.withHeader("Date", DateUtils.formatRfc1123Date(serviceTime))
183+
.withHeader("Date", DateUtils.formatRfc822Date(serviceTime))
184184
.withBody("{}")));
185185

186186
stubFor(post(urlEqualTo(PATH))

utils/src/main/java/software/amazon/awssdk/utils/DateUtils.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@
2525
import java.time.Instant;
2626
import java.time.ZoneOffset;
2727
import java.time.ZonedDateTime;
28+
import java.time.chrono.IsoChronology;
2829
import java.time.format.DateTimeFormatter;
2930
import java.time.format.DateTimeFormatterBuilder;
3031
import java.time.format.DateTimeParseException;
32+
import java.time.format.ResolverStyle;
3133
import java.util.Arrays;
3234
import java.util.List;
35+
import java.util.Locale;
3336
import software.amazon.awssdk.annotations.SdkProtectedApi;
3437
import software.amazon.awssdk.annotations.ThreadSafe;
3538

@@ -48,6 +51,20 @@ public final class DateUtils {
4851
.toFormatter()
4952
.withZone(UTC);
5053

54+
/**
55+
* RFC 822 date/time formatter.
56+
*/
57+
static final DateTimeFormatter RFC_822_DATE_TIME = new DateTimeFormatterBuilder()
58+
.parseCaseInsensitive()
59+
.parseLenient()
60+
.appendPattern("EEE, dd MMM yyyy HH:mm:ss")
61+
.appendLiteral(' ')
62+
.appendOffset("+HHMM", "GMT")
63+
.toFormatter()
64+
.withLocale(Locale.US)
65+
.withResolverStyle(ResolverStyle.SMART)
66+
.withChronology(IsoChronology.INSTANCE);
67+
5168
// ISO_INSTANT does not handle offsets in Java 12-. See https://bugs.openjdk.java.net/browse/JDK-8166138
5269
private static final List<DateTimeFormatter> ALTERNATE_ISO_8601_FORMATTERS =
5370
Arrays.asList(ISO_INSTANT, ALTERNATE_ISO_8601_DATE_FORMAT, ISO_OFFSET_DATE_TIME);
@@ -102,6 +119,33 @@ public static String formatIso8601Date(Instant date) {
102119
return ISO_INSTANT.format(date);
103120
}
104121

122+
/**
123+
* Parses the specified date string as an RFC 822 date and returns the Date object.
124+
*
125+
* @param dateString
126+
* The date string to parse.
127+
*
128+
* @return The parsed Date object.
129+
*/
130+
public static Instant parseRfc822Date(String dateString) {
131+
if (dateString == null) {
132+
return null;
133+
}
134+
return parseInstant(dateString, RFC_822_DATE_TIME);
135+
}
136+
137+
/**
138+
* Formats the specified date as an RFC 822 string.
139+
*
140+
* @param instant
141+
* The instant to format.
142+
*
143+
* @return The RFC 822 string representing the specified date.
144+
*/
145+
public static String formatRfc822Date(Instant instant) {
146+
return RFC_822_DATE_TIME.format(ZonedDateTime.ofInstant(instant, UTC));
147+
}
148+
105149
/**
106150
* Parses the specified date string as an RFC 1123 date and returns the Date
107151
* object.

0 commit comments

Comments
 (0)