While migrating my JAX-RS application from Jersey to Quarkus/Resteasy, I came across a behavior change with the method evaluatePreconditions(Date lastModified)
. Indeed, in my use case, the last modified date contains milliseconds and unfortunately the date format of the headers If-Modified-Since
and Last-Modified
doesn't support milliseconds as we can see in the RFC 2616.
Jersey trims the milliseconds from the provided date (as we can see here) while in Resteasy, the date is not modified so it actually compares dates (the date from the header If-Modified-Since
and the provided date) with different precisions (respectively seconds versus milliseconds) which ends up with a mismatch so an HTTP status code 200
.
The code that illustrates the issue:
@Path("/evaluatePreconditions")
public class EvaluatePreconditionsResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
public Response findData(@Context Request request) {
final Data data = retrieveData();
final Date lastModified = Timestamp.valueOf(data.getLastModified());
final Response.ResponseBuilder responseBuilder =
request.evaluatePreconditions(lastModified);
if (responseBuilder == null) {
// Last modified date didn't match, send new content
return Response.ok(data.toString())
.lastModified(lastModified)
.build();
}
// Sending 304 not modified
return responseBuilder.build();
}
private Data retrieveData() {
// Let's assume that we call a service here that provides this value
// The date time is expressed in GMT+2, please adjust it according
// to your timezone
return new Data(
LocalDateTime.of(2020, 10, 2, 10, 23, 16, 1_000_000),
"This is my content"
);
}
public static class Data {
private final LocalDateTime lastModified;
private final String content;
public Data(LocalDateTime lastModified, String content) {
this.lastModified = lastModified;
this.content = content;
}
public LocalDateTime getLastModified() {
return lastModified;
}
@Override
public String toString() {
return content;
}
}
}
The corresponding result with Jersey:
curl -H "If-Modified-Since: Fri, 02 Oct 2020 08:23:16 GMT" \
-I localhost:8080/evaluatePreconditions
HTTP/1.1 304 Not Modified
...
The corresponding result with Quarkus/Resteasy:
curl -H "If-Modified-Since: Fri, 02 Oct 2020 08:23:16 GMT" \
-I localhost:8080/evaluatePreconditions
HTTP/1.1 200 OK
Last-Modified: Fri, 02 Oct 2020 08:23:16 GMT
...
This behavior has already been raised in the Resteasy project, but for the team, trimming the date would add a new bug because if the data/resource is modified several times within the same second, we would get a 304
if we trim the date and 200
if we don't, which is a fair point. However, I maybe wrong but according to what I understand from the RFC 7232, if several modifications can happen within the same second, we are supposed to rely on an ETag too which means that in the JAX-RS specification, we are supposed to use evaluatePreconditions(Date lastModified, EntityTag eTag)
instead.
So what is the correct behavior according to the JAX-RS specification regarding this particular case?