391080 Multipart temp files can be left on disk from Request.getPart and getParts

This commit is contained in:
Jan Bartel 2012-10-04 18:31:09 +10:00
parent 25cdef966c
commit 36a2ed10be
4 changed files with 92 additions and 13 deletions

View File

@ -50,6 +50,8 @@ import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -80,6 +82,7 @@ import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.MultiMap; import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.MultiPartInputStream; import org.eclipse.jetty.util.MultiPartInputStream;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
@ -123,12 +126,44 @@ import org.eclipse.jetty.util.log.Logger;
public class Request implements HttpServletRequest public class Request implements HttpServletRequest
{ {
public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig"; public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig";
public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.multiPartInputStream";
private static final Logger LOG = Log.getLogger(Request.class); private static final Logger LOG = Log.getLogger(Request.class);
private static final String __ASYNC_FWD = "org.eclipse.asyncfwd"; private static final String __ASYNC_FWD = "org.eclipse.asyncfwd";
private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault()); private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault());
private static final int __NONE = 0, _STREAM = 1, __READER = 2; private static final int __NONE = 0, _STREAM = 1, __READER = 2;
public static class MultiPartCleanerListener implements ServletRequestListener
{
@Override
public void requestDestroyed(ServletRequestEvent sre)
{
//Clean up any tmp files created by MultiPartInputStream
MultiPartInputStream mpis = (MultiPartInputStream)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM);
if (mpis != null)
{
try
{
mpis.deleteParts();
}
catch (MultiException e)
{
sre.getServletContext().log("Errors deleting multipart tmp files", e);
}
}
}
@Override
public void requestInitialized(ServletRequestEvent sre)
{
//nothing to do, multipart config set up by ServletHolder.handle()
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public static Request getRequest(HttpServletRequest request) public static Request getRequest(HttpServletRequest request)
{ {
@ -1975,6 +2010,7 @@ public class Request implements HttpServletRequest
_multiPartInputStream = new MultiPartInputStream(getInputStream(), _multiPartInputStream = new MultiPartInputStream(getInputStream(),
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT), getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
for (Part p:parts) for (Part p:parts)
{ {
@ -2006,6 +2042,7 @@ public class Request implements HttpServletRequest
_multiPartInputStream = new MultiPartInputStream(getInputStream(), _multiPartInputStream = new MultiPartInputStream(getInputStream(),
getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT), getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT),
(_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null));
setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream);
Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing
for (Part p:parts) for (Part p:parts)
{ {

View File

@ -514,6 +514,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
initJspServlet(); initJspServlet();
} }
initMultiPart();
_servlet.init(_config); _servlet.init(_config);
} }
catch (UnavailableException e) catch (UnavailableException e)
@ -570,6 +572,25 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
} }
} }
/* ------------------------------------------------------------ */
/**
* Register a ServletRequestListener that will ensure tmp multipart
* files are deleted when the request goes out of scope.
*
* @throws Exception
*/
protected void initMultiPart () throws Exception
{
//if this servlet can handle multipart requests, ensure tmp files will be
//cleaned up correctly
if (((Registration)getRegistration()).getMultipartConfig() != null)
{
//Register a listener to delete tmp files that are created as a result of this
//servlet calling Request.getPart() or Request.getParts()
ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler();
ch.addEventListener(new Request.MultiPartCleanerListener());
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**

View File

@ -84,7 +84,7 @@ import org.eclipse.jetty.util.TypeUtil;
public class MultiPartFilter implements Filter public class MultiPartFilter implements Filter
{ {
public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType"; public final static String CONTENT_TYPE_SUFFIX=".org.eclipse.jetty.servlet.contentType";
private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartInputStream"; private final static String MULTIPART = "org.eclipse.jetty.servlet.MultiPartFile.multiPartInputStream";
private File tempdir; private File tempdir;
private boolean _deleteFiles; private boolean _deleteFiles;
private ServletContext _context; private ServletContext _context;
@ -191,23 +191,24 @@ public class MultiPartFilter implements Filter
deleteFiles(request); deleteFiles(request);
} }
} }
/* ------------------------------------------------------------ */
private void deleteFiles(ServletRequest request) private void deleteFiles(ServletRequest request)
{ {
if (!_deleteFiles)
return;
MultiPartInputStream mpis = (MultiPartInputStream)request.getAttribute(MULTIPART); MultiPartInputStream mpis = (MultiPartInputStream)request.getAttribute(MULTIPART);
if (mpis != null) if (mpis != null)
{ {
Collection<Part> parts = mpis.getParsedParts(); try
for (Part p:parts)
{ {
try mpis.deleteParts();
{ }
p.delete(); catch (Exception e)
} {
catch(Exception e) _context.log("Error deleting multipart tmp files", e);
{
_context.log("Failed to delete "+p.getName(),e);
}
} }
} }
request.removeAttribute(MULTIPART); request.removeAttribute(MULTIPART);

View File

@ -236,7 +236,7 @@ public class MultiPartInputStream
*/ */
public long getSize() public long getSize()
{ {
return _size; return _size;
} }
/** /**
@ -322,6 +322,7 @@ public class MultiPartInputStream
_contextTmpDir = contextTmpDir; _contextTmpDir = contextTmpDir;
if (_contextTmpDir == null) if (_contextTmpDir == null)
_contextTmpDir = new File (System.getProperty("java.io.tmpdir")); _contextTmpDir = new File (System.getProperty("java.io.tmpdir"));
if (_config == null) if (_config == null)
_config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath()); _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath());
} }
@ -340,6 +341,25 @@ public class MultiPartInputStream
} }
return parts; return parts;
} }
public void deleteParts ()
throws MultiException
{
Collection<Part> parts = getParsedParts();
MultiException err = new MultiException();
for (Part p:parts)
{
try
{
p.delete();
}
catch(Exception e)
{
err.add(e);
}
}
err.ifExceptionThrowMulti();
}
public Collection<Part> getParts() public Collection<Part> getParts()