Author: lukaszlenart Date: Sun Jan 27 20:23:06 2013 New Revision: 1439169 URL: http://svn.apache.org/viewvc?rev=1439169&view=rev Log: WW-3492 adds proper handling of If-Modified-Since header
Modified: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/DefaultHttpHeaders.java struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/DefaultHttpHeadersTest.java Modified: struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/DefaultHttpHeaders.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/DefaultHttpHeaders.java?rev=1439169&r1=1439168&r2=1439169&view=diff ============================================================================== --- struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/DefaultHttpHeaders.java (original) +++ struts/struts2/trunk/plugins/rest/src/main/java/org/apache/struts2/rest/DefaultHttpHeaders.java Sun Jan 27 20:23:06 2013 @@ -21,40 +21,55 @@ package org.apache.struts2.rest; +import com.opensymphony.xwork2.util.logging.Logger; +import com.opensymphony.xwork2.util.logging.LoggerFactory; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import static javax.servlet.http.HttpServletResponse.*; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.util.Date; +import static javax.servlet.http.HttpServletResponse.SC_CREATED; +import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED; +import static javax.servlet.http.HttpServletResponse.SC_OK; + /** * Default implementation of rest info that uses fluent-style construction */ public class DefaultHttpHeaders implements HttpHeaders { - String resultCode; - int status = SC_OK; - Object etag; - Object locationId; - String location; - boolean disableCaching; - boolean noETag = false; - Date lastModified; - - public DefaultHttpHeaders() {} - + + private static final Logger LOG = LoggerFactory.getLogger(DefaultHttpHeaders.class); + + private static final String IF_MODIFIED_SINCE_DATE_FORMAT = "EEE, dd MMM yyyy HH:mm:ss zzz"; + private static final SimpleDateFormat IF_MODIFIED_SINCE_FORMAT = new SimpleDateFormat(IF_MODIFIED_SINCE_DATE_FORMAT); + + private String resultCode; + private int status = SC_OK; + private Object etag; + private Object locationId; + private String location; + private boolean disableCaching; + private boolean noETag = false; + private Date lastModified; + + public DefaultHttpHeaders() { + } + public DefaultHttpHeaders(String result) { resultCode = result; } - + public DefaultHttpHeaders renderResult(String code) { this.resultCode = code; return this; } - + public DefaultHttpHeaders withStatus(int code) { this.status = code; return this; } - + public DefaultHttpHeaders withETag(Object etag) { this.etag = etag; return this; @@ -64,27 +79,27 @@ public class DefaultHttpHeaders implemen this.noETag = true; return this; } - + public DefaultHttpHeaders setLocationId(Object id) { this.locationId = id; return this; } - + public DefaultHttpHeaders setLocation(String loc) { this.location = loc; return this; } - + public DefaultHttpHeaders lastModified(Date date) { this.lastModified = date; return this; } - + public DefaultHttpHeaders disableCaching() { this.disableCaching = true; return this; } - + /* (non-Javadoc) * @see org.apache.struts2.rest.HttpHeaders#apply(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object) */ @@ -108,9 +123,9 @@ public class DefaultHttpHeaders implemen int lastSlash = url.lastIndexOf("/"); int lastDot = url.lastIndexOf("."); if (lastDot > lastSlash && lastDot > -1) { - url = url.substring(0, lastDot)+"/"+locationId+url.substring(lastDot); + url = url.substring(0, lastDot) + "/" + locationId + url.substring(lastDot); } else { - url += "/"+locationId; + url += "/" + locationId; } response.setHeader("Location", url); status = SC_CREATED; @@ -130,16 +145,13 @@ public class DefaultHttpHeaders implemen } String reqLastModified = request.getHeader("If-Modified-Since"); - if (lastModified != null) { - if (String.valueOf(lastModified.getTime()).equals(reqLastModified)) { - lastModifiedNotChanged = true; - } - + if (lastModified != null && reqLastModified != null) { + lastModifiedNotChanged = compareIfModifiedSince(reqLastModified); } if ((etagNotChanged && lastModifiedNotChanged) || - (etagNotChanged && reqLastModified == null) || - (lastModifiedNotChanged && reqETag == null)) { + (etagNotChanged && reqLastModified == null) || + (lastModifiedNotChanged && reqETag == null)) { status = SC_NOT_MODIFIED; } } @@ -148,19 +160,30 @@ public class DefaultHttpHeaders implemen return resultCode; } + private boolean compareIfModifiedSince(String reqLastModified) { + try { + if (lastModified.compareTo(IF_MODIFIED_SINCE_FORMAT.parse(reqLastModified)) >= 0) { + return true; + } + } catch (ParseException e) { + if (LOG.isDebugEnabled()) { + LOG.debug("Got error parsing If-Modified-Since header value [#0] as [#1]!", e, reqLastModified, IF_MODIFIED_SINCE_DATE_FORMAT); + } + return false; + } + return false; + } + public int getStatus() { return status; } - + public void setStatus(int s) { - status = s; + status = s; + } + + public String getResultCode() { + return resultCode; } - public String getResultCode() { - return resultCode; - } - - - - } Modified: struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/DefaultHttpHeadersTest.java URL: http://svn.apache.org/viewvc/struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/DefaultHttpHeadersTest.java?rev=1439169&r1=1439168&r2=1439169&view=diff ============================================================================== --- struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/DefaultHttpHeadersTest.java (original) +++ struts/struts2/trunk/plugins/rest/src/test/java/org/apache/struts2/rest/DefaultHttpHeadersTest.java Sun Jan 27 20:23:06 2013 @@ -25,9 +25,14 @@ import junit.framework.TestCase; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; -import static javax.servlet.http.HttpServletResponse.*; +import java.text.SimpleDateFormat; import java.util.Date; +import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST; +import static javax.servlet.http.HttpServletResponse.SC_CREATED; +import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED; +import static javax.servlet.http.HttpServletResponse.SC_OK; + public class DefaultHttpHeadersTest extends TestCase { private MockHttpServletResponse mockResponse; private MockHttpServletRequest mockRequest; @@ -128,7 +133,7 @@ public class DefaultHttpHeadersTest exte Date now = new Date(); DefaultHttpHeaders headers = new DefaultHttpHeaders() .lastModified(now); - mockRequest.addHeader("If-Modified-Since", String.valueOf(now.getTime())); + mockRequest.addHeader("If-Modified-Since", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(now)); headers.apply(mockRequest, mockResponse, new Object()); assertEquals(SC_NOT_MODIFIED, mockResponse.getStatus()); @@ -144,13 +149,31 @@ public class DefaultHttpHeadersTest exte assertEquals(SC_OK, mockResponse.getStatus()); } + public void testLastModifiedSince() { + Date now = new Date(); + DefaultHttpHeaders headers = new DefaultHttpHeaders().lastModified(now); + mockRequest.addHeader("If-Modified-Since", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(now)); + headers.apply(mockRequest, mockResponse, new Object()); + + assertEquals(SC_NOT_MODIFIED, mockResponse.getStatus()); + } + + public void testLastModifiedSinceIsOlder() { + Date now = new Date(); + DefaultHttpHeaders headers = new DefaultHttpHeaders().lastModified(now); + mockRequest.addHeader("If-Modified-Since", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(new Date(now.getTime() - 1000 * 60 * 60))); + headers.apply(mockRequest, mockResponse, new Object()); + + assertEquals(SC_NOT_MODIFIED, mockResponse.getStatus()); + } + public void testConditionalGetForLastModifiedAndETag() { Date now = new Date(); DefaultHttpHeaders headers = new DefaultHttpHeaders() .lastModified(now) .withETag("asdf"); mockRequest.addHeader("If-None-Match", "asdf"); - mockRequest.addHeader("If-Modified-Since", String.valueOf(now.getTime())); + mockRequest.addHeader("If-Modified-Since", new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz").format(now)); headers.apply(mockRequest, mockResponse, new Object()); assertEquals(SC_NOT_MODIFIED, mockResponse.getStatus());