diff options
4 files changed, 124 insertions, 5 deletions
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java index 623a0af6c0..4a5c483586 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java @@ -104,6 +104,7 @@ public class MultiPartFilter implements Filter private boolean _deleteFiles; private ServletContext _context; private int _fileOutputBuffer = 0; + private boolean _writeFilesWithFilenames = false; private long _maxFileSize = -1L; private long _maxRequestSize = -1L; private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys", 1000); @@ -130,6 +131,7 @@ public class MultiPartFilter implements Filter String mfks = filterConfig.getInitParameter("maxFormKeys"); if (mfks!=null) _maxFormKeys=Integer.parseInt(mfks); + _writeFilesWithFilenames = "true".equalsIgnoreCase(filterConfig.getInitParameter("writeFilesWithFilenames")); } /* ------------------------------------------------------------------------------- */ @@ -164,6 +166,7 @@ public class MultiPartFilter implements Filter MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer); MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(in, content_type, config, tempdir); mpis.setDeleteOnExit(_deleteFiles); + mpis.setWriteFilesWithFilenames(_writeFilesWithFilenames); request.setAttribute(MULTIPART, mpis); try { diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java index 01cdb45637..c3b43e4750 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java @@ -54,7 +54,17 @@ public class MultipartFilterTest { private File _dir; private ServletTester tester; - + FilterHolder multipartFilter; + + public static class FilenameServlet extends TestServlet + { + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException + { + assertNotNull(req.getAttribute("fileup")); + super.doPost(req, resp); + } + } public static class BoundaryServlet extends TestServlet { @@ -113,7 +123,7 @@ public class MultipartFilterTest tester.getContext().setResourceBase(_dir.getCanonicalPath()); tester.getContext().addServlet(TestServlet.class, "/"); tester.getContext().setAttribute("javax.servlet.context.tempdir", _dir); - FilterHolder multipartFilter = tester.getContext().addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST)); + multipartFilter = tester.getContext().addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST)); multipartFilter.setInitParameter("deleteFiles", "true"); multipartFilter.setInitParameter("fileOutputBuffer", "1"); //write a file if there's more than 1 byte content tester.start(); @@ -885,6 +895,60 @@ public class MultipartFilterTest response = HttpTester.parseResponse(tester.getResponses(request.generate())); } + + @Test + public void testFilesWithFilenames () + throws Exception + { + multipartFilter.setInitParameter("fileOutputBuffer", "0"); + multipartFilter.setInitParameter("writeFilesWithFilenames", "true"); + + + String boundary="XyXyXy"; + HttpTester.Request request = HttpTester.newRequest(); + HttpTester.Response response; + tester.addServlet(FilenameServlet.class,"/testf"); + // test GET + request.setMethod("POST"); + request.setVersion("HTTP/1.0"); + request.setHeader("Host","tester"); + request.setURI("/context/testf"); + request.setHeader("Content-Type","multipart/form-data; boundary="+boundary); + + String content = "--XyXyXy\r"+ + "Content-Disposition: form-data; name=\"fileName\"\r"+ + "Content-Type: text/plain; charset=US-ASCII\r"+ + "Content-Transfer-Encoding: 8bit\r"+ + "\r"+ + "abc\r"+ + "--XyXyXy\r"+ + "Content-Disposition: form-data; name=\"desc\"\r"+ + "Content-Type: text/plain; charset=US-ASCII\r"+ + "Content-Transfer-Encoding: 8bit\r"+ + "\r"+ + "123\r"+ + "--XyXyXy\r"+ + "Content-Disposition: form-data; name=\"title\"\r"+ + "Content-Type: text/plain; charset=US-ASCII\r"+ + "Content-Transfer-Encoding: 8bit\r"+ + "\r"+ + "ttt\r"+ + "--XyXyXy\r"+ + "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r"+ + "Content-Type: application/octet-stream\r"+ + "Content-Transfer-Encoding: binary\r"+ + "\r"+ + "000\r"+ + "--XyXyXy--\r"; + request.setContent(content); + + response = HttpTester.parseResponse(tester.getResponses(request.generate())); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + assertTrue(response.getContent().indexOf("000")>=0); + } + + + public static class DumpServlet extends HttpServlet { private static final long serialVersionUID = 201012011130L; diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java index 946d708c30..7703835ce0 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStreamParser.java @@ -63,6 +63,7 @@ public class MultiPartInputStreamParser protected File _tmpDir; protected File _contextTmpDir; protected boolean _deleteOnExit; + protected boolean _writeFilesWithFilenames; @@ -94,9 +95,19 @@ public class MultiPartInputStreamParser protected void open() throws IOException { - //Write to a buffer in memory until we discover we've exceed the - //MultipartConfig fileSizeThreshold - _out = _bout= new ByteArrayOutputStream2(); + //We will either be writing to a file, if it has a filename on the content-disposition + //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we + //will need to change to write to a file. + if (isWriteFilesWithFilenames() && _filename != null && _filename.trim().length() > 0) + { + createFile(); + } + else + { + //Write to a buffer in memory until we discover we've exceed the + //MultipartConfig fileSizeThreshold + _out = _bout= new ByteArrayOutputStream2(); + } } protected void close() @@ -744,6 +755,15 @@ public class MultiPartInputStreamParser _deleteOnExit = deleteOnExit; } + public void setWriteFilesWithFilenames (boolean writeFilesWithFilenames) + { + _writeFilesWithFilenames = writeFilesWithFilenames; + } + + public boolean isWriteFilesWithFilenames () + { + return _writeFilesWithFilenames; + } public boolean isDeleteOnExit() { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java index 6f164620b9..293fb3d6de 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -657,6 +657,38 @@ public class MultiPartInputStreamTest } + @Test + public void testWriteFilesIfContentDispositionFilename () + throws Exception + { + String s = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"; filename=\"frooble.txt\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+"sss"+ + "aaa"+"\r\n" + + "--AaB03x--\r\n"; + //all default values for multipartconfig, ie file size threshold 0 + MultipartConfigElement config = new MultipartConfigElement(_dirname); + MultiPartInputStreamParser mpis = new MultiPartInputStreamParser(new ByteArrayInputStream(s.getBytes()), + _contentType, + config, + _tmpDir); + mpis.setDeleteOnExit(true); + mpis.setWriteFilesWithFilenames(true); + Collection<Part> parts = mpis.getParts(); + assertThat(parts.size(), is(2)); + Part field1 = mpis.getPart("field1"); //has a filename, should be written to a file + File f = ((MultiPartInputStreamParser.MultiPart)field1).getFile(); + assertThat(f,notNullValue()); // longer than 100 bytes, should already be a tmp file + + Part stuff = mpis.getPart("stuff"); + f = ((MultiPartInputStreamParser.MultiPart)stuff).getFile(); //should only be in memory, no filename + assertThat(f, nullValue()); + } private void testMulti(String filename) throws IOException, ServletException, InterruptedException |