Add all non-file parts as request parameters

Closes gh-26400
This commit is contained in:
Rossen Stoyanchev 2021-01-19 20:49:28 +00:00
parent 4779323d33
commit 584dabbb39
2 changed files with 26 additions and 32 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,6 +17,7 @@
package org.springframework.test.web.servlet.request; package org.springframework.test.web.servlet.request;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.net.URI; import java.net.URI;
import java.nio.charset.Charset; import java.nio.charset.Charset;
@ -38,7 +39,6 @@ import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.multipart.MultipartFile;
/** /**
* Default builder for {@link MockMultipartHttpServletRequest}. * Default builder for {@link MockMultipartHttpServletRequest}.
@ -144,47 +144,40 @@ public class MockMultipartHttpServletRequestBuilder extends MockHttpServletReque
@Override @Override
protected final MockHttpServletRequest createServletRequest(ServletContext servletContext) { protected final MockHttpServletRequest createServletRequest(ServletContext servletContext) {
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(servletContext); MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(servletContext);
Charset defaultCharset = (request.getCharacterEncoding() != null ?
Charset.forName(request.getCharacterEncoding()) : StandardCharsets.UTF_8);
this.files.forEach(request::addFile); this.files.forEach(request::addFile);
this.parts.values().stream().flatMap(Collection::stream).forEach(part -> { this.parts.values().stream().flatMap(Collection::stream).forEach(part -> {
request.addPart(part); request.addPart(part);
try { try {
MultipartFile file = asMultipartFile(part); String name = part.getName();
if (file != null) { String filename = part.getSubmittedFileName();
request.addFile(file); InputStream is = part.getInputStream();
return; if (filename != null) {
request.addFile(new MockMultipartFile(name, filename, part.getContentType(), is));
} }
String value = toParameterValue(part); else {
if (value != null) { InputStreamReader reader = new InputStreamReader(is, getCharsetOrDefault(part, defaultCharset));
request.addParameter(part.getName(), toParameterValue(part)); String value = FileCopyUtils.copyToString(reader);
request.addParameter(part.getName(), value);
} }
} }
catch (IOException ex) { catch (IOException ex) {
throw new IllegalStateException("Failed to read content for part " + part.getName(), ex); throw new IllegalStateException("Failed to read content for part " + part.getName(), ex);
} }
}); });
return request; return request;
} }
@Nullable private Charset getCharsetOrDefault(Part part, Charset defaultCharset) {
private MultipartFile asMultipartFile(Part part) throws IOException { if (part.getContentType() != null) {
String name = part.getName(); MediaType mediaType = MediaType.parseMediaType(part.getContentType());
String filename = part.getSubmittedFileName(); if (mediaType.getCharset() != null) {
if (filename != null) { return mediaType.getCharset();
return new MockMultipartFile(name, filename, part.getContentType(), part.getInputStream()); }
} }
return null; return defaultCharset;
} }
@Nullable
private String toParameterValue(Part part) throws IOException {
String rawType = part.getContentType();
MediaType mediaType = (rawType != null ? MediaType.parseMediaType(rawType) : MediaType.TEXT_PLAIN);
if (!mediaType.isCompatibleWith(MediaType.TEXT_PLAIN)) {
return null;
}
Charset charset = (mediaType.getCharset() != null ? mediaType.getCharset() : StandardCharsets.UTF_8);
InputStreamReader reader = new InputStreamReader(part.getInputStream(), charset);
return FileCopyUtils.copyToString(reader);
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -50,7 +50,7 @@ public class MockMultipartHttpServletRequestBuilderTests {
assertThat(mockRequest.getParts()).extracting(Part::getName).containsExactly("name"); assertThat(mockRequest.getParts()).extracting(Part::getName).containsExactly("name");
} }
@Test // gh-26261 @Test // gh-26261, gh-26400
void addFileWithoutFilename() throws Exception { void addFileWithoutFilename() throws Exception {
MockPart jsonPart = new MockPart("data", "{\"node\":\"node\"}".getBytes(UTF_8)); MockPart jsonPart = new MockPart("data", "{\"node\":\"node\"}".getBytes(UTF_8));
jsonPart.getHeaders().setContentType(MediaType.APPLICATION_JSON); jsonPart.getHeaders().setContentType(MediaType.APPLICATION_JSON);
@ -62,7 +62,8 @@ public class MockMultipartHttpServletRequestBuilderTests {
.buildRequest(new MockServletContext()); .buildRequest(new MockServletContext());
assertThat(mockRequest.getFileMap()).containsOnlyKeys("file"); assertThat(mockRequest.getFileMap()).containsOnlyKeys("file");
assertThat(mockRequest.getParameterMap()).isEmpty(); assertThat(mockRequest.getParameterMap()).hasSize(1);
assertThat(mockRequest.getParameter("data")).isEqualTo("{\"node\":\"node\"}");
assertThat(mockRequest.getParts()).extracting(Part::getName).containsExactly("data"); assertThat(mockRequest.getParts()).extracting(Part::getName).containsExactly("data");
} }