diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java index 1e0bc98a56..2e8b210130 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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,8 +21,11 @@ import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumSet; import java.util.List; import java.util.Map; +import java.util.Set; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -66,6 +69,8 @@ import org.springframework.web.servlet.support.RequestContextUtils; */ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor { + private static final Set SAFE_METHODS = EnumSet.of(HttpMethod.GET, HttpMethod.HEAD); + /** * Basic constructor with converters only. Suitable for resolving * {@code HttpEntity}. For handling {@code ResponseEntity} consider also @@ -199,7 +204,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro int returnStatus = ((ResponseEntity) responseEntity).getStatusCodeValue(); outputMessage.getServletResponse().setStatus(returnStatus); if (returnStatus == 200) { - if (isResourceNotModified(inputMessage, outputMessage)) { + if (SAFE_METHODS.contains(inputMessage.getMethod()) + && isResourceNotModified(inputMessage, outputMessage)) { // Ensure headers are flushed, no body should be written. outputMessage.flush(); // Skip call to converters, as they may update the body. diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java index 50c030042c..05f04c3669 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/HttpEntityMethodProcessorMockTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2017 the original author or authors. + * Copyright 2002-2018 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. @@ -22,6 +22,7 @@ import java.net.URI; import java.nio.charset.StandardCharsets; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -558,6 +559,21 @@ public class HttpEntityMethodProcessorMockTests { assertConditionalResponse(HttpStatus.OK, "body", etagValue, -1); } + @Test + public void shouldNotFailPreconditionForPutRequests() throws Exception { + servletRequest.setMethod("PUT"); + ZonedDateTime dateTime = ofEpochMilli(new Date().getTime()).atZone(GMT); + servletRequest.addHeader(HttpHeaders.IF_UNMODIFIED_SINCE, RFC_1123_DATE_TIME.format(dateTime)); + + long justModified = dateTime.plus(1, ChronoUnit.SECONDS).toEpochSecond() * 1000; + ResponseEntity returnValue = ResponseEntity.ok() + .lastModified(justModified).body("body"); + initStringMessageConversion(TEXT_PLAIN); + processor.handleReturnValue(returnValue, returnTypeResponseEntity, mavContainer, webRequest); + + assertConditionalResponse(HttpStatus.OK, null, null, justModified); + } + @Test public void varyHeader() throws Exception { String[] entityValues = {"Accept-Language", "User-Agent"};