Skip to content

Commit 573e74b

Browse files
Russell Bollessdeleuze
Russell Bolles
authored andcommitted
Refine FormHttpMessageConverter exception handling
FormHttpMessageConverter could throw a more specific HttpMessageNotReadableException instead of an IllegalArgumentException when the http form data is invalid. See gh-34594 Signed-off-by: Russell Bolles <[email protected]>
1 parent 6c23180 commit 573e74b

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

Diff for: spring-web/src/main/java/org/springframework/http/converter/FormHttpMessageConverter.java

+14-4
Original file line numberDiff line numberDiff line change
@@ -353,12 +353,22 @@ public MultiValueMap<String, String> read(@Nullable Class<? extends MultiValueMa
353353
for (String pair : pairs) {
354354
int idx = pair.indexOf('=');
355355
if (idx == -1) {
356-
result.add(URLDecoder.decode(pair, charset), null);
356+
try {
357+
result.add(URLDecoder.decode(pair, charset), null);
358+
}
359+
catch (IllegalArgumentException ex) {
360+
throw new HttpMessageNotReadableException("Could not decode HTTP form payload", ex, inputMessage);
361+
}
357362
}
358363
else {
359-
String name = URLDecoder.decode(pair.substring(0, idx), charset);
360-
String value = URLDecoder.decode(pair.substring(idx + 1), charset);
361-
result.add(name, value);
364+
try {
365+
String name = URLDecoder.decode(pair.substring(0, idx), charset);
366+
String value = URLDecoder.decode(pair.substring(idx + 1), charset);
367+
result.add(name, value);
368+
}
369+
catch (IllegalArgumentException ex) {
370+
throw new HttpMessageNotReadableException("Could not decode HTTP form payload", ex, inputMessage);
371+
}
362372
}
363373
}
364374
return result;

Diff for: spring-web/src/test/java/org/springframework/http/converter/FormHttpMessageConverterTests.java

+33
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
import static java.nio.charset.StandardCharsets.UTF_8;
5151
import static org.assertj.core.api.Assertions.assertThat;
52+
import static org.assertj.core.api.Assertions.assertThatThrownBy;
5253
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
5354
import static org.springframework.http.MediaType.APPLICATION_JSON;
5455
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
@@ -132,6 +133,27 @@ void readForm() throws Exception {
132133
assertThat(result.getFirst("name 3")).as("Invalid result").isNull();
133134
}
134135

136+
@Test
137+
void readInvalidFormWithValueThatWontUrlDecode() {
138+
//java.net.URLDecoder doesn't like negative integer values after a % character
139+
String body = "name+1=value+1&name+2=value+2%" + ((char)-1);
140+
assertInvalidFormIsRejectedWithSpecificException(body);
141+
}
142+
143+
@Test
144+
void readInvalidFormWithNameThatWontUrlDecode() {
145+
//java.net.URLDecoder doesn't like negative integer values after a % character
146+
String body = "name+1=value+1&name+2%" + ((char)-1) + "=value+2";
147+
assertInvalidFormIsRejectedWithSpecificException(body);
148+
}
149+
150+
@Test
151+
void readInvalidFormWithNameWithNoValueThatWontUrlDecode() {
152+
//java.net.URLDecoder doesn't like negative integer values after a % character
153+
String body = "name+1=value+1&name+2%" + ((char)-1);
154+
assertInvalidFormIsRejectedWithSpecificException(body);
155+
}
156+
135157
@Test
136158
void writeForm() throws IOException {
137159
MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
@@ -410,6 +432,17 @@ private void assertCannotWrite(MediaType mediaType) {
410432
assertThat(this.converter.canWrite(clazz, mediaType)).as(clazz.getSimpleName() + " : " + mediaType).isFalse();
411433
}
412434

435+
private void assertInvalidFormIsRejectedWithSpecificException(String body) {
436+
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes(StandardCharsets.ISO_8859_1));
437+
inputMessage.getHeaders().setContentType(
438+
new MediaType("application", "x-www-form-urlencoded", StandardCharsets.ISO_8859_1));
439+
440+
assertThatThrownBy(() -> this.converter.read(null, inputMessage))
441+
.isInstanceOf(HttpMessageNotReadableException.class)
442+
.hasCauseInstanceOf(IllegalArgumentException.class)
443+
.hasMessage("Could not decode HTTP form payload");
444+
}
445+
413446

414447
private static class MockHttpOutputMessageRequestContext implements UploadContext {
415448

0 commit comments

Comments
 (0)