diff --git a/spring-web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java index 18983a14cf..ee9f8bf0c6 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/FacesWebRequest.java @@ -155,6 +155,17 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb return false; } + /** + * Last-modified handling not supported for portlet requests: + * As a consequence, this method always returns {@code false}. + * + * @since 4.2 + */ + @Override + public boolean checkNotModified(String etag, long lastModifiedTimestamp) { + return false; + } + @Override public String getDescription(boolean includeClientInfo) { ExternalContext externalContext = getExternalContext(); diff --git a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java index 079314f606..5b8c5314ee 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/ServletWebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,6 +21,7 @@ import java.util.Date; import java.util.Iterator; import java.util.Locale; import java.util.Map; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; @@ -35,6 +36,9 @@ import org.springframework.web.util.WebUtils; * {@link WebRequest} adapter for an {@link javax.servlet.http.HttpServletRequest}. * * @author Juergen Hoeller + * @author Brian Clozel + * @author Markus Malkusch + * * @since 2.0 */ public class ServletWebRequest extends ServletRequestAttributes implements NativeWebRequest { @@ -72,7 +76,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ super(request, response); } - @Override public Object getNativeRequest() { return getRequest(); @@ -93,7 +96,6 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return WebUtils.getNativeResponse(getResponse(), requiredType); } - /** * Return the HTTP method of the request. * @since 4.0.2 @@ -169,35 +171,15 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ } @Override - @SuppressWarnings("deprecation") public boolean checkNotModified(long lastModifiedTimestamp) { HttpServletResponse response = getResponse(); - if (lastModifiedTimestamp >= 0 && !this.notModified && - (response == null || !response.containsHeader(HEADER_LAST_MODIFIED))) { - long ifModifiedSince = -1; - try { - ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE); - } - catch (IllegalArgumentException ex) { - String headerValue = getRequest().getHeader(HEADER_IF_MODIFIED_SINCE); - // Possibly an IE 10 style value: "Wed, 09 Apr 2014 09:57:42 GMT; length=13774" - int separatorIndex = headerValue.indexOf(';'); - if (separatorIndex != -1) { - String datePart = headerValue.substring(0, separatorIndex); - try { - ifModifiedSince = Date.parse(datePart); + if (lastModifiedTimestamp >= 0 && !this.notModified) { + if (response == null || !response.containsHeader(HEADER_LAST_MODIFIED)) { + this.notModified = isTimeStampNotModified(lastModifiedTimestamp); + if (response != null) { + if (this.notModified && supportsNotModifiedStatus()) { + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); } - catch (IllegalArgumentException ex2) { - // Giving up - } - } - } - this.notModified = (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000)); - if (response != null) { - if (this.notModified && supportsNotModifiedStatus()) { - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - } - else { response.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp); } } @@ -205,18 +187,40 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return this.notModified; } + @SuppressWarnings("deprecation") + private boolean isTimeStampNotModified(long lastModifiedTimestamp) { + long ifModifiedSince = -1; + try { + ifModifiedSince = getRequest().getDateHeader(HEADER_IF_MODIFIED_SINCE); + } + catch (IllegalArgumentException ex) { + String headerValue = getRequest().getHeader(HEADER_IF_MODIFIED_SINCE); + // Possibly an IE 10 style value: "Wed, 09 Apr 2014 09:57:42 GMT; length=13774" + int separatorIndex = headerValue.indexOf(';'); + if (separatorIndex != -1) { + String datePart = headerValue.substring(0, separatorIndex); + try { + ifModifiedSince = Date.parse(datePart); + } + catch (IllegalArgumentException ex2) { + // Giving up + } + } + } + return (ifModifiedSince >= (lastModifiedTimestamp / 1000 * 1000)); + } + @Override public boolean checkNotModified(String etag) { HttpServletResponse response = getResponse(); - if (StringUtils.hasLength(etag) && !this.notModified && - (response == null || !response.containsHeader(HEADER_ETAG))) { - String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH); - this.notModified = etag.equals(ifNoneMatch); - if (response != null) { - if (this.notModified && supportsNotModifiedStatus()) { - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - } - else { + if (StringUtils.hasLength(etag) && !this.notModified) { + if (response == null || !response.containsHeader(HEADER_ETAG)) { + 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); } } @@ -224,11 +228,56 @@ public class ServletWebRequest extends ServletRequestAttributes implements Nativ return this.notModified; } + private String addEtagPadding(String etag) { + if (!(etag.startsWith("\"") || etag.startsWith("W/\"")) || !etag.endsWith("\"")) { + etag = "\"" + etag + "\""; + } + return etag; + } + + private boolean isETagNotModified(String etag) { + if (StringUtils.hasLength(etag)) { + String ifNoneMatch = getRequest().getHeader(HEADER_IF_NONE_MATCH); + if (StringUtils.hasLength(ifNoneMatch)) { + String[] clientETags = StringUtils.delimitedListToStringArray(ifNoneMatch, ",", " "); + for (String clientETag : clientETags) { + // compare weak/strong ETags as per https://tools.ietf.org/html/rfc7232#section-2.3 + if (StringUtils.hasLength(clientETag) && + (clientETag.replaceFirst("^W/", "").equals(etag.replaceFirst("^W/", "")) + || clientETag.equals("*"))) { + return true; + } + } + } + } + return false; + } + private boolean supportsNotModifiedStatus() { String method = getRequest().getMethod(); return (METHOD_GET.equals(method) || METHOD_HEAD.equals(method)); } + @Override + public boolean checkNotModified(String etag, long lastModifiedTimestamp) { + HttpServletResponse response = getResponse(); + if (StringUtils.hasLength(etag) && !this.notModified) { + if (response == null || + (!response.containsHeader(HEADER_ETAG) && !response.containsHeader(HEADER_LAST_MODIFIED))) { + 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.setDateHeader(HEADER_LAST_MODIFIED, lastModifiedTimestamp); + } + } + } + return this.notModified; + } + public boolean isNotModified() { return this.notModified; } diff --git a/spring-web/src/main/java/org/springframework/web/context/request/WebRequest.java b/spring-web/src/main/java/org/springframework/web/context/request/WebRequest.java index 401451494f..6a9d6bb547 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/WebRequest.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/WebRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -141,9 +141,12 @@ public interface WebRequest extends RequestAttributes { * model.addAttribute(...); * return "myViewName"; * } - *

Note: that you typically want to use either + *

Note: you can use either * this {@code #checkNotModified(long)} method; or - * {@link #checkNotModified(String)}, but not both. + * {@link #checkNotModified(String)}. If you want enforce both + * a strong entity tag and a Last-Modified value, + * as recommended by the HTTP specification, + * then you should use {@link #checkNotModified(String, long)}. *

If the "If-Modified-Since" header is set but cannot be parsed * to a date value, this method will ignore the header and proceed * with setting the last-modified timestamp on the response. @@ -172,9 +175,12 @@ public interface WebRequest extends RequestAttributes { * model.addAttribute(...); * return "myViewName"; * } - *

Note: that you typically want to use either + *

Note: you can use either * this {@code #checkNotModified(String)} method; or - * {@link #checkNotModified(long)}, but not both. + * {@link #checkNotModified(long)}. If you want enforce both + * a strong entity tag and a Last-Modified value, + * as recommended by the HTTP specification, + * then you should use {@link #checkNotModified(String, long)}. * @param etag the entity tag that the application determined * for the underlying resource. This parameter will be padded * with quotes (") if necessary. @@ -184,6 +190,42 @@ public interface WebRequest extends RequestAttributes { */ boolean checkNotModified(String etag); + /** + * Check whether the request qualifies as not modified given the + * supplied {@code ETag} (entity tag) and last-modified timestamp, + * as determined by the application. + *

This will also transparently set the appropriate response headers, + * for both the modified case and the not-modified case. + *

Typical usage: + *

+	 * public String myHandleMethod(WebRequest webRequest, Model model) {
+	 *   String eTag = // application-specific calculation
+	 *   long lastModified = // application-specific calculation
+	 *   if (request.checkNotModified(eTag, lastModified)) {
+	 *     // shortcut exit - no further processing necessary
+	 *     return null;
+	 *   }
+	 *   // further request processing, actually building content
+	 *   model.addAttribute(...);
+	 *   return "myViewName";
+	 * }
+ *

Note: The HTTP specification recommends + * setting both ETag and Last-Modified values, but you can also + * use {@code #checkNotModified(String)} or + * {@link #checkNotModified(long)}. + * @param etag the entity tag that the application determined + * for the underlying resource. This parameter will be padded + * with quotes (") if necessary. + * @param lastModifiedTimestamp the last-modified timestamp that + * the application determined for the underlying resource + * @return whether the request qualifies as not modified, + * allowing to abort request processing and relying on the response + * telling the client that the content has not been modified + * + * @since 4.2 + */ + boolean checkNotModified(String etag, long lastModifiedTimestamp); + /** * Get a short description of this request, * typically containing request URI and session id. diff --git a/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java new file mode 100644 index 0000000000..7121a8bfe8 --- /dev/null +++ b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestHttpMethodsTests.java @@ -0,0 +1,258 @@ +/* + * Copyright 2002-2015 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.web.context.request; + +import static org.junit.Assert.*; + +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.Locale; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import org.springframework.mock.web.test.MockHttpServletRequest; +import org.springframework.mock.web.test.MockHttpServletResponse; + +/** + * Parameterized tests for ServletWebRequest + * @author Juergen Hoeller + * @author Brian Clozel + * @author Markus Malkusch + */ +@RunWith(Parameterized.class) +public class ServletWebRequestHttpMethodsTests { + + private SimpleDateFormat dateFormat; + + private MockHttpServletRequest servletRequest; + + private MockHttpServletResponse servletResponse; + + private ServletWebRequest request; + + private String method; + + @Parameters + static public Iterable safeMethods() { + return Arrays.asList(new Object[][] { + {"GET"}, + {"HEAD"} + }); + } + + public ServletWebRequestHttpMethodsTests(String method) { + this.method = method; + } + + @Before + public void setUp() { + dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + servletRequest = new MockHttpServletRequest(method, "http://example.org"); + servletResponse = new MockHttpServletResponse(); + request = new ServletWebRequest(servletRequest, servletResponse); + } + + @Test + public void checkNotModifiedTimestamp() { + long currentTime = new Date().getTime(); + servletRequest.addHeader("If-Modified-Since", currentTime); + + assertTrue(request.checkNotModified(currentTime)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkModifiedTimestamp() { + long currentTime = new Date().getTime(); + long oneMinuteAgo = currentTime - (1000 * 60); + servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); + + assertFalse(request.checkNotModified(currentTime)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkNotModifiedETag() { + String eTag = "\"Foo\""; + servletRequest.addHeader("If-None-Match", eTag); + + assertTrue(request.checkNotModified(eTag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkModifiedETag() { + String currentETag = "\"Foo\""; + String oldEtag = "Bar"; + servletRequest.addHeader("If-None-Match", oldEtag); + + assertFalse(request.checkNotModified(currentETag)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals(currentETag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedUnpaddedETag() { + String eTag = "Foo"; + String paddedEtag = String.format("\"%s\"", eTag); + servletRequest.addHeader("If-None-Match", paddedEtag); + + assertTrue(request.checkNotModified(eTag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(paddedEtag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkModifiedUnpaddedETag() { + String currentETag = "Foo"; + String oldEtag = "Bar"; + servletRequest.addHeader("If-None-Match", oldEtag); + + assertFalse(request.checkNotModified(currentETag)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals(String.format("\"%s\"", currentETag), servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedWildcardETag() { + String eTag = "\"Foo\""; + servletRequest.addHeader("If-None-Match", "*"); + + assertTrue(request.checkNotModified(eTag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedETagAndTimestamp() { + String eTag = "\"Foo\""; + servletRequest.addHeader("If-None-Match", eTag); + long currentTime = new Date().getTime(); + servletRequest.addHeader("If-Modified-Since", currentTime); + + assertTrue(request.checkNotModified(eTag, currentTime)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkNotModifiedETagAndModifiedTimestamp() { + String eTag = "\"Foo\""; + servletRequest.addHeader("If-None-Match", eTag); + long currentTime = new Date().getTime(); + long oneMinuteAgo = currentTime - (1000 * 60); + servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); + + assertFalse(request.checkNotModified(eTag, currentTime)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkModifiedETagAndNotModifiedTimestamp() { + String currentETag = "\"Foo\""; + String oldEtag = "\"Bar\""; + servletRequest.addHeader("If-None-Match", oldEtag); + long currentTime = new Date().getTime(); + servletRequest.addHeader("If-Modified-Since", currentTime); + + assertFalse(request.checkNotModified(currentETag, currentTime)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals(currentETag, servletResponse.getHeader("ETag")); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkNotModifiedETagWeakStrong() { + String eTag = "\"Foo\""; + String weakEtag = String.format("W/%s", eTag); + servletRequest.addHeader("If-None-Match", eTag); + + assertTrue(request.checkNotModified(weakEtag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(weakEtag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedETagStrongWeak() { + String eTag = "\"Foo\""; + servletRequest.addHeader("If-None-Match", String.format("W/%s", eTag)); + + assertTrue(request.checkNotModified(eTag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedMultipleETags() { + String eTag = "\"Bar\""; + String multipleETags = String.format("\"Foo\", %s", eTag); + servletRequest.addHeader("If-None-Match", multipleETags); + + assertTrue(request.checkNotModified(eTag)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals(eTag, servletResponse.getHeader("ETag")); + } + + @Test + public void checkNotModifiedTimestampWithLengthPart() throws Exception { + long currentTime = dateFormat.parse("Wed, 09 Apr 2014 09:57:42 GMT").getTime(); + servletRequest.setMethod("GET"); + servletRequest.addHeader("If-Modified-Since", "Wed, 09 Apr 2014 09:57:42 GMT; length=13774"); + + assertTrue(request.checkNotModified(currentTime)); + + assertEquals(304, servletResponse.getStatus()); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + + @Test + public void checkModifiedTimestampWithLengthPart() throws Exception { + long currentTime = dateFormat.parse("Wed, 09 Apr 2014 09:57:42 GMT").getTime(); + servletRequest.setMethod("GET"); + servletRequest.addHeader("If-Modified-Since", "Wed, 08 Apr 2014 09:57:42 GMT; length=13774"); + + assertFalse(request.checkNotModified(currentTime)); + + assertEquals(200, servletResponse.getStatus()); + assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); + } + +} diff --git a/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java index dc3ad4b062..75fed80b84 100644 --- a/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java +++ b/spring-web/src/test/java/org/springframework/web/context/request/ServletWebRequestTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,9 +16,11 @@ package org.springframework.web.context.request; -import java.util.Date; +import static org.junit.Assert.*; + import java.util.Locale; import java.util.Map; + import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; @@ -33,12 +35,8 @@ import org.springframework.mock.web.test.MockHttpServletRequest; import org.springframework.mock.web.test.MockHttpServletResponse; import org.springframework.web.multipart.MultipartRequest; -import static org.junit.Assert.*; - /** * @author Juergen Hoeller - * @author Markus Malkusch - * @since 26.07.2006 */ public class ServletWebRequestTests { @@ -116,113 +114,4 @@ public class ServletWebRequestTests { assertNull(request.getNativeResponse(MultipartRequest.class)); } - @Test - public void checkNotModifiedTimestampForGET() { - long currentTime = new Date().getTime(); - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-Modified-Since", currentTime); - - assertTrue(request.checkNotModified(currentTime)); - assertEquals(304, servletResponse.getStatus()); - } - - @Test - public void checkModifiedTimestampForGET() { - long currentTime = new Date().getTime(); - long oneMinuteAgo = currentTime - (1000 * 60); - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); - - assertFalse(request.checkNotModified(currentTime)); - assertEquals(200, servletResponse.getStatus()); - assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); - } - - @Test - public void checkNotModifiedTimestampForHEAD() { - long currentTime = new Date().getTime(); - servletRequest.setMethod("HEAD"); - servletRequest.addHeader("If-Modified-Since", currentTime); - - assertTrue(request.checkNotModified(currentTime)); - assertEquals(304, servletResponse.getStatus()); - } - - @Test - public void checkModifiedTimestampForHEAD() { - long currentTime = new Date().getTime(); - long oneMinuteAgo = currentTime - (1000 * 60); - servletRequest.setMethod("HEAD"); - servletRequest.addHeader("If-Modified-Since", oneMinuteAgo); - - assertFalse(request.checkNotModified(currentTime)); - assertEquals(200, servletResponse.getStatus()); - assertEquals(""+currentTime, servletResponse.getHeader("Last-Modified")); - } - - @Test - public void checkNotModifiedTimestampWithLengthPart() { - long currentTime = Date.parse("Wed, 09 Apr 2014 09:57:42 GMT"); - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-Modified-Since", "Wed, 09 Apr 2014 09:57:42 GMT; length=13774"); - - assertTrue(request.checkNotModified(currentTime)); - assertEquals(304, servletResponse.getStatus()); - } - - @Test - public void checkModifiedTimestampWithLengthPart() { - long currentTime = Date.parse("Wed, 09 Apr 2014 09:57:42 GMT"); - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-Modified-Since", "Wed, 08 Apr 2014 09:57:42 GMT; length=13774"); - - assertFalse(request.checkNotModified(currentTime)); - assertEquals(200, servletResponse.getStatus()); - assertEquals("" + currentTime, servletResponse.getHeader("Last-Modified")); - } - - @Test - public void checkNotModifiedETagForGET() { - String eTag = "\"Foo\""; - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-None-Match", eTag ); - - assertTrue(request.checkNotModified(eTag)); - assertEquals(304, servletResponse.getStatus()); - } - - @Test - public void checkModifiedETagForGET() { - String currentETag = "\"Foo\""; - String oldEtag = "Bar"; - servletRequest.setMethod("GET"); - servletRequest.addHeader("If-None-Match", oldEtag); - - assertFalse(request.checkNotModified(currentETag)); - assertEquals(200, servletResponse.getStatus()); - assertEquals(currentETag, servletResponse.getHeader("ETag")); - } - - @Test - public void checkNotModifiedETagForHEAD() { - String eTag = "\"Foo\""; - servletRequest.setMethod("HEAD"); - servletRequest.addHeader("If-None-Match", eTag ); - - assertTrue(request.checkNotModified(eTag)); - assertEquals(304, servletResponse.getStatus()); - } - - @Test - public void checkModifiedETagForHEAD() { - String currentETag = "\"Foo\""; - String oldEtag = "Bar"; - servletRequest.setMethod("HEAD"); - servletRequest.addHeader("If-None-Match", oldEtag); - - assertFalse(request.checkNotModified(currentETag)); - assertEquals(200, servletResponse.getStatus()); - assertEquals(currentETag, servletResponse.getHeader("ETag")); - } - -} +} \ No newline at end of file diff --git a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java index 29b65b765d..ea1e359e86 100644 --- a/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java +++ b/spring-webmvc-portlet/src/main/java/org/springframework/web/portlet/context/PortletWebRequest.java @@ -162,6 +162,17 @@ public class PortletWebRequest extends PortletRequestAttributes implements Nativ return false; } + /** + * Last-modified handling not supported for portlet requests: + * As a consequence, this method always returns {@code false}. + * + * @since 4.2 + */ + @Override + public boolean checkNotModified(String etag, long lastModifiedTimestamp) { + return false; + } + @Override public String getDescription(boolean includeClientInfo) { PortletRequest request = getRequest();