JETTY-1500 form parameters from multipart request not available via request.getParameter

This commit is contained in:
Jan Bartel 2012-03-20 18:35:21 +11:00
parent 3218298798
commit 9d54ea4cde
4 changed files with 112 additions and 9 deletions

View File

@ -65,6 +65,7 @@ import org.eclipse.jetty.http.HttpVersions;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferUtil;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
@ -1949,6 +1950,22 @@ public class Request implements HttpServletRequest
_multiPartInputStream = new MultiPartInputStream(getInputStream(),
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
for (Part p:parts)
{
MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p;
if (mp.getContentDispositionFilename() == null && mp.getFile() == null)
{
//Servlet Spec 3.0 pg 23, parts without filenames must be put into init params
String charset = null;
if (mp.getContentType() != null)
charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType()));
String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset);
getParameter(""); //cause params to be evaluated
getParameters().add(mp.getName(), content);
}
}
}
return _multiPartInputStream.getPart(name);
}
@ -1964,6 +1981,22 @@ public class Request implements HttpServletRequest
_multiPartInputStream = new MultiPartInputStream(getInputStream(),
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
for (Part p:parts)
{
MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p;
if (mp.getContentDispositionFilename() == null && mp.getFile() == null)
{
//Servlet Spec 3.0 pg 23, parts without filenames must be put into init params
String charset = null;
if (mp.getContentType() != null)
charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType()));
String content=new String(mp.getBytes(),charset==null?StringUtil.__UTF8:charset);
getParameter(""); //cause params to be evaluated
getParameters().add(mp.getName(), content);
}
}
}
return _multiPartInputStream.getParts();
}

View File

@ -18,6 +18,7 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import java.io.BufferedReader;
import java.io.File;
@ -35,6 +36,7 @@ import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import junit.framework.Assert;
@ -123,6 +125,51 @@ public class RequestTest
}
@Test
public void testMultiPart() throws Exception
{
_handler._checker = new RequestTester()
{
public boolean check(HttpServletRequest request,HttpServletResponse response)
{
try
{
Part foo = request.getPart("stuff");
assertNotNull(foo);
String value = request.getParameter("stuff");
byte[] expected = "000000000000000000000000000000000000000000000000000".getBytes("ISO-8859-1");
return value.equals(new String(expected, "ISO-8859-1"));
}
catch (Exception e)
{
e.printStackTrace();
return false;
}
}
};
String multipart = "--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\"\r\n"+
"Content-Type: text/plain;charset=ISO-8859-1\r\n"+
"\r\n"+
"000000000000000000000000000000000000000000000000000\r\n"+
"--AaB03x--\r\n";
String request="GET / HTTP/1.1\r\n"+
"Host: whatever\r\n"+
"Content-Type: multipart/form-data; boundary=\"AaB03x\"\r\n"+
"Content-Length: "+multipart.getBytes().length+"\r\n"+
"\r\n"+
multipart;
String responses=_connector.getResponses(request);
assertTrue(responses.startsWith("HTTP/1.1 200"));
}
@Test
public void testBadUtf8ParamExtraction() throws Exception
{
@ -833,7 +880,9 @@ public class RequestTest
{
((Request)request).setHandled(true);
if (request.getContentLength()>0 && !MimeTypes.FORM_ENCODED.equals(request.getContentType()))
if (request.getContentLength()>0
&& !MimeTypes.FORM_ENCODED.equals(request.getContentType())
&& !request.getContentType().startsWith("multipart/form-data"))
_content=IO.toString(request.getInputStream());
if (_checker!=null && _checker.check(request,response))

View File

@ -64,6 +64,7 @@ public class MultiPartInputStream
protected String _filename;
protected File _file;
protected OutputStream _out;
protected ByteArrayOutputStream2 _bout;
protected String _contentType;
protected MultiMap<String> _headers;
protected long _size = 0;
@ -95,7 +96,7 @@ public class MultiPartInputStream
{
//Write to a buffer in memory until we discover we've exceed the
//MultipartConfig fileSizeThreshold
_out = new ByteArrayOutputStream();
_out = _bout= new ByteArrayOutputStream2();
}
}
@ -142,8 +143,9 @@ public class MultiPartInputStream
{
//already written some bytes, so need to copy them into the file
_out.flush();
((ByteArrayOutputStream)_out).writeTo(bos);
_bout.writeTo(bos);
_out.close();
_bout = null;
}
_out = bos;
}
@ -199,10 +201,17 @@ public class MultiPartInputStream
else
{
//part content is in a ByteArrayOutputStream
return new ByteArrayInputStream(((ByteArrayOutputStream)_out).toByteArray());
return new ByteArrayInputStream(_bout.getBuf(),0,_bout.size());
}
}
public byte[] getBytes()
{
if (_bout!=null)
return _bout.toByteArray();
return null;
}
/**
* @see javax.servlet.http.Part#getName()
*/
@ -232,19 +241,22 @@ public class MultiPartInputStream
try
{
bos = new BufferedOutputStream(new FileOutputStream(_file));
((ByteArrayOutputStream)_out).writeTo(bos);
_bout.writeTo(bos);
bos.flush();
}
finally
{
if (bos != null)
bos.close();
_bout = null;
}
}
else
{
//the part data is already written to a temporary file, just rename it
_file.renameTo(new File(_tmpDir, fileName));
File f = new File(_tmpDir, fileName);
if (_file.renameTo(f))
_file = f;
}
}

View File

@ -131,11 +131,19 @@ public class MultiPartInputStreamTest extends TestCase
IO.copy(is, os);
assertEquals("Joe Blow", new String(os.toByteArray()));
assertEquals(8, field1.getSize());
assertNotNull(((MultiPartInputStream.MultiPart)field1).getBytes()); //in internal buffer
field1.write("field1.txt");
assertNull(((MultiPartInputStream.MultiPart)field1).getBytes()); //no longer in internal buffer
File f = new File (_dirname+File.separator+"field1.txt");
assertTrue(f.exists());
field1.delete();
assertFalse(f.exists());
field1.write("another_field1.txt");
File f2 = new File(_dirname+File.separator+"another_field1.txt");
assertTrue(f2.exists());
assertFalse(f.exists()); //should have been renamed
field1.delete(); //file should be deleted
assertFalse(f2.exists());
Part stuff = mpis.getPart("stuff");
assertEquals("text/plain", stuff.getContentType());
@ -146,6 +154,7 @@ public class MultiPartInputStreamTest extends TestCase
assertEquals(51, stuff.getSize());
f = ((MultiPartInputStream.MultiPart)stuff).getFile();
assertNotNull(f); // longer than 100 bytes, should already be a file
assertNull(((MultiPartInputStream.MultiPart)stuff).getBytes()); //not in internal buffer any more
assertTrue(f.exists());
assertNotSame("stuff.txt", f.getName());
stuff.write("stuff.txt");