383116: fix truncated filenames for multipart file uploads containing spaces in filename

This commit is contained in:
Thomas Becker 2012-06-20 17:16:33 +02:00
parent 571b1da632
commit 9410a8d81c
2 changed files with 62 additions and 39 deletions

View File

@ -371,7 +371,7 @@ public class MultiPartInputStream
if (!_tmpDir.exists()) if (!_tmpDir.exists())
_tmpDir.mkdirs(); _tmpDir.mkdirs();
String boundary="--"+QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary="))).trim()); String boundary="--"+QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary=")), true).trim());
byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1); byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1);
// Get first boundary // Get first boundary
@ -440,9 +440,9 @@ public class MultiPartInputStream
if(t.startsWith("form-data")) if(t.startsWith("form-data"))
form_data=true; form_data=true;
else if(tl.startsWith("name=")) else if(tl.startsWith("name="))
name=value(t); name=value(t, true);
else if(tl.startsWith("filename=")) else if(tl.startsWith("filename="))
filename=value(t); filename=value(t, false);
} }
// Check disposition // Check disposition
@ -588,7 +588,7 @@ public class MultiPartInputStream
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
private String value(String nameEqualsValue) private String value(String nameEqualsValue, boolean splitAfterSpace)
{ {
String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim(); String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
int i=value.indexOf(';'); int i=value.indexOf(';');
@ -598,7 +598,7 @@ public class MultiPartInputStream
{ {
value=value.substring(1,value.indexOf('"',1)); value=value.substring(1,value.indexOf('"',1));
} }
else else if (splitAfterSpace)
{ {
i=value.indexOf(' '); i=value.indexOf(' ');
if(i>0) if(i>0)

View File

@ -13,9 +13,16 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertThat;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Collection; import java.util.Collection;
@ -25,6 +32,8 @@ import javax.servlet.http.Part;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.eclipse.jetty.util.MultiPartInputStream.MultiPart;
/** /**
* MultiPartInputStreamTest * MultiPartInputStreamTest
* *
@ -32,19 +41,9 @@ import junit.framework.TestCase;
*/ */
public class MultiPartInputStreamTest extends TestCase public class MultiPartInputStreamTest extends TestCase
{ {
private static final String FILENAME = "stuff.txt";
protected String _contentType = "multipart/form-data, boundary=AaB03x"; protected String _contentType = "multipart/form-data, boundary=AaB03x";
protected String _multi = protected String _multi = createMultipartRequestString(FILENAME);
"--AaB03x\r\n"+
"content-disposition: form-data; name=\"field1\"\r\n"+
"\r\n"+
"Joe Blow\r\n"+
"--AaB03x\r\n"+
"content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+
"Content-Type: text/plain\r\n"+
"\r\n"+
"000000000000000000000000000000000000000000000000000\r\n"+
"--AaB03x--\r\n";
protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis(); protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis();
@ -114,18 +113,28 @@ public class MultiPartInputStreamTest extends TestCase
public void testMulti () public void testMulti ()
throws Exception throws Exception
{
testMulti(FILENAME);
}
public void testMultiWithSpaceInFilename() throws Exception
{
testMulti("stuff with spaces.txt");
}
private void testMulti(String filename) throws IOException, ServletException
{ {
MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50);
MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(createMultipartRequestString(filename).getBytes()),
_contentType, _contentType,
config, config,
new File(_dirname)); new File(_dirname));
Collection<Part> parts = mpis.getParts(); Collection<Part> parts = mpis.getParts();
assertEquals(2, parts.size()); assertThat(parts.size(), is(2));
Part field1 = mpis.getPart("field1"); Part field1 = mpis.getPart("field1");
assertNotNull(field1); assertThat(field1,notNullValue());
assertEquals("field1", field1.getName()); assertThat(field1.getName(),is("field1"));
InputStream is = field1.getInputStream(); InputStream is = field1.getInputStream();
ByteArrayOutputStream os = new ByteArrayOutputStream(); ByteArrayOutputStream os = new ByteArrayOutputStream();
IO.copy(is, os); IO.copy(is, os);
@ -143,23 +152,23 @@ public class MultiPartInputStreamTest extends TestCase
assertFalse(f.exists()); //should have been renamed assertFalse(f.exists()); //should have been renamed
field1.delete(); //file should be deleted field1.delete(); //file should be deleted
assertFalse(f2.exists()); assertFalse(f2.exists());
Part stuff = mpis.getPart("stuff"); MultiPart stuff = (MultiPart)mpis.getPart("stuff");
assertEquals("text/plain", stuff.getContentType()); assertThat(stuff.getContentDispositionFilename(), is(filename));
assertEquals("text/plain", stuff.getHeader("Content-Type")); assertThat(stuff.getContentType(),is("text/plain"));
assertEquals(1, stuff.getHeaders("content-type").size()); assertThat(stuff.getHeader("Content-Type"),is("text/plain"));
assertEquals("form-data; name=\"stuff\"; filename=\"stuff.txt\"", stuff.getHeader("content-disposition")); assertThat(stuff.getHeaders("content-type").size(),is(1));
assertEquals(2, stuff.getHeaderNames().size()); assertThat(stuff.getHeader("content-disposition"),is("form-data; name=\"stuff\"; filename=\"" + filename + "\""));
assertEquals(51, stuff.getSize()); assertThat(stuff.getHeaderNames().size(),is(2));
assertThat(stuff.getSize(),is(51L));
f = ((MultiPartInputStream.MultiPart)stuff).getFile(); f = ((MultiPartInputStream.MultiPart)stuff).getFile();
assertNotNull(f); // longer than 100 bytes, should already be a file assertThat(f,notNullValue()); // longer than 100 bytes, should already be a file
assertNull(((MultiPartInputStream.MultiPart)stuff).getBytes()); //not in internal buffer any more assertThat(((MultiPartInputStream.MultiPart)stuff).getBytes(),nullValue()); //not in internal buffer any more
assertTrue(f.exists()); assertThat(f.exists(),is(true));
assertNotSame("stuff.txt", f.getName()); assertThat(f.getName(),is(not("stuff with space.txt")));
stuff.write("stuff.txt"); stuff.write(filename);
f = new File(_dirname+File.separator+"stuff.txt"); f = new File(_dirname+File.separator+filename);
assertTrue(f.exists()); assertThat(f.exists(),is(true));
} }
public void testMultiSameNames () public void testMultiSameNames ()
@ -193,4 +202,18 @@ public class MultiPartInputStreamTest extends TestCase
assertNotNull(p); assertNotNull(p);
assertEquals(5, p.getSize()); assertEquals(5, p.getSize());
} }
private String createMultipartRequestString(String filename)
{
return "--AaB03x\r\n"+
"content-disposition: form-data; name=\"field1\"\r\n"+
"\r\n"+
"Joe Blow\r\n"+
"--AaB03x\r\n"+
"content-disposition: form-data; name=\"stuff\"; filename=\"" + filename + "\"\r\n"+
"Content-Type: text/plain\r\n"+
"\r\n"+
"000000000000000000000000000000000000000000000000000\r\n"+
"--AaB03x--\r\n";
}
} }