Skip to content

Commit

Permalink
Add Last-Modified header to 304 response when ETag is not present
Browse files Browse the repository at this point in the history
.

This commit adds the Last-Modified header to the 304 Not Modified response when the ETag header is not present in the cache entry. This aligns the behavior with the recommendations in RFC 7232 and helps clients that rely on the Last-Modified header for cache updates when
  • Loading branch information
arturobernalg authored and ok2c committed Apr 23, 2023
1 parent e0a912d commit 772cbf3
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ SimpleHttpResponse generateNotModifiedResponse(final HttpCacheEntry entry) {
response.addHeader(varyHeader);
}

//Since the goal of a 304 response is to minimize information transfer
//when the recipient already has one or more cached representations, a
//sender SHOULD NOT generate representation metadata other than the
//above listed fields unless said metadata exists for the purpose of
//guiding cache updates (e.g., Last-Modified might be useful if the
//response does not have an ETag field).
if (etagHeader == null) {
final Header lastModifiedHeader = entry.getFirstHeader(HttpHeaders.LAST_MODIFIED);
if (lastModifiedHeader != null) {
response.addHeader(lastModifiedHeader);
}
}
return response;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ public void testReturns304ForIfModifiedSinceHeaderIf304ResponseInCache() throws
resp1.setHeader("Date", DateUtils.formatStandardDate(now));
resp1.setHeader("Cache-control", "max-age=600");
resp1.setHeader("Expires", DateUtils.formatStandardDate(inTenMinutes));
resp1.setHeader("ETag", "\"etag\"");

Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);

Expand All @@ -403,6 +404,32 @@ public void testReturns304ForIfModifiedSinceHeaderIf304ResponseInCache() throws
Mockito.verify(mockExecChain).proceed(Mockito.any(), Mockito.any());
}

@Test
public void testReturns304ForIfModifiedSinceHeaderIf304ResponseInCacheWithLastModified() throws Exception {
final Instant now = Instant.now();
final Instant oneHourAgo = now.minus(1, ChronoUnit.HOURS);
final Instant inTenMinutes = now.plus(10, ChronoUnit.MINUTES);
final ClassicHttpRequest req1 = new HttpGet("http://foo.example.com/");
req1.addHeader("If-Modified-Since", DateUtils.formatStandardDate(oneHourAgo));
final ClassicHttpRequest req2 = new HttpGet("http://foo.example.com/");
req2.addHeader("If-Modified-Since", DateUtils.formatStandardDate(oneHourAgo));

final ClassicHttpResponse resp1 = HttpTestUtils.make304Response();
resp1.setHeader("Date", DateUtils.formatStandardDate(now));
resp1.setHeader("Cache-control", "max-age=600");
resp1.setHeader("Expires", DateUtils.formatStandardDate(inTenMinutes));

Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);

execute(req1);

final ClassicHttpResponse result = execute(req2);
Assertions.assertEquals(HttpStatus.SC_NOT_MODIFIED, result.getCode());
Assertions.assertTrue(result.containsHeader("Last-Modified"));

Mockito.verify(mockExecChain).proceed(Mockito.any(), Mockito.any());
}

@Test
public void testReturns200ForIfModifiedSinceDateIsLess() throws Exception {
final Instant now = Instant.now();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ private void cacheGenerated304ForValidatorShouldNotContainEntityHeader(
resp1.setHeader("Cache-Control","max-age=3600");
resp1.setHeader(validatorHeader, validator);
resp1.setHeader(headerName, headerValue);
resp1.setHeader("ETag", "\"etag\"");

Mockito.when(mockExecChain.proceed(Mockito.any(), Mockito.any())).thenReturn(resp1);

Expand Down

0 comments on commit 772cbf3

Please sign in to comment.