From 0095ba89843cdc5d85a1d1f8703d2ca5249e9aa0 Mon Sep 17 00:00:00 2001 From: Michael Hartle Date: Tue, 26 Jul 2016 13:37:46 +0200 Subject: [PATCH 1/2] Fixed an issue where the pre FormBodyWrapperFilter adds multiples of every multipart part to a request --- .../cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java index 35a3a45a..4231ecc4 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilter.java @@ -184,10 +184,10 @@ public class FormBodyWrapperFilter extends ZuulFilter { MultipartRequest multi = (MultipartRequest) this.request; for (Entry> parts : multi .getMultiFileMap().entrySet()) { - for (Part file : this.request.getParts()) { + for (MultipartFile file : parts.getValue()) { HttpHeaders headers = new HttpHeaders(); headers.setContentDispositionFormData(file.getName(), - file.getSubmittedFileName()); + file.getOriginalFilename()); if (file.getContentType() != null) { headers.setContentType( MediaType.valueOf(file.getContentType())); From 8bb223f6e3975d1d2b5d692cdc7244c18eaca5ae Mon Sep 17 00:00:00 2001 From: Michael Hartle Date: Tue, 2 Aug 2016 12:15:15 +0200 Subject: [PATCH 2/2] Added a minimal test for FormBodyWrapperFilter handling multiple part names with multiple parts --- .../pre/FormBodyWrapperFilterTests.java | 188 ++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilterTests.java diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilterTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilterTests.java new file mode 100644 index 00000000..10ef5b4e --- /dev/null +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/filters/pre/FormBodyWrapperFilterTests.java @@ -0,0 +1,188 @@ +package org.springframework.cloud.netflix.zuul.filters.pre; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.Part; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockMultipartHttpServletRequest; + +import com.netflix.zuul.context.RequestContext; + +/** + * @author Michael Hartle + */ +public class FormBodyWrapperFilterTests { + + private FormBodyWrapperFilter filter; + + private MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest(); + + @Before + public void init() { + this.filter = new FormBodyWrapperFilter(); + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.clear(); + ctx.setRequest(this.request); + } + + @Test + public void multiplePartNamesWithMultipleParts() throws IOException, ServletException { + this.request.setRequestURI("/api/foo/1"); + this.request.setRemoteAddr("5.6.7.8"); + + final Map> firstPartHeaders = new HashMap<>(); + final byte[] firstPartBody = "{ \"u\" : 1 }".getBytes(); + final Part firstPart = new MockPart("a", "application/json", null, firstPartHeaders, firstPartBody); + this.request.addPart(firstPart); + + final Map> secondPartHeaders = new HashMap<>(); + final byte[] secondPartBody = "%PDF...1".getBytes(); + final Part secondPart = new MockPart("b", "application/pdf", "document.pdf", secondPartHeaders, secondPartBody); + this.request.addPart(secondPart); + + final Map> thirdPartHeaders = new HashMap<>(); + final byte[] thirdPartBody = "%PDF...2".getBytes(); + final Part thirdPart = new MockPart("c", "application/pdf", "attachment1.pdf", thirdPartHeaders, thirdPartBody); + this.request.addPart(thirdPart); + + final Map> fourthPartHeaders = new HashMap<>(); + final byte[] fourthPartBody = "%PDF...3".getBytes(); + final Part fourthPart = new MockPart("c", "application/pdf", "attachment2.pdf", fourthPartHeaders, fourthPartBody); + this.request.addPart(fourthPart); + + final Map> fifthPartHeaders = new HashMap<>(); + final byte[] fifthPartBody = "%PDF...4".getBytes(); + final Part fifthPart = new MockPart("c", "application/pdf", "attachment3.pdf", fifthPartHeaders, fifthPartBody); + this.request.addPart(fifthPart); + + this.filter.run(); + + final RequestContext ctx = RequestContext.getCurrentContext(); + assertEquals("/api/foo/1", ctx.getRequest().getRequestURI()); + assertEquals("5.6.7.8", ctx.getRequest().getRemoteAddr()); + assertEquals(5, ctx.getRequest().getParts().size()); + + final Part[] parts = ctx.getRequest().getParts().toArray(new Part[0]); + assertEquals("a", parts[0].getName()); + assertEquals(null, parts[0].getSubmittedFileName()); + assertEquals("application/json", parts[0].getContentType()); + assertArrayEquals(firstPartBody, IOUtils.toByteArray(parts[0].getInputStream())); + + assertEquals("b", parts[1].getName()); + assertEquals("document.pdf", parts[1].getSubmittedFileName()); + assertEquals("application/pdf", parts[1].getContentType()); + assertArrayEquals(secondPartBody, IOUtils.toByteArray(parts[1].getInputStream())); + + assertEquals("c", parts[2].getName()); + assertEquals("attachment1.pdf", parts[2].getSubmittedFileName()); + assertEquals("application/pdf", parts[2].getContentType()); + assertArrayEquals(thirdPartBody, IOUtils.toByteArray(parts[2].getInputStream())); + + assertEquals("c", parts[3].getName()); + assertEquals("attachment2.pdf", parts[3].getSubmittedFileName()); + assertEquals("application/pdf", parts[3].getContentType()); + assertArrayEquals(fourthPartBody, IOUtils.toByteArray(parts[3].getInputStream())); + + assertEquals("c", parts[4].getName()); + assertEquals("attachment3.pdf", parts[4].getSubmittedFileName()); + assertEquals("application/pdf", parts[4].getContentType()); + assertArrayEquals(fifthPartBody, IOUtils.toByteArray(parts[4].getInputStream())); + } + + private class MockPart implements Part { + private final String name; + private final String contentType; + private final String submittedFileName; + private final Map> headers; + private final byte[] body; + + public MockPart(final String name, final String contentType, final String submittedFileName, final Map> headers, final byte[] body) { + this.name = name; + this.contentType = contentType; + this.submittedFileName = submittedFileName; + this.headers = headers; + this.body = body; + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(this.body); + } + + @Override + public String getContentType() { + return this.contentType; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public String getSubmittedFileName() { + return this.submittedFileName; + } + + @Override + public long getSize() { + return this.body != null ? this.body.length : 0; + } + + @Override + public void write(String fileName) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public void delete() throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public String getHeader(String name) { + if (this.headers == null) { + return null; + } + + final List values = this.headers.get(name); + + if (values == null || values.size() == 0) { + return null; + } + + return values.get(0); + } + + @Override + public Collection getHeaders(String name) { + if (this.headers == null) { + return null; + } + + return this.headers.get(name); + } + + @Override + public Collection getHeaderNames() { + if (this.headers == null) { + return null; + } + + return this.headers.keySet(); + } + } +}