Fix conditional requests support for HttpEntity

Prior to this commit, `HttpEntityMethodProcessor` would rely on
`ServletWebRequest` to process conditional requests and with incoming
`"If-Modified-Since"` / `"If-None-Match"` request headers.

This approach is problematic since in that class:

* response is wrapped in a `ServletServerHttpResponse`
* this wrapped response does not write response headers right away
* `ServletWebRequest.checkNotModified` methods can't apply their
logic with incomplete response headers

This solution adds some minimal code duplication and applies
the conditional request logic within the Processor.

A possible alternative would be to improve the
`ServletServerHttpResponse$ServletResponseHttpHeaders` implementation
with write methods - but this solution would only work for Servlet 3.x
applications.

Issue: SPR-13090
This commit is contained in:
Brian Clozel
2015-06-26 15:28:59 +02:00
parent 338a18ef99
commit 39d689da0c
4 changed files with 88 additions and 48 deletions

View File

@@ -181,33 +181,21 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
public boolean checkNotModified(long lastModifiedTimestamp) {
HttpServletResponse response = getResponse();
if (lastModifiedTimestamp >= 0 && !this.notModified) {
if (response == null || isResponseCompatibleWithConditional(response, HEADER_LAST_MODIFIED)) {
if (response == null || HttpStatus.valueOf(response.getStatus()).is2xxSuccessful()) {
this.notModified = isTimeStampNotModified(lastModifiedTimestamp);
if (response != null) {
if (this.notModified && supportsNotModifiedStatus()) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
if(response.getHeader(HEADER_LAST_MODIFIED) == null) {
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
}
}
}
}
return this.notModified;
}
private boolean isResponseCompatibleWithConditional(HttpServletResponse response, String... headers) {
if (response != null) {
if (HttpStatus.valueOf(response.getStatus()).is2xxSuccessful()) {
for (String header : headers) {
if (response.containsHeader(header)) {
return false;
}
}
return true;
}
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isTimeStampNotModified(long lastModifiedTimestamp) {
long ifModifiedSince = -1;
@@ -235,14 +223,16 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
public boolean checkNotModified(String etag) {
HttpServletResponse response = getResponse();
if (StringUtils.hasLength(etag) && !this.notModified) {
if (response == null || isResponseCompatibleWithConditional(response, HEADER_ETAG)) {
if (response == null || HttpStatus.valueOf(response.getStatus()).is2xxSuccessful()) {
etag = addEtagPadding(etag);
this.notModified = isETagNotModified(etag);
if (response != null) {
if (this.notModified && supportsNotModifiedStatus()) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
response.setHeader(HEADER_ETAG, etag);
if(response.getHeader(HEADER_ETAG) == null) {
response.setHeader(HEADER_ETAG, etag);
}
}
}
}
@@ -283,15 +273,19 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ
public boolean checkNotModified(String etag, long lastModifiedTimestamp) {
HttpServletResponse response = getResponse();
if (StringUtils.hasLength(etag) && !this.notModified) {
if (response == null || isResponseCompatibleWithConditional(response, HEADER_ETAG, HEADER_LAST_MODIFIED)) {
if (response == null || HttpStatus.valueOf(response.getStatus()).is2xxSuccessful()) {
etag = addEtagPadding(etag);
this.notModified = isETagNotModified(etag) && isTimeStampNotModified(lastModifiedTimestamp);
if (response != null) {
if (this.notModified && supportsNotModifiedStatus()) {
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
response.setHeader(HEADER_ETAG, etag);
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
if(response.getHeader(HEADER_ETAG) == null) {
response.setHeader(HEADER_ETAG, etag);
}
if(response.getHeader(HEADER_LAST_MODIFIED) == null) {
response.setHeader(HEADER_LAST_MODIFIED, formatDate(lastModifiedTimestamp));
}
}
}
}