Skip to content

Commit 0e3aa0e

Browse files
committed
Peek into the content for @RequestBody(required=false)
For @RequestBody(required=false), it is not sufficient to check if the InputStream is null. This change reads the first byte of the request InputStream to determine if the request body is empty or not. If the InputStream implementation supports mark(int) and reset(), then we use those. Otherwise we use PushbackInputStream to read and unread the first byte. All of this is done only if the required flag of @RequestBody is set to "false" (default is "true"). Issue: SPR-9942
1 parent 742d5f6 commit 0e3aa0e

File tree

1 file changed

+39
-7
lines changed

1 file changed

+39
-7
lines changed

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,21 @@
1717
package org.springframework.web.servlet.mvc.method.annotation;
1818

1919
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.io.PushbackInputStream;
2022
import java.lang.annotation.Annotation;
2123
import java.lang.reflect.Type;
2224
import java.util.List;
2325

26+
import javax.servlet.http.HttpServletRequest;
27+
2428
import org.springframework.core.Conventions;
2529
import org.springframework.core.MethodParameter;
2630
import org.springframework.core.annotation.AnnotationUtils;
2731
import org.springframework.http.HttpInputMessage;
2832
import org.springframework.http.converter.HttpMessageConverter;
2933
import org.springframework.http.converter.HttpMessageNotReadableException;
34+
import org.springframework.http.server.ServletServerHttpRequest;
3035
import org.springframework.validation.BindingResult;
3136
import org.springframework.validation.Errors;
3237
import org.springframework.web.HttpMediaTypeNotAcceptableException;
@@ -134,18 +139,45 @@ private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter pa
134139
}
135140

136141
@Override
137-
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
138-
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
142+
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest,
143+
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
139144

140-
if (inputMessage.getBody() != null) {
141-
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
142-
}
145+
final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
146+
HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest);
143147

144148
RequestBody annot = methodParam.getParameterAnnotation(RequestBody.class);
145149
if (!annot.required()) {
146-
return null;
150+
InputStream inputStream = inputMessage.getBody();
151+
if (inputStream == null) {
152+
return null;
153+
}
154+
else if (inputStream.markSupported()) {
155+
inputStream.mark(1);
156+
if (inputStream.read() == -1) {
157+
return null;
158+
}
159+
inputStream.reset();
160+
}
161+
else {
162+
final PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
163+
int b = pushbackInputStream.read();
164+
if (b == -1) {
165+
return null;
166+
}
167+
else {
168+
pushbackInputStream.unread(b);
169+
}
170+
inputMessage = new ServletServerHttpRequest(servletRequest) {
171+
@Override
172+
public InputStream getBody() throws IOException {
173+
// Form POST should not get here
174+
return pushbackInputStream;
175+
}
176+
};
177+
}
147178
}
148-
throw new HttpMessageNotReadableException("Required request body content is missing: " + methodParam.toString());
179+
180+
return super.readWithMessageConverters(inputMessage, methodParam, paramType);
149181
}
150182

151183
public void handleReturnValue(Object returnValue, MethodParameter returnType,

0 commit comments

Comments
 (0)