JBossWeb SVN: r1537 - sandbox/webapps/src.
by jbossweb-commits@lists.jboss.org
Author: jfrederic.clere(a)jboss.com
Date: 2010-08-18 12:27:58 -0400 (Wed, 18 Aug 2010)
New Revision: 1537
Modified:
sandbox/webapps/src/MyCookies.java
Log:
test for issue 1183773.
Modified: sandbox/webapps/src/MyCookies.java
===================================================================
--- sandbox/webapps/src/MyCookies.java 2010-08-18 15:14:24 UTC (rev 1536)
+++ sandbox/webapps/src/MyCookies.java 2010-08-18 16:27:58 UTC (rev 1537)
@@ -61,8 +61,8 @@
HttpServletResponse response)
throws IOException, ServletException
{
+ String action = request.getParameter("test");
-
response.setContentType("text/html");
Enumeration names = request.getHeaderNames();
@@ -79,6 +79,11 @@
String title = "sessions.title";
out.println("<title>" + title + "</title>");
+
+ if (action != null && action.compareToIgnoreCase("meta") == 0) {
+ out.println("<meta http-equiv=\"set-cookie\" content=\"RH-Test-Cookie=testcookie::aftercolon; expires=Fri, 31 Dec 2010 23:59:59 GMT; path=/\">");
+ }
+
out.println("</head>");
out.println("<body>");
@@ -87,7 +92,7 @@
/*
* create the name/value pairs
*/
- Test[] mytest = new Test[13];
+ Test[] mytest = new Test[14];
StringBuffer buffer = new StringBuffer();
buffer.append("<xml><name>John Doe</name><age attribute=\"this breaks\">45</age></xml>");
mytest[0] = new Test("xmlCookie",buffer.toString());
@@ -105,6 +110,7 @@
mytest[11] = new Test("Quoted9","I am \r\n testing...");
// mytest[12] = new Test("Equal","P=I am = Equal\n...&A=46164");
mytest[12] = new Test("Equal","P=14662+26891+20253+28934+15744+22344+43641+13624+28974+15489+35353+47293+14662+26891+20253+28934+28596+27065+28648+22542&L=60766+6654+19186+43352+58684+61932+37440+23672&A=46164+56607+41861+51054&S=46164+56607+41861+51054&T=23922+55384+5601+51160+38643+36027+49212+16265+61873+55260+16665+53468&X=12795+26412+43746+37688&U=47207+55215+24609+16813+46164+56607+41861+51054&D=36080+20612+7827+5411+35188+54326+19636+46695+27748+646+37165+34626&C=11656+47389+63649+49622+46164+56607+41861+51054&");
+ mytest[13] = new Test("RH-Test-Cookie" , "testcookie::aftercolon; expires=Fri, 31 Dec 2010 23:59:59 GMT; path=/");
Cookie[] cookies = request.getCookies();
if(cookies != null) {
for(int i=0;i<cookies.length;i++) {
@@ -116,17 +122,19 @@
}
/* create the cookies */
- for (int i=0; i<mytest.length; i++) {
- try {
- Cookie cookie = CreateCookie(mytest[i]);
+ if (action == null || (action != null && action.compareToIgnoreCase("meta") != 0)) {
+ for (int i=0; i<mytest.length; i++) {
+ try {
+ Cookie cookie = CreateCookie(mytest[i]);
+ response.addCookie(cookie);
+ } catch (Exception ex) {
+ out.println("Cookie test: " + i + " Failed<br>");
+ }
+ }
+ Cookie cookie = new Cookie("commented", "commented cookie");
+ cookie.setComment("This is a comment");
response.addCookie(cookie);
- } catch (Exception ex) {
- out.println("Cookie test: " + i + " Failed<br>");
- }
}
- Cookie cookie = new Cookie("commented", "commented cookie");
- cookie.setComment("This is a comment");
- response.addCookie(cookie);
out.println("<hr>");
14 years, 4 months
JBossWeb SVN: r1536 - sandbox/webapps/src.
by jbossweb-commits@lists.jboss.org
Author: jfrederic.clere(a)jboss.com
Date: 2010-08-18 11:14:24 -0400 (Wed, 18 Aug 2010)
New Revision: 1536
Modified:
sandbox/webapps/src/TestOutputStream.java
Log:
Add a test related to case 1172143.
Modified: sandbox/webapps/src/TestOutputStream.java
===================================================================
--- sandbox/webapps/src/TestOutputStream.java 2010-08-18 14:31:57 UTC (rev 1535)
+++ sandbox/webapps/src/TestOutputStream.java 2010-08-18 15:14:24 UTC (rev 1536)
@@ -69,6 +69,23 @@
e.printStackTrace();
}
}
+ public void doTest3(HttpServletRequest request,
+ HttpServletResponse response)
+ throws IOException, ServletException
+ {
+ response.setContentType("text/html");
+ OutputStream outs = response.getOutputStream();
+ for (;;) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ for (int i=0; i<90112;i++)
+ baos.write('A');
+
+ baos.writeTo(outs);
+ outs.flush();
+ }
+ // outs.close();
+ }
+
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
@@ -88,12 +105,15 @@
out.println("<h3>" + title + "</h3>");
out.println("use bla?test=1 for outputstream<br/>");
out.println("use bla?test=2 for closing it<br/>");
+ out.println("use bla?test=3 for endless write<br/>");
out.println("</body>");
out.println("</html>");
} else if (test.equals("1")) {
doTest1(request, response);
} else if (test.equals("2")) {
doTest2(request, response);
+ } else if (test.equals("3")) {
+ doTest3(request, response);
}
}
14 years, 4 months
JBossWeb SVN: r1535 - in trunk: webapps/docs and 1 other directory.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2010-08-18 10:31:57 -0400 (Wed, 18 Aug 2010)
New Revision: 1535
Modified:
trunk/java/org/apache/catalina/servlets/WebdavServlet.java
trunk/webapps/docs/changelog.xml
Log:
- Port webdav fix.
Modified: trunk/java/org/apache/catalina/servlets/WebdavServlet.java
===================================================================
--- trunk/java/org/apache/catalina/servlets/WebdavServlet.java 2010-08-18 12:40:08 UTC (rev 1534)
+++ trunk/java/org/apache/catalina/servlets/WebdavServlet.java 2010-08-18 14:31:57 UTC (rev 1535)
@@ -114,16 +114,17 @@
* http://host:port/context/webdavedit/content
*
* @author Remy Maucherat
- * @version $Revision$ $Date$
+ * @version $Id$
*/
public class WebdavServlet
extends DefaultServlet {
+ private static final long serialVersionUID = 1L;
+
// -------------------------------------------------------------- Constants
-
private static final String METHOD_PROPFIND = "PROPFIND";
private static final String METHOD_PROPPATCH = "PROPPATCH";
private static final String METHOD_MKCOL = "MKCOL";
@@ -259,6 +260,7 @@
/**
* Initialize this servlet.
*/
+ @Override
public void init()
throws ServletException {
@@ -309,6 +311,7 @@
/**
* Handles the special WebDAV methods.
*/
+ @Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
@@ -352,6 +355,7 @@
* and false if any of the conditions is not satisfied, in which case
* request processing is stopped
*/
+ @Override
protected boolean checkIfHeaders(HttpServletRequest request,
HttpServletResponse response,
ResourceAttributes resourceAttributes)
@@ -374,6 +378,7 @@
*
* @param request The servlet request we are processing
*/
+ @Override
protected String getRelativePath(HttpServletRequest request) {
// Are we being processed by a RequestDispatcher.include()?
if (request.getAttribute(RequestDispatcher.INCLUDE_REQUEST_URI) != null) {
@@ -402,6 +407,7 @@
* @throws ServletException If an error occurs
* @throws IOException If an IO error occurs
*/
+ @Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
@@ -506,6 +512,8 @@
if (type == FIND_BY_PROPERTY) {
properties = new Vector<String>();
+ // propNode must be non-null if type == FIND_BY_PROPERTY
+ @SuppressWarnings("null")
NodeList childList = propNode.getChildNodes();
for (int i=0; i < childList.getLength(); i++) {
@@ -555,13 +563,13 @@
new XMLWriter(resp.getWriter());
generatedXML.writeXMLHeader();
generatedXML.writeElement
- (null, "multistatus"
+ (null, "D:multistatus"
+ generateNamespaceDeclarations(),
XMLWriter.OPENING);
parseLockNullProperties
(req, generatedXML, lockNullPath, type,
properties);
- generatedXML.writeElement(null, "multistatus",
+ generatedXML.writeElement(null, "D:multistatus",
XMLWriter.CLOSING);
generatedXML.sendData();
return;
@@ -584,7 +592,7 @@
XMLWriter generatedXML = new XMLWriter(resp.getWriter());
generatedXML.writeXMLHeader();
- generatedXML.writeElement(null, "multistatus"
+ generatedXML.writeElement(null, "D:multistatus"
+ generateNamespaceDeclarations(),
XMLWriter.OPENING);
@@ -664,7 +672,7 @@
}
}
- generatedXML.writeElement(null, "multistatus",
+ generatedXML.writeElement(null, "D:multistatus",
XMLWriter.CLOSING);
generatedXML.sendData();
@@ -675,9 +683,8 @@
/**
* PROPPATCH Method.
*/
- protected void doProppatch(HttpServletRequest req,
- HttpServletResponse resp)
- throws ServletException, IOException {
+ protected void doProppatch(HttpServletRequest req, HttpServletResponse resp)
+ throws IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
@@ -777,6 +784,7 @@
/**
* DELETE Method.
*/
+ @Override
protected void doDelete(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
@@ -804,6 +812,7 @@
* @exception IOException if an input/output error occurs
* @exception ServletException if a servlet-specified error occurs
*/
+ @Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
@@ -825,7 +834,7 @@
* COPY Method.
*/
protected void doCopy(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
+ throws IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
@@ -841,7 +850,7 @@
* MOVE Method.
*/
protected void doMove(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
+ throws IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
@@ -1148,7 +1157,7 @@
generatedXML.writeXMLHeader();
generatedXML.writeElement
- (null, "multistatus" + generateNamespaceDeclarations(),
+ (null, "D:multistatus" + generateNamespaceDeclarations(),
XMLWriter.OPENING);
while (lockPathsList.hasMoreElements()) {
@@ -1282,19 +1291,15 @@
LockInfo toRenew = resourceLocks.get(path);
Enumeration<String> tokenList = null;
- if (lock != null) {
- // At least one of the tokens of the locks must have been given
-
- tokenList = toRenew.tokens.elements();
- while (tokenList.hasMoreElements()) {
- String token = tokenList.nextElement();
- if (ifHeader.indexOf(token) != -1) {
- toRenew.expiresAt = lock.expiresAt;
- lock = toRenew;
- }
+ // At least one of the tokens of the locks must have been given
+ tokenList = toRenew.tokens.elements();
+ while (tokenList.hasMoreElements()) {
+ String token = tokenList.nextElement();
+ if (ifHeader.indexOf(token) != -1) {
+ toRenew.expiresAt = lock.expiresAt;
+ lock = toRenew;
}
-
}
// Checking inheritable collection locks
@@ -1323,19 +1328,19 @@
// the lock information
XMLWriter generatedXML = new XMLWriter();
generatedXML.writeXMLHeader();
- generatedXML.writeElement(null, "prop"
+ generatedXML.writeElement(null, "D:prop"
+ generateNamespaceDeclarations(),
XMLWriter.OPENING);
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.OPENING);
lock.toXML(generatedXML);
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.CLOSING);
- generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.CLOSING);
resp.setStatus(WebdavStatus.SC_OK);
resp.setContentType("text/xml; charset=UTF-8");
@@ -1350,7 +1355,7 @@
* UNLOCK Method.
*/
protected void doUnlock(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException {
+ throws IOException {
if (readOnly) {
resp.sendError(WebdavStatus.SC_FORBIDDEN);
@@ -1427,7 +1432,7 @@
* Generate the namespace declarations.
*/
private String generateNamespaceDeclarations() {
- return " xmlns=\"" + DEFAULT_NAMESPACE + "\"";
+ return " xmlns:D=\"" + DEFAULT_NAMESPACE + "\"";
}
@@ -1527,7 +1532,7 @@
*/
private boolean copyResource(HttpServletRequest req,
HttpServletResponse resp)
- throws ServletException, IOException {
+ throws IOException {
// Parsing destination header
@@ -1693,13 +1698,13 @@
/**
* Copy a collection.
*
- * @param resources Resources implementation to be used
+ * @param dirContext Resources implementation to be used
* @param errorList Hashtable containing the list of errors which occurred
* during the copy operation
* @param source Path of the resource to be copied
* @param dest Destination path
*/
- private boolean copyResource(DirContext resources,
+ private boolean copyResource(DirContext dirContext,
Hashtable<String,Integer> errorList, String source, String dest) {
if (debug > 1)
@@ -1707,7 +1712,7 @@
Object object = null;
try {
- object = resources.lookup(source);
+ object = dirContext.lookup(source);
} catch (NamingException e) {
// Ignore
}
@@ -1715,15 +1720,16 @@
if (object instanceof DirContext) {
try {
- resources.createSubcontext(dest);
+ dirContext.createSubcontext(dest);
} catch (NamingException e) {
- errorList.put(dest, WebdavStatus.SC_CONFLICT);
+ errorList.put
+ (dest, new Integer(WebdavStatus.SC_CONFLICT));
return false;
}
try {
NamingEnumeration<NameClassPair> enumeration =
- resources.list(source);
+ dirContext.list(source);
while (enumeration.hasMoreElements()) {
NameClassPair ncPair = enumeration.nextElement();
String childDest = dest;
@@ -1734,10 +1740,11 @@
if (!childSrc.equals("/"))
childSrc += "/";
childSrc += ncPair.getName();
- copyResource(resources, errorList, childSrc, childDest);
+ copyResource(dirContext, errorList, childSrc, childDest);
}
} catch (NamingException e) {
- errorList.put(dest, WebdavStatus.SC_INTERNAL_SERVER_ERROR);
+ errorList.put
+ (dest, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
return false;
}
@@ -1745,19 +1752,23 @@
if (object instanceof Resource) {
try {
- resources.bind(dest, object);
+ dirContext.bind(dest, object);
} catch (NamingException e) {
if (e.getCause() instanceof FileNotFoundException) {
// We know the source exists so it must be the
// destination dir that can't be found
- errorList.put(source, WebdavStatus.SC_CONFLICT);
+ errorList.put(source,
+ new Integer(WebdavStatus.SC_CONFLICT));
} else {
- errorList.put(source, WebdavStatus.SC_INTERNAL_SERVER_ERROR);
+ errorList.put(source,
+ new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
}
return false;
}
} else {
- errorList.put(source, WebdavStatus.SC_INTERNAL_SERVER_ERROR);
+ errorList.put
+ (source,
+ new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
return false;
}
@@ -1777,7 +1788,7 @@
*/
private boolean deleteResource(HttpServletRequest req,
HttpServletResponse resp)
- throws ServletException, IOException {
+ throws IOException {
String path = getRelativePath(req);
@@ -1797,7 +1808,7 @@
*/
private boolean deleteResource(String path, HttpServletRequest req,
HttpServletResponse resp, boolean setStatus)
- throws ServletException, IOException {
+ throws IOException {
if ((path.toUpperCase(Locale.ENGLISH).startsWith("/WEB-INF")) ||
(path.toUpperCase(Locale.ENGLISH).startsWith("/META-INF"))) {
@@ -1872,12 +1883,12 @@
/**
* Deletes a collection.
*
- * @param resources Resources implementation associated with the context
+ * @param dirContext Resources implementation associated with the context
* @param path Path to the collection to be deleted
* @param errorList Contains the list of the errors which occurred
*/
private void deleteCollection(HttpServletRequest req,
- DirContext resources,
+ DirContext dirContext,
String path,
Hashtable<String,Integer> errorList) {
@@ -1900,7 +1911,7 @@
Enumeration<NameClassPair> enumeration = null;
try {
- enumeration = resources.list(path);
+ enumeration = dirContext.list(path);
} catch (NamingException e) {
errorList.put(path, new Integer
(WebdavStatus.SC_INTERNAL_SERVER_ERROR));
@@ -1921,13 +1932,13 @@
} else {
try {
- Object object = resources.lookup(childName);
+ Object object = dirContext.lookup(childName);
if (object instanceof DirContext) {
- deleteCollection(req, resources, childName, errorList);
+ deleteCollection(req, dirContext, childName, errorList);
}
try {
- resources.unbind(childName);
+ dirContext.unbind(childName);
} catch (NamingException e) {
if (!(object instanceof DirContext)) {
// If it's not a collection, then it's an unknown
@@ -1959,7 +1970,7 @@
*/
private void sendReport(HttpServletRequest req, HttpServletResponse resp,
Hashtable<String,Integer> errorList)
- throws ServletException, IOException {
+ throws IOException {
resp.setStatus(WebdavStatus.SC_MULTI_STATUS);
@@ -2035,13 +2046,13 @@
return;
}
- generatedXML.writeElement(null, "response", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:response", XMLWriter.OPENING);
String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " "
+ WebdavStatus.getStatusText
(WebdavStatus.SC_OK));
// Generating href element
- generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:href", XMLWriter.OPENING);
String href = req.getContextPath() + req.getServletPath();
if ((href.endsWith("/")) && (path.startsWith("/")))
@@ -2053,7 +2064,7 @@
generatedXML.writeText(rewriteUrl(href));
- generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:href", XMLWriter.CLOSING);
String resourceName = path;
int lastSlash = path.lastIndexOf('/');
@@ -2064,98 +2075,98 @@
case FIND_ALL_PROP :
- generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
- generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.OPENING);
generatedXML.writeProperty
- (null, "creationdate",
+ (null, "D:creationdate",
getISOCreationDate(cacheEntry.attributes.getCreation()));
- generatedXML.writeElement(null, "displayname", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:displayname", XMLWriter.OPENING);
generatedXML.writeData(resourceName);
- generatedXML.writeElement(null, "displayname", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:displayname", XMLWriter.CLOSING);
if (cacheEntry.resource != null) {
generatedXML.writeProperty
- (null, "getlastmodified", FastHttpDateFormat.formatDate
+ (null, "D:getlastmodified", FastHttpDateFormat.formatDate
(cacheEntry.attributes.getLastModified(), null));
generatedXML.writeProperty
- (null, "getcontentlength",
+ (null, "D:getcontentlength",
String.valueOf(cacheEntry.attributes.getContentLength()));
String contentType = getServletContext().getMimeType
(cacheEntry.name);
if (contentType != null) {
- generatedXML.writeProperty(null, "getcontenttype",
+ generatedXML.writeProperty(null, "D:getcontenttype",
contentType);
}
- generatedXML.writeProperty(null, "getetag",
+ generatedXML.writeProperty(null, "D:getetag",
cacheEntry.attributes.getETag());
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.NO_CONTENT);
} else {
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.OPENING);
- generatedXML.writeElement(null, "collection",
+ generatedXML.writeElement(null, "D:collection",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.CLOSING);
}
- generatedXML.writeProperty(null, "source", "");
+ generatedXML.writeProperty(null, "D:source", "");
- String supportedLocks = "<lockentry>"
- + "<lockscope><exclusive/></lockscope>"
- + "<locktype><write/></locktype>"
- + "</lockentry>" + "<lockentry>"
- + "<lockscope><shared/></lockscope>"
- + "<locktype><write/></locktype>"
- + "</lockentry>";
- generatedXML.writeElement(null, "supportedlock",
+ String supportedLocks = "<D:lockentry>"
+ + "<D:lockscope><D:exclusive/></D:lockscope>"
+ + "<D:locktype><D:write/></D:locktype>"
+ + "</D:lockentry>" + "<D:lockentry>"
+ + "<D:lockscope><D:shared/></D:lockscope>"
+ + "<D:locktype><D:write/></D:locktype>"
+ + "</D:lockentry>";
+ generatedXML.writeElement(null, "D:supportedlock",
XMLWriter.OPENING);
generatedXML.writeText(supportedLocks);
- generatedXML.writeElement(null, "supportedlock",
+ generatedXML.writeElement(null, "D:supportedlock",
XMLWriter.CLOSING);
generateLockDiscovery(path, generatedXML);
- generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.OPENING);
generatedXML.writeText(status);
- generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.CLOSING);
break;
case FIND_PROPERTY_NAMES :
- generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
- generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.OPENING);
- generatedXML.writeElement(null, "creationdate",
+ generatedXML.writeElement(null, "D:creationdate",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "displayname",
+ generatedXML.writeElement(null, "D:displayname",
XMLWriter.NO_CONTENT);
if (cacheEntry.resource != null) {
- generatedXML.writeElement(null, "getcontentlanguage",
+ generatedXML.writeElement(null, "D:getcontentlanguage",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "getcontentlength",
+ generatedXML.writeElement(null, "D:getcontentlength",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "getcontenttype",
+ generatedXML.writeElement(null, "D:getcontenttype",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "getetag",
+ generatedXML.writeElement(null, "D:getetag",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "getlastmodified",
+ generatedXML.writeElement(null, "D:getlastmodified",
XMLWriter.NO_CONTENT);
}
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "source", XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:source", XMLWriter.NO_CONTENT);
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.OPENING);
generatedXML.writeText(status);
- generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.CLOSING);
break;
@@ -2165,8 +2176,8 @@
// Parse the list of properties
- generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
- generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.OPENING);
Enumeration<String> properties = propertiesVector.elements();
@@ -2176,19 +2187,19 @@
if (property.equals("creationdate")) {
generatedXML.writeProperty
- (null, "creationdate",
+ (null, "D:creationdate",
getISOCreationDate(cacheEntry.attributes.getCreation()));
} else if (property.equals("displayname")) {
generatedXML.writeElement
- (null, "displayname", XMLWriter.OPENING);
+ (null, "D:displayname", XMLWriter.OPENING);
generatedXML.writeData(resourceName);
generatedXML.writeElement
- (null, "displayname", XMLWriter.CLOSING);
+ (null, "D:displayname", XMLWriter.CLOSING);
} else if (property.equals("getcontentlanguage")) {
if (cacheEntry.context != null) {
propertiesNotFound.addElement(property);
} else {
- generatedXML.writeElement(null, "getcontentlanguage",
+ generatedXML.writeElement(null, "D:getcontentlanguage",
XMLWriter.NO_CONTENT);
}
} else if (property.equals("getcontentlength")) {
@@ -2196,7 +2207,7 @@
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
- (null, "getcontentlength",
+ (null, "D:getcontentlength",
(String.valueOf(cacheEntry.attributes.getContentLength())));
}
} else if (property.equals("getcontenttype")) {
@@ -2204,7 +2215,7 @@
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
- (null, "getcontenttype",
+ (null, "D:getcontenttype",
getServletContext().getMimeType
(cacheEntry.name));
}
@@ -2213,42 +2224,42 @@
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
- (null, "getetag", cacheEntry.attributes.getETag());
+ (null, "D:getetag", cacheEntry.attributes.getETag());
}
} else if (property.equals("getlastmodified")) {
if (cacheEntry.context != null) {
propertiesNotFound.addElement(property);
} else {
generatedXML.writeProperty
- (null, "getlastmodified", FastHttpDateFormat.formatDate
+ (null, "D:getlastmodified", FastHttpDateFormat.formatDate
(cacheEntry.attributes.getLastModified(), null));
}
} else if (property.equals("resourcetype")) {
if (cacheEntry.context != null) {
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.OPENING);
- generatedXML.writeElement(null, "collection",
+ generatedXML.writeElement(null, "D:collection",
XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.CLOSING);
} else {
- generatedXML.writeElement(null, "resourcetype",
+ generatedXML.writeElement(null, "D:resourcetype",
XMLWriter.NO_CONTENT);
}
} else if (property.equals("source")) {
- generatedXML.writeProperty(null, "source", "");
+ generatedXML.writeProperty(null, "D:source", "");
} else if (property.equals("supportedlock")) {
- supportedLocks = "<lockentry>"
- + "<lockscope><exclusive/></lockscope>"
- + "<locktype><write/></locktype>"
- + "</lockentry>" + "<lockentry>"
- + "<lockscope><shared/></lockscope>"
- + "<locktype><write/></locktype>"
- + "</lockentry>";
- generatedXML.writeElement(null, "supportedlock",
+ supportedLocks = "<D:lockentry>"
+ + "<D:lockscope><D:exclusive/></D:lockscope>"
+ + "<D:locktype><D:write/></D:locktype>"
+ + "</D:lockentry>" + "<D:lockentry>"
+ + "<D:lockscope><D:shared/></D:lockscope>"
+ + "<D:locktype><D:write/></D:locktype>"
+ + "</D:lockentry>";
+ generatedXML.writeElement(null, "D:supportedlock",
XMLWriter.OPENING);
generatedXML.writeText(supportedLocks);
- generatedXML.writeElement(null, "supportedlock",
+ generatedXML.writeElement(null, "D:supportedlock",
XMLWriter.CLOSING);
} else if (property.equals("lockdiscovery")) {
if (!generateLockDiscovery(path, generatedXML))
@@ -2259,11 +2270,11 @@
}
- generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.OPENING);
generatedXML.writeText(status);
- generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.CLOSING);
Enumeration<String> propertiesNotFoundList =
propertiesNotFound.elements();
@@ -2274,8 +2285,8 @@
+ " " + WebdavStatus.getStatusText
(WebdavStatus.SC_NOT_FOUND));
- generatedXML.writeElement(null, "propstat", XMLWriter.OPENING);
- generatedXML.writeElement(null, "prop", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.OPENING);
while (propertiesNotFoundList.hasMoreElements()) {
generatedXML.writeElement
@@ -2283,11 +2294,11 @@
XMLWriter.NO_CONTENT);
}
- generatedXML.writeElement(null, "prop", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "status", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:prop", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.OPENING);
generatedXML.writeText(status);
- generatedXML.writeElement(null, "status", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:status", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:propstat", XMLWriter.CLOSING);
}
@@ -2295,13 +2306,13 @@
}
- generatedXML.writeElement(null, "response", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:response", XMLWriter.CLOSING);
}
/**
- * Propfind helper method. Dispays the properties of a lock-null resource.
+ * Propfind helper method. Displays the properties of a lock-null resource.
*
* @param resources Resources object associated with this context
* @param generatedXML XML response to the Propfind request
@@ -2379,7 +2390,7 @@
generatedXML.writeElement(null, "resourcetype",
XMLWriter.CLOSING);
- generatedXML.writeProperty(null, "source", "");
+ generatedXML.writeProperty(null, "D:source", "");
String supportedLocks = "<lockentry>"
+ "<lockscope><exclusive/></lockscope>"
@@ -2567,7 +2578,7 @@
if (resourceLock != null) {
wroteStart = true;
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.OPENING);
resourceLock.toXML(generatedXML);
}
@@ -2577,7 +2588,7 @@
if (path.startsWith(currentLock.path)) {
if (!wroteStart) {
wroteStart = true;
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.OPENING);
}
currentLock.toXML(generatedXML);
@@ -2585,7 +2596,7 @@
}
if (wroteStart) {
- generatedXML.writeElement(null, "lockdiscovery",
+ generatedXML.writeElement(null, "D:lockdiscovery",
XMLWriter.CLOSING);
} else {
return false;
@@ -2627,7 +2638,7 @@
* Determines the methods normally allowed for the resource.
*
*/
- private StringBuilder determineMethodsAllowed(DirContext resources,
+ private StringBuilder determineMethodsAllowed(DirContext dirContext,
HttpServletRequest req) {
StringBuilder methodsAllowed = new StringBuilder();
@@ -2636,7 +2647,7 @@
try {
String path = getRelativePath(req);
- object = resources.lookup(path);
+ object = dirContext.lookup(path);
} catch (NamingException e) {
exists = false;
}
@@ -2699,6 +2710,7 @@
/**
* Get a String representation of this lock token.
*/
+ @Override
public String toString() {
String result = "Type:" + type + "\n";
@@ -2740,44 +2752,44 @@
*/
public void toXML(XMLWriter generatedXML) {
- generatedXML.writeElement(null, "activelock", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:activelock", XMLWriter.OPENING);
- generatedXML.writeElement(null, "locktype", XMLWriter.OPENING);
- generatedXML.writeElement(null, type, XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "locktype", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:locktype", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:" + type, XMLWriter.NO_CONTENT);
+ generatedXML.writeElement(null, "D:locktype", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "lockscope", XMLWriter.OPENING);
- generatedXML.writeElement(null, scope, XMLWriter.NO_CONTENT);
- generatedXML.writeElement(null, "lockscope", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:lockscope", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:" + scope, XMLWriter.NO_CONTENT);
+ generatedXML.writeElement(null, "D:lockscope", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "depth", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:depth", XMLWriter.OPENING);
if (depth == maxDepth) {
generatedXML.writeText("Infinity");
} else {
generatedXML.writeText("0");
}
- generatedXML.writeElement(null, "depth", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:depth", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "owner", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:owner", XMLWriter.OPENING);
generatedXML.writeText(owner);
- generatedXML.writeElement(null, "owner", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:owner", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "timeout", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:timeout", XMLWriter.OPENING);
long timeout = (expiresAt - System.currentTimeMillis()) / 1000;
generatedXML.writeText("Second-" + timeout);
- generatedXML.writeElement(null, "timeout", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:timeout", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "locktoken", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:locktoken", XMLWriter.OPENING);
Enumeration<String> tokensList = tokens.elements();
while (tokensList.hasMoreElements()) {
- generatedXML.writeElement(null, "href", XMLWriter.OPENING);
+ generatedXML.writeElement(null, "D:href", XMLWriter.OPENING);
generatedXML.writeText("opaquelocktoken:"
+ tokensList.nextElement());
- generatedXML.writeElement(null, "href", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:href", XMLWriter.CLOSING);
}
- generatedXML.writeElement(null, "locktoken", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:locktoken", XMLWriter.CLOSING);
- generatedXML.writeElement(null, "activelock", XMLWriter.CLOSING);
+ generatedXML.writeElement(null, "D:activelock", XMLWriter.CLOSING);
}
@@ -2788,8 +2800,9 @@
// --------------------------------------------- WebdavResolver Inner Class
/**
* Work around for XML parsers that don't fully respect
- * {@link DocumentBuilderFactory#setExpandEntityReferences(false)}. External
- * references are filtered out for security reasons. See CVE-2007-5461.
+ * {@link DocumentBuilderFactory#setExpandEntityReferences(boolean)} when
+ * called with <code>false</code>. External references are filtered out for
+ * security reasons. See CVE-2007-5461.
*/
private class WebdavResolver implements EntityResolver {
private ServletContext context;
@@ -3011,8 +3024,8 @@
* providing status for multiple independent operations.
*/
public static final int SC_MULTI_STATUS = 207;
- // This one colides with HTTP 1.1
- // "207 Parital Update OK"
+ // This one collides with HTTP 1.1
+ // "207 Partial Update OK"
/**
@@ -3020,7 +3033,7 @@
* the PATCH method was not understood by the resource.
*/
public static final int SC_UNPROCESSABLE_ENTITY = 418;
- // This one colides with HTTP 1.1
+ // This one collides with HTTP 1.1
// "418 Reauthentication Required"
@@ -3030,7 +3043,7 @@
* execution of this method.
*/
public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419;
- // This one colides with HTTP 1.1
+ // This one collides with HTTP 1.1
// "419 Proxy Reauthentication Required"
@@ -3056,7 +3069,7 @@
static {
- // HTTP 1.0 tatus Code
+ // HTTP 1.0 status Code
addStatusCodeMap(SC_OK, "OK");
addStatusCodeMap(SC_CREATED, "Created");
addStatusCodeMap(SC_ACCEPTED, "Accepted");
@@ -3126,5 +3139,3 @@
}
}
-
-
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2010-08-18 12:40:08 UTC (rev 1534)
+++ trunk/webapps/docs/changelog.xml 2010-08-18 14:31:57 UTC (rev 1535)
@@ -44,6 +44,10 @@
<fix>
<bug>48960</bug>: Disable SSI exec by default, and add allowExec configuration. (markt)
</fix>
+ <fix>
+ <bug>49428</bug>: Specify a namespace rather than use a default to please MS clients.
+ Submitted by Panagiotis Astithas. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
14 years, 4 months
JBossWeb SVN: r1534 - in trunk: webapps/docs and 1 other directory.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2010-08-18 08:40:08 -0400 (Wed, 18 Aug 2010)
New Revision: 1534
Modified:
trunk/java/org/apache/catalina/ssi/SSIFilter.java
trunk/java/org/apache/catalina/ssi/SSIProcessor.java
trunk/java/org/apache/catalina/ssi/SSIServlet.java
trunk/webapps/docs/changelog.xml
trunk/webapps/docs/ssi-howto.xml
Log:
- Disable SSI exec by default.
Modified: trunk/java/org/apache/catalina/ssi/SSIFilter.java
===================================================================
--- trunk/java/org/apache/catalina/ssi/SSIFilter.java 2010-08-18 10:01:08 UTC (rev 1533)
+++ trunk/java/org/apache/catalina/ssi/SSIFilter.java 2010-08-18 12:40:08 UTC (rev 1534)
@@ -43,11 +43,11 @@
* from within web.xml.
*
* @author David Becker
- * @version $Revision$, $Date$
+ * @version $Id$
* @see org.apache.catalina.ssi.SSIServlet
*/
public class SSIFilter implements Filter {
- protected FilterConfig config = null;
+ protected FilterConfig config = null;
/** Debug level for this servlet. */
protected int debug = 0;
/** Expiration time in seconds for the doc. */
@@ -55,10 +55,12 @@
/** virtual path can be webapp-relative */
protected boolean isVirtualWebappRelative = false;
/** regex pattern to match when evaluating content types */
- protected Pattern contentTypeRegEx = null;
- /** default pattern for ssi filter content type matching */
- protected Pattern shtmlRegEx =
+ protected Pattern contentTypeRegEx = null;
+ /** default pattern for ssi filter content type matching */
+ protected Pattern shtmlRegEx =
Pattern.compile("text/x-server-parsed-html(;.*)?");
+ /** Allow exec (normally blocked for security) */
+ protected boolean allowExec = false;
//----------------- Public methods.
@@ -69,8 +71,8 @@
* if an error occurs
*/
public void init(FilterConfig config) throws ServletException {
- this.config = config;
-
+ this.config = config;
+
if (config.getInitParameter("debug") != null) {
debug = Integer.parseInt(config.getInitParameter("debug"));
}
@@ -87,6 +89,8 @@
if (config.getInitParameter("expires") != null)
expires = Long.valueOf(config.getInitParameter("expires"));
+ allowExec = Boolean.parseBoolean(config.getInitParameter("allowExec"));
+
if (debug > 0)
config.getServletContext().log(
"SSIFilter.init() SSI invoker started with 'debug'=" + debug);
@@ -125,7 +129,7 @@
new SSIServletExternalResolver(config.getServletContext(), req,
res, isVirtualWebappRelative, debug, encoding);
SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver,
- debug);
+ debug, allowExec);
// prepare readers/writers
Reader reader =
@@ -155,10 +159,10 @@
Matcher shtmlMatcher =
shtmlRegEx.matcher(responseIncludeWrapper.getContentType());
if (shtmlMatcher.matches()) {
- // Convert shtml mime type to ordinary html mime type but preserve
+ // Convert shtml mime type to ordinary html mime type but preserve
// encoding, if any.
- String enc = shtmlMatcher.group(1);
- res.setContentType("text/html" + ((enc != null) ? enc : ""));
+ String enc = shtmlMatcher.group(1);
+ res.setContentType("text/html" + ((enc != null) ? enc : ""));
}
}
@@ -177,5 +181,6 @@
}
public void destroy() {
+ // NOOP
}
}
Modified: trunk/java/org/apache/catalina/ssi/SSIProcessor.java
===================================================================
--- trunk/java/org/apache/catalina/ssi/SSIProcessor.java 2010-08-18 10:01:08 UTC (rev 1533)
+++ trunk/java/org/apache/catalina/ssi/SSIProcessor.java 2010-08-18 12:40:08 UTC (rev 1534)
@@ -32,7 +32,7 @@
*
* @author Dan Sandberg
* @author David Becker
- * @version $Revision$, $Date$
+ * @version $Id$
*/
public class SSIProcessor {
/** The start pattern */
@@ -41,13 +41,17 @@
protected final static String COMMAND_END = "-->";
protected final static int BUFFER_SIZE = 4096;
protected SSIExternalResolver ssiExternalResolver;
- protected HashMap commands = new HashMap();
+ protected HashMap<String,SSICommand> commands =
+ new HashMap<String,SSICommand>();
protected int debug;
+ protected final boolean allowExec;
- public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug) {
+ public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug,
+ boolean allowExec) {
this.ssiExternalResolver = ssiExternalResolver;
this.debug = debug;
+ this.allowExec = allowExec;
addBuiltinCommands();
}
@@ -55,7 +59,9 @@
protected void addBuiltinCommands() {
addCommand("config", new SSIConfig());
addCommand("echo", new SSIEcho());
- addCommand("exec", new SSIExec());
+ if (allowExec) {
+ addCommand("exec", new SSIExec());
+ }
addCommand("include", new SSIInclude());
addCommand("flastmod", new SSIFlastmod());
addCommand("fsize", new SSIFsize());
@@ -133,8 +139,8 @@
// change
// during the loop
String configErrMsg = ssiMediator.getConfigErrMsg();
- SSICommand ssiCommand = (SSICommand)commands
- .get(strCmd.toLowerCase(Locale.ENGLISH));
+ SSICommand ssiCommand =
+ commands.get(strCmd.toLowerCase(Locale.ENGLISH));
String errorMessage = null;
if (ssiCommand == null) {
errorMessage = "Unknown command: " + strCmd;
@@ -322,4 +328,4 @@
protected boolean isQuote(char c) {
return c == '\'' || c == '\"' || c == '`';
}
-}
+}
\ No newline at end of file
Modified: trunk/java/org/apache/catalina/ssi/SSIServlet.java
===================================================================
--- trunk/java/org/apache/catalina/ssi/SSIServlet.java 2010-08-18 10:01:08 UTC (rev 1533)
+++ trunk/java/org/apache/catalina/ssi/SSIServlet.java 2010-08-18 12:40:08 UTC (rev 1534)
@@ -41,7 +41,7 @@
* @author Amy Roh
* @author Dan Sandberg
* @author David Becker
- * @version $Revision$, $Date$
+ * @version $Id$
*/
public class SSIServlet extends HttpServlet {
/** Debug level for this servlet. */
@@ -56,6 +56,8 @@
protected String inputEncoding = null;
/** Output encoding. If not specified, uses platform default */
protected String outputEncoding = "UTF-8";
+ /** Allow exec (normally blocked for security) */
+ protected boolean allowExec = false;
//----------------- Public methods.
@@ -65,6 +67,7 @@
* @exception ServletException
* if an error occurs
*/
+ @Override
public void init() throws ServletException {
if (getServletConfig().getInitParameter("debug") != null)
@@ -83,6 +86,9 @@
if (getServletConfig().getInitParameter("outputEncoding") != null)
outputEncoding = getServletConfig().getInitParameter("outputEncoding");
+ allowExec = Boolean.parseBoolean(
+ getServletConfig().getInitParameter("allowExec"));
+
if (debug > 0)
log("SSIServlet.init() SSI invoker started with 'debug'=" + debug);
@@ -101,6 +107,7 @@
* @exception ServletException
* if an error occurs
*/
+ @Override
public void doGet(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
if (debug > 0) log("SSIServlet.doGet()");
@@ -121,6 +128,7 @@
* @exception ServletException
* if an error occurs
*/
+ @Override
public void doPost(HttpServletRequest req, HttpServletResponse res)
throws IOException, ServletException {
if (debug > 0) log("SSIServlet.doPost()");
@@ -137,7 +145,7 @@
* a value of type 'HttpServletResponse'
*/
protected void requestHandler(HttpServletRequest req,
- HttpServletResponse res) throws IOException, ServletException {
+ HttpServletResponse res) throws IOException {
ServletContext servletContext = getServletContext();
String path = SSIServletRequestUtil.getRelativePath(req);
if (debug > 0)
@@ -178,7 +186,7 @@
new SSIServletExternalResolver(getServletContext(), req, res,
isVirtualWebappRelative, debug, inputEncoding);
SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver,
- debug);
+ debug, allowExec);
PrintWriter printWriter = null;
StringWriter stringWriter = null;
if (buffered) {
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2010-08-18 10:01:08 UTC (rev 1533)
+++ trunk/webapps/docs/changelog.xml 2010-08-18 12:40:08 UTC (rev 1534)
@@ -41,6 +41,9 @@
<fix>
CSRF filter updates. (markt)
</fix>
+ <fix>
+ <bug>48960</bug>: Disable SSI exec by default, and add allowExec configuration. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
Modified: trunk/webapps/docs/ssi-howto.xml
===================================================================
--- trunk/webapps/docs/ssi-howto.xml 2010-08-18 10:01:08 UTC (rev 1533)
+++ trunk/webapps/docs/ssi-howto.xml 2010-08-18 12:40:08 UTC (rev 1534)
@@ -85,6 +85,7 @@
the default platform encoding.</li>
<li><strong>outputEncoding</strong> - The encoding to be used for the result
of the SSI processing. Default is UTF-8.</li>
+<li><strong>allowExec</strong> - Allow SSI exec. Default is false.</li>
</ul>
</p>
@@ -108,6 +109,7 @@
<li><strong>isVirtualWebappRelative</strong> - Should "virtual" SSI directive
paths be interpreted as relative to the context root, instead of the server
root? (0=false, 1=true) Default 0 (false).</li>
+<li><strong>allowExec</strong> - Allow SSI exec. Default is false.</li>
</ul>
</p>
14 years, 4 months
JBossWeb SVN: r1533 - in trunk: java/org/apache/catalina/core and 5 other directories.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2010-08-18 06:01:08 -0400 (Wed, 18 Aug 2010)
New Revision: 1533
Added:
trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java
trunk/java/org/apache/tomcat/util/http/fileupload/disk/
trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
trunk/java/org/apache/tomcat/util/http/fileupload/servlet/
trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
trunk/java/org/apache/tomcat/util/http/fileupload/util/
trunk/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java
trunk/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
trunk/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java
trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
Removed:
trunk/java/org/apache/tomcat/util/http/fileupload/Closeable.java
trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java
trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileCleanerCleanup.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java
trunk/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java
trunk/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java
trunk/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java
trunk/java/org/apache/tomcat/util/http/fileupload/Streams.java
Modified:
trunk/java/org/apache/catalina/connector/Request.java
trunk/java/org/apache/catalina/core/StandardPart.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileUpload.java
trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
trunk/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java
trunk/java/org/apache/tomcat/util/http/fileupload/package.html
trunk/webapps/docs/changelog.xml
Log:
- Port the fileupload update.
Modified: trunk/java/org/apache/catalina/connector/Request.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Request.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/catalina/connector/Request.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -114,12 +114,12 @@
import org.apache.tomcat.util.http.FastHttpDateFormat;
import org.apache.tomcat.util.http.Parameters;
import org.apache.tomcat.util.http.ServerCookie;
-import org.apache.tomcat.util.http.fileupload.DiskFileItemFactory;
import org.apache.tomcat.util.http.fileupload.FileItem;
import org.apache.tomcat.util.http.fileupload.FileUploadException;
-import org.apache.tomcat.util.http.fileupload.ServletFileUpload;
import org.apache.tomcat.util.http.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.tomcat.util.http.fileupload.FileUploadBase.SizeLimitExceededException;
+import org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory;
+import org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload;
import org.apache.tomcat.util.http.mapper.MappingData;
Modified: trunk/java/org/apache/catalina/core/StandardPart.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardPart.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/catalina/core/StandardPart.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -28,8 +28,8 @@
import javax.servlet.http.Part;
import org.apache.catalina.deploy.Multipart;
-import org.apache.tomcat.util.http.fileupload.DiskFileItem;
import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem;
/**
* Adaptor to allow {@link FileItem} objects generated by the package renamed
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/Closeable.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/Closeable.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/Closeable.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,38 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.IOException;
-
-
-/**
- * Interface of an object, which may be closed.
- */
-public interface Closeable {
- /**
- * Closes the object.
- * @throws IOException An I/O error occurred.
- */
- void close() throws IOException;
-
- /**
- * Returns, whether the object is already closed.
- * @return True, if the object is closed, otherwise false.
- * @throws IOException An I/O error occurred.
- */
- boolean isClosed() throws IOException;
-}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,728 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.util.Map;
-
-
-/**
- * <p> The default implementation of the
- * {@link org.apache.commons.fileupload.FileItem FileItem} interface.
- *
- * <p> After retrieving an instance of this class from a {@link
- * org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} instance (see
- * {@link org.apache.commons.fileupload.DiskFileUpload
- * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
- * either request all contents of file at once using {@link #get()} or
- * request an {@link java.io.InputStream InputStream} with
- * {@link #getInputStream()} and process the file without attempting to load
- * it into memory, which may come handy with large files.
- *
- * <p>When using the <code>DiskFileItemFactory</code>, then you should
- * consider the following: Temporary files are automatically deleted as
- * soon as they are no longer needed. (More precisely, when the
- * corresponding instance of {@link java.io.File} is garbage collected.)
- * This is done by the so-called reaper thread, which is started
- * automatically when the class {@link org.apache.commons.io.FileCleaner}
- * is loaded.
- * It might make sense to terminate that thread, for example, if
- * your web application ends. See the section on "Resource cleanup"
- * in the users guide of commons-fileupload.</p>
- *
- * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
- * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
- * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @since FileUpload 1.1
- *
- * @version $Id: DiskFileItem.java 881562 2009-11-17 22:03:22Z markt $
- */
-public class DiskFileItem
- implements FileItem, FileItemHeadersSupport {
-
- // ----------------------------------------------------- Manifest constants
-
- /**
- * The UID to use when serializing this instance.
- */
- private static final long serialVersionUID = 2237570099615271025L;
-
-
- /**
- * Default content charset to be used when no explicit charset
- * parameter is provided by the sender. Media subtypes of the
- * "text" type are defined to have a default charset value of
- * "ISO-8859-1" when received via HTTP.
- */
- public static final String DEFAULT_CHARSET = "ISO-8859-1";
-
-
- // ----------------------------------------------------------- Data members
-
-
- /**
- * UID used in unique file name generation.
- */
- private static final String UID =
- new java.rmi.server.UID().toString()
- .replace(':', '_').replace('-', '_');
-
- /**
- * Counter used in unique identifier generation.
- */
- private static int counter = 0;
-
-
- /**
- * The name of the form field as provided by the browser.
- */
- private String fieldName;
-
-
- /**
- * The content type passed by the browser, or <code>null</code> if
- * not defined.
- */
- private String contentType;
-
-
- /**
- * Whether or not this item is a simple form field.
- */
- private boolean isFormField;
-
-
- /**
- * The original filename in the user's filesystem.
- */
- private String fileName;
-
-
- /**
- * The size of the item, in bytes. This is used to cache the size when a
- * file item is moved from its original location.
- */
- private long size = -1;
-
-
- /**
- * The threshold above which uploads will be stored on disk.
- */
- private int sizeThreshold;
-
-
- /**
- * The directory in which uploaded files will be stored, if stored on disk.
- */
- private File repository;
-
-
- /**
- * Cached contents of the file.
- */
- private byte[] cachedContent;
-
-
- /**
- * Output stream for this item.
- */
- private transient DeferredFileOutputStream dfos;
-
- /**
- * The temporary file to use.
- */
- private transient File tempFile;
-
- /**
- * File to allow for serialization of the content of this item.
- */
- private File dfosFile;
-
- /**
- * The file items headers.
- */
- private FileItemHeaders headers;
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Constructs a new <code>DiskFileItem</code> instance.
- *
- * @param fieldName The name of the form field.
- * @param contentType The content type passed by the browser or
- * <code>null</code> if not specified.
- * @param isFormField Whether or not this item is a plain form field, as
- * opposed to a file upload.
- * @param fileName The original filename in the user's filesystem, or
- * <code>null</code> if not specified.
- * @param sizeThreshold The threshold, in bytes, below which items will be
- * retained in memory and above which they will be
- * stored as a file.
- * @param repository The data repository, which is the directory in
- * which files will be created, should the item size
- * exceed the threshold.
- */
- public DiskFileItem(String fieldName,
- String contentType, boolean isFormField, String fileName,
- int sizeThreshold, File repository) {
- this.fieldName = fieldName;
- this.contentType = contentType;
- this.isFormField = isFormField;
- this.fileName = fileName;
- this.sizeThreshold = sizeThreshold;
- this.repository = repository;
- }
-
-
- // ------------------------------- Methods from javax.activation.DataSource
-
-
- /**
- * Returns an {@link java.io.InputStream InputStream} that can be
- * used to retrieve the contents of the file.
- *
- * @return An {@link java.io.InputStream InputStream} that can be
- * used to retrieve the contents of the file.
- *
- * @throws IOException if an error occurs.
- */
- public InputStream getInputStream()
- throws IOException {
- if (!isInMemory()) {
- return new FileInputStream(dfos.getFile());
- }
-
- if (cachedContent == null) {
- cachedContent = dfos.getData();
- }
- return new ByteArrayInputStream(cachedContent);
- }
-
-
- /**
- * Returns the content type passed by the agent or <code>null</code> if
- * not defined.
- *
- * @return The content type passed by the agent or <code>null</code> if
- * not defined.
- */
- public String getContentType() {
- return contentType;
- }
-
-
- /**
- * Returns the content charset passed by the agent or <code>null</code> if
- * not defined.
- *
- * @return The content charset passed by the agent or <code>null</code> if
- * not defined.
- */
- public String getCharSet() {
- ParameterParser parser = new ParameterParser();
- parser.setLowerCaseNames(true);
- // Parameter parser can handle null input
- Map<String,String> params = parser.parse(getContentType(), ';');
- return params.get("charset");
- }
-
-
- /**
- * Returns the original filename in the client's filesystem.
- *
- * @return The original filename in the client's filesystem.
- */
- public String getName() {
- return fileName;
- }
-
-
- // ------------------------------------------------------- FileItem methods
-
-
- /**
- * Provides a hint as to whether or not the file contents will be read
- * from memory.
- *
- * @return <code>true</code> if the file contents will be read
- * from memory; <code>false</code> otherwise.
- */
- public boolean isInMemory() {
- if (cachedContent != null) {
- return true;
- }
- return dfos.isInMemory();
- }
-
-
- /**
- * Returns the size of the file.
- *
- * @return The size of the file, in bytes.
- */
- public long getSize() {
- if (size >= 0) {
- return size;
- } else if (cachedContent != null) {
- return cachedContent.length;
- } else if (dfos.isInMemory()) {
- return dfos.getData().length;
- } else {
- return dfos.getFile().length();
- }
- }
-
-
- /**
- * Returns the contents of the file as an array of bytes. If the
- * contents of the file were not yet cached in memory, they will be
- * loaded from the disk storage and cached.
- *
- * @return The contents of the file as an array of bytes.
- */
- public byte[] get() {
- if (isInMemory()) {
- if (cachedContent == null) {
- cachedContent = dfos.getData();
- }
- return cachedContent;
- }
-
- byte[] fileData = new byte[(int) getSize()];
- FileInputStream fis = null;
-
- try {
- fis = new FileInputStream(dfos.getFile());
- fis.read(fileData);
- } catch (IOException e) {
- fileData = null;
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
-
- return fileData;
- }
-
-
- /**
- * Returns the contents of the file as a String, using the specified
- * encoding. This method uses {@link #get()} to retrieve the
- * contents of the file.
- *
- * @param charset The charset to use.
- *
- * @return The contents of the file, as a string.
- *
- * @throws UnsupportedEncodingException if the requested character
- * encoding is not available.
- */
- public String getString(final String charset)
- throws UnsupportedEncodingException {
- return new String(get(), charset);
- }
-
-
- /**
- * Returns the contents of the file as a String, using the default
- * character encoding. This method uses {@link #get()} to retrieve the
- * contents of the file.
- *
- * @return The contents of the file, as a string.
- *
- * @todo Consider making this method throw UnsupportedEncodingException.
- */
- public String getString() {
- byte[] rawdata = get();
- String charset = getCharSet();
- if (charset == null) {
- charset = DEFAULT_CHARSET;
- }
- try {
- return new String(rawdata, charset);
- } catch (UnsupportedEncodingException e) {
- return new String(rawdata);
- }
- }
-
-
- /**
- * A convenience method to write an uploaded item to disk. The client code
- * is not concerned with whether or not the item is stored in memory, or on
- * disk in a temporary location. They just want to write the uploaded item
- * to a file.
- * <p>
- * This implementation first attempts to rename the uploaded item to the
- * specified destination file, if the item was originally written to disk.
- * Otherwise, the data will be copied to the specified file.
- * <p>
- * This method is only guaranteed to work <em>once</em>, the first time it
- * is invoked for a particular item. This is because, in the event that the
- * method renames a temporary file, that file will no longer be available
- * to copy or rename again at a later time.
- *
- * @param file The <code>File</code> into which the uploaded item should
- * be stored.
- *
- * @throws Exception if an error occurs.
- */
- public void write(File file) throws Exception {
- if (isInMemory()) {
- FileOutputStream fout = null;
- try {
- fout = new FileOutputStream(file);
- fout.write(get());
- } finally {
- if (fout != null) {
- fout.close();
- }
- }
- } else {
- File outputFile = getStoreLocation();
- if (outputFile != null) {
- // Save the length of the file
- size = outputFile.length();
- /*
- * The uploaded file is being stored on disk
- * in a temporary location so move it to the
- * desired file.
- */
- if (!outputFile.renameTo(file)) {
- BufferedInputStream in = null;
- BufferedOutputStream out = null;
- try {
- in = new BufferedInputStream(
- new FileInputStream(outputFile));
- out = new BufferedOutputStream(
- new FileOutputStream(file));
- IOUtils.copy(in, out);
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // ignore
- }
- }
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
- }
- } else {
- /*
- * For whatever reason we cannot write the
- * file to disk.
- */
- throw new FileUploadException(
- "Cannot write uploaded file to disk!");
- }
- }
- }
-
-
- /**
- * Deletes the underlying storage for a file item, including deleting any
- * associated temporary disk file. Although this storage will be deleted
- * automatically when the <code>FileItem</code> instance is garbage
- * collected, this method can be used to ensure that this is done at an
- * earlier time, thus preserving system resources.
- */
- public void delete() {
- cachedContent = null;
- File outputFile = getStoreLocation();
- if (outputFile != null && outputFile.exists()) {
- outputFile.delete();
- }
- }
-
-
- /**
- * Returns the name of the field in the multipart form corresponding to
- * this file item.
- *
- * @return The name of the form field.
- *
- * @see #setFieldName(java.lang.String)
- *
- */
- public String getFieldName() {
- return fieldName;
- }
-
-
- /**
- * Sets the field name used to reference this file item.
- *
- * @param fieldName The name of the form field.
- *
- * @see #getFieldName()
- *
- */
- public void setFieldName(String fieldName) {
- this.fieldName = fieldName;
- }
-
-
- /**
- * Determines whether or not a <code>FileItem</code> instance represents
- * a simple form field.
- *
- * @return <code>true</code> if the instance represents a simple form
- * field; <code>false</code> if it represents an uploaded file.
- *
- * @see #setFormField(boolean)
- *
- */
- public boolean isFormField() {
- return isFormField;
- }
-
-
- /**
- * Specifies whether or not a <code>FileItem</code> instance represents
- * a simple form field.
- *
- * @param state <code>true</code> if the instance represents a simple form
- * field; <code>false</code> if it represents an uploaded file.
- *
- * @see #isFormField()
- *
- */
- public void setFormField(boolean state) {
- isFormField = state;
- }
-
-
- /**
- * Returns an {@link java.io.OutputStream OutputStream} that can
- * be used for storing the contents of the file.
- *
- * @return An {@link java.io.OutputStream OutputStream} that can be used
- * for storing the contensts of the file.
- *
- * @throws IOException if an error occurs.
- */
- public OutputStream getOutputStream()
- throws IOException {
- if (dfos == null) {
- File outputFile = getTempFile();
- dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
- }
- return dfos;
- }
-
-
- // --------------------------------------------------------- Public methods
-
-
- /**
- * Returns the {@link java.io.File} object for the <code>FileItem</code>'s
- * data's temporary location on the disk. Note that for
- * <code>FileItem</code>s that have their data stored in memory,
- * this method will return <code>null</code>. When handling large
- * files, you can use {@link java.io.File#renameTo(java.io.File)} to
- * move the file to new location without copying the data, if the
- * source and destination locations reside within the same logical
- * volume.
- *
- * @return The data file, or <code>null</code> if the data is stored in
- * memory.
- */
- public File getStoreLocation() {
- return dfos == null ? null : dfos.getFile();
- }
-
-
- // ------------------------------------------------------ Protected methods
-
-
- /**
- * Removes the file contents from the temporary storage.
- */
- @Override
- protected void finalize() {
- File outputFile = dfos.getFile();
-
- if (outputFile != null && outputFile.exists()) {
- outputFile.delete();
- }
- }
-
-
- /**
- * Creates and returns a {@link java.io.File File} representing a uniquely
- * named temporary file in the configured repository path. The lifetime of
- * the file is tied to the lifetime of the <code>FileItem</code> instance;
- * the file will be deleted when the instance is garbage collected.
- *
- * @return The {@link java.io.File File} to be used for temporary storage.
- */
- protected File getTempFile() {
- if (tempFile == null) {
- File tempDir = repository;
- if (tempDir == null) {
- tempDir = new File(System.getProperty("java.io.tmpdir"));
- }
-
- String tempFileName =
- "upload_" + UID + "_" + getUniqueId() + ".tmp";
-
- tempFile = new File(tempDir, tempFileName);
- }
- return tempFile;
- }
-
-
- // -------------------------------------------------------- Private methods
-
-
- /**
- * Returns an identifier that is unique within the class loader used to
- * load this class, but does not have random-like apearance.
- *
- * @return A String with the non-random looking instance identifier.
- */
- private static String getUniqueId() {
- final int limit = 100000000;
- int current;
- synchronized (DiskFileItem.class) {
- current = counter++;
- }
- String id = Integer.toString(current);
-
- // If you manage to get more than 100 million of ids, you'll
- // start getting ids longer than 8 characters.
- if (current < limit) {
- id = ("00000000" + id).substring(id.length());
- }
- return id;
- }
-
-
-
-
- /**
- * Returns a string representation of this object.
- *
- * @return a string representation of this object.
- */
- @Override
- public String toString() {
- return "name=" + this.getName()
- + ", StoreLocation="
- + String.valueOf(this.getStoreLocation())
- + ", size="
- + this.getSize()
- + "bytes, "
- + "isFormField=" + isFormField()
- + ", FieldName="
- + this.getFieldName();
- }
-
-
- // -------------------------------------------------- Serialization methods
-
-
- /**
- * Writes the state of this object during serialization.
- *
- * @param out The stream to which the state should be written.
- *
- * @throws IOException if an error occurs.
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- // Read the data
- if (dfos.isInMemory()) {
- cachedContent = get();
- } else {
- cachedContent = null;
- dfosFile = dfos.getFile();
- }
-
- // write out values
- out.defaultWriteObject();
- }
-
- /**
- * Reads the state of this object during deserialization.
- *
- * @param in The stream from which the state should be read.
- *
- * @throws IOException if an error occurs.
- * @throws ClassNotFoundException if class cannot be found.
- */
- private void readObject(ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- // read values
- in.defaultReadObject();
-
- OutputStream output = getOutputStream();
- if (cachedContent != null) {
- output.write(cachedContent);
- } else {
- FileInputStream input = new FileInputStream(dfosFile);
- IOUtils.copy(input, output);
- dfosFile.delete();
- dfosFile = null;
- }
- output.close();
-
- cachedContent = null;
- }
-
- /**
- * Returns the file item headers.
- * @return The file items headers.
- */
- public FileItemHeaders getHeaders() {
- return headers;
- }
-
- /**
- * Sets the file item headers.
- * @param pHeaders The file items headers.
- */
- public void setHeaders(FileItemHeaders pHeaders) {
- headers = pHeaders;
- }
-}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,223 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.File;
-
-
-/**
- * <p>The default {@link org.apache.commons.fileupload.FileItemFactory}
- * implementation. This implementation creates
- * {@link org.apache.commons.fileupload.FileItem} instances which keep their
- * content either in memory, for smaller items, or in a temporary file on disk,
- * for larger items. The size threshold, above which content will be stored on
- * disk, is configurable, as is the directory in which temporary files will be
- * created.</p>
- *
- * <p>If not otherwise configured, the default configuration values are as
- * follows:
- * <ul>
- * <li>Size threshold is 10KB.</li>
- * <li>Repository is the system default temp directory, as returned by
- * <code>System.getProperty("java.io.tmpdir")</code>.</li>
- * </ul>
- * </p>
- *
- * <p>When using the <code>DiskFileItemFactory</code>, then you should
- * consider the following: Temporary files are automatically deleted as
- * soon as they are no longer needed. (More precisely, when the
- * corresponding instance of {@link java.io.File} is garbage collected.)
- * Cleaning up those files is done by an instance of
- * {@link FileCleaningTracker}, and an associated thread. In a complex
- * environment, for example in a web application, you should consider
- * terminating this thread, for example, when your web application
- * ends. See the section on "Resource cleanup"
- * in the users guide of commons-fileupload.</p>
- *
- * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
- *
- * @since FileUpload 1.1
- *
- * @version $Id: DiskFileItemFactory.java 881493 2009-11-17 20:30:39Z markt $
- */
-public class DiskFileItemFactory implements FileItemFactory {
-
- // ----------------------------------------------------- Manifest constants
-
-
- /**
- * The default threshold above which uploads will be stored on disk.
- */
- public static final int DEFAULT_SIZE_THRESHOLD = 10240;
-
-
- // ----------------------------------------------------- Instance Variables
-
-
- /**
- * The directory in which uploaded files will be stored, if stored on disk.
- */
- private File repository;
-
-
- /**
- * The threshold above which uploads will be stored on disk.
- */
- private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
-
-
- /**
- * <p>The instance of {@link FileCleaningTracker}, which is responsible
- * for deleting temporary files.</p>
- * <p>May be null, if tracking files is not required.</p>
- */
- private FileCleaningTracker fileCleaningTracker;
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Constructs an unconfigured instance of this class. The resulting factory
- * may be configured by calling the appropriate setter methods.
- */
- public DiskFileItemFactory() {
- this(DEFAULT_SIZE_THRESHOLD, null);
- }
-
-
- /**
- * Constructs a preconfigured instance of this class.
- *
- * @param sizeThreshold The threshold, in bytes, below which items will be
- * retained in memory and above which they will be
- * stored as a file.
- * @param repository The data repository, which is the directory in
- * which files will be created, should the item size
- * exceed the threshold.
- */
- public DiskFileItemFactory(int sizeThreshold, File repository) {
- this.sizeThreshold = sizeThreshold;
- this.repository = repository;
- }
-
- // ------------------------------------------------------------- Properties
-
-
- /**
- * Returns the directory used to temporarily store files that are larger
- * than the configured size threshold.
- *
- * @return The directory in which temporary files will be located.
- *
- * @see #setRepository(java.io.File)
- *
- */
- public File getRepository() {
- return repository;
- }
-
-
- /**
- * Sets the directory used to temporarily store files that are larger
- * than the configured size threshold.
- *
- * @param repository The directory in which temporary files will be located.
- *
- * @see #getRepository()
- *
- */
- public void setRepository(File repository) {
- this.repository = repository;
- }
-
-
- /**
- * Returns the size threshold beyond which files are written directly to
- * disk. The default value is 10240 bytes.
- *
- * @return The size threshold, in bytes.
- *
- * @see #setSizeThreshold(int)
- */
- public int getSizeThreshold() {
- return sizeThreshold;
- }
-
-
- /**
- * Sets the size threshold beyond which files are written directly to disk.
- *
- * @param sizeThreshold The size threshold, in bytes.
- *
- * @see #getSizeThreshold()
- *
- */
- public void setSizeThreshold(int sizeThreshold) {
- this.sizeThreshold = sizeThreshold;
- }
-
-
- // --------------------------------------------------------- Public Methods
-
- /**
- * Create a new {@link org.apache.commons.fileupload.disk.DiskFileItem}
- * instance from the supplied parameters and the local factory
- * configuration.
- *
- * @param fieldName The name of the form field.
- * @param contentType The content type of the form field.
- * @param isFormField <code>true</code> if this is a plain form field;
- * <code>false</code> otherwise.
- * @param fileName The name of the uploaded file, if any, as supplied
- * by the browser or other client.
- *
- * @return The newly created file item.
- */
- public FileItem createItem(String fieldName, String contentType,
- boolean isFormField, String fileName) {
- DiskFileItem result = new DiskFileItem(fieldName, contentType,
- isFormField, fileName, sizeThreshold, repository);
- FileCleaningTracker tracker = getFileCleaningTracker();
- if (tracker != null) {
- tracker.track(result.getTempFile(), this);
- }
- return result;
- }
-
-
- /**
- * Returns the tracker, which is responsible for deleting temporary
- * files.
- * @return An instance of {@link FileCleaningTracker}, defaults to
- * {@link org.apache.commons.io.FileCleaner#getInstance()}. Null,
- * if temporary files aren't tracked.
- */
- public FileCleaningTracker getFileCleaningTracker() {
- return fileCleaningTracker;
- }
-
- /**
- * Returns the tracker, which is responsible for deleting temporary
- * files.
- * @param pTracker An instance of {@link FileCleaningTracker},
- * which will from now on track the created files. May be null
- * to disable tracking.
- */
- public void setFileCleaningTracker(FileCleaningTracker pTracker) {
- fileCleaningTracker = pTracker;
- }
-}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/FileCleanerCleanup.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileCleanerCleanup.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileCleanerCleanup.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextListener;
-import javax.servlet.ServletContextEvent;
-
-
-/**
- * A servlet context listener, which ensures that the
- * {@link org.apache.commons.io.FileCleaner FileCleaner's}
- * reaper thread is terminated,
- * when the web application is destroyed.
- */
-public class FileCleanerCleanup implements ServletContextListener {
- /**
- * Attribute name, which is used for storing an instance of
- * {@link FileCleaningTracker} in the web application.
- */
- public static final String FILE_CLEANING_TRACKER_ATTRIBUTE
- = FileCleanerCleanup.class.getName() + ".FileCleaningTracker";
-
- /**
- * Returns the instance of {@link FileCleaningTracker}, which is
- * associated with the given {@link ServletContext}.
- * @param pServletContext The servlet context to query
- * @return The contexts tracker
- */
- public static FileCleaningTracker
- getFileCleaningTracker(ServletContext pServletContext) {
- return (FileCleaningTracker)
- pServletContext.getAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE);
- }
-
- /**
- * Sets the instance of {@link FileCleaningTracker}, which is
- * associated with the given {@link ServletContext}.
- * @param pServletContext The servlet context to modify
- * @param pTracker The tracker to set
- */
- public static void setFileCleaningTracker(ServletContext pServletContext,
- FileCleaningTracker pTracker) {
- pServletContext.setAttribute(FILE_CLEANING_TRACKER_ATTRIBUTE, pTracker);
- }
-
- /**
- * Called when the web application is initialized. Does
- * nothing.
- * @param sce The servlet context, used for calling
- * {@link #setFileCleaningTracker(ServletContext, FileCleaningTracker)}.
- */
- public void contextInitialized(ServletContextEvent sce) {
- setFileCleaningTracker(sce.getServletContext(),
- new FileCleaningTracker());
- }
-
- /**
- * Called when the web application is being destroyed.
- * Calls {@link FileCleaningTracker#exitWhenFinished()}.
- * @param sce The servlet context, used for calling
- * {@link #getFileCleaningTracker(ServletContext)}.
- */
- public void contextDestroyed(ServletContextEvent sce) {
- getFileCleaningTracker(sce.getServletContext()).exitWhenFinished();
- }
-}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileCleaningTracker.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,259 +1,259 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.File;
-import java.lang.ref.PhantomReference;
-import java.lang.ref.ReferenceQueue;
-import java.util.Collection;
-import java.util.Vector;
-
-/**
- * Keeps track of files awaiting deletion, and deletes them when an associated
- * marker object is reclaimed by the garbage collector.
- * <p>
- * This utility creates a background thread to handle file deletion.
- * Each file to be deleted is registered with a handler object.
- * When the handler object is garbage collected, the file is deleted.
- * <p>
- * In an environment with multiple class loaders (a servlet container, for
- * example), you should consider stopping the background thread if it is no
- * longer needed. This is done by invoking the method
- * {@link #exitWhenFinished}, typically in
- * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
- *
- * @author Noel Bergman
- * @author Martin Cooper
- * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $
- */
-public class FileCleaningTracker {
- /**
- * Queue of <code>Tracker</code> instances being watched.
- */
- ReferenceQueue /* Tracker */ q = new ReferenceQueue();
- /**
- * Collection of <code>Tracker</code> instances in existence.
- */
- final Collection<Tracker> trackers = new Vector<Tracker>(); // synchronized
- /**
- * Whether to terminate the thread when the tracking is complete.
- */
- volatile boolean exitWhenFinished = false;
- /**
- * The thread that will clean up registered files.
- */
- Thread reaper;
-
- //-----------------------------------------------------------------------
- /**
- * Track the specified file, using the provided marker, deleting the file
- * when the marker instance is garbage collected.
- * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
- *
- * @param file the file to be tracked, not null
- * @param marker the marker object used to track the file, not null
- * @throws NullPointerException if the file is null
- */
- public void track(File file, Object marker) {
- track(file, marker, (FileDeleteStrategy) null);
- }
-
- /**
- * Track the specified file, using the provided marker, deleting the file
- * when the marker instance is garbage collected.
- * The speified deletion strategy is used.
- *
- * @param file the file to be tracked, not null
- * @param marker the marker object used to track the file, not null
- * @param deleteStrategy the strategy to delete the file, null means normal
- * @throws NullPointerException if the file is null
- */
- public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
- if (file == null) {
- throw new NullPointerException("The file must not be null");
- }
- addTracker(file.getPath(), marker, deleteStrategy);
- }
-
- /**
- * Track the specified file, using the provided marker, deleting the file
- * when the marker instance is garbage collected.
- * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
- *
- * @param path the full path to the file to be tracked, not null
- * @param marker the marker object used to track the file, not null
- * @throws NullPointerException if the path is null
- */
- public void track(String path, Object marker) {
- track(path, marker, (FileDeleteStrategy) null);
- }
-
- /**
- * Track the specified file, using the provided marker, deleting the file
- * when the marker instance is garbage collected.
- * The speified deletion strategy is used.
- *
- * @param path the full path to the file to be tracked, not null
- * @param marker the marker object used to track the file, not null
- * @param deleteStrategy the strategy to delete the file, null means normal
- * @throws NullPointerException if the path is null
- */
- public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
- if (path == null) {
- throw new NullPointerException("The path must not be null");
- }
- addTracker(path, marker, deleteStrategy);
- }
-
- /**
- * Adds a tracker to the list of trackers.
- *
- * @param path the full path to the file to be tracked, not null
- * @param marker the marker object used to track the file, not null
- * @param deleteStrategy the strategy to delete the file, null means normal
- */
- private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) {
- // synchronized block protects reaper
- if (exitWhenFinished) {
- throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
- }
- if (reaper == null) {
- reaper = new Reaper();
- reaper.start();
- }
- trackers.add(new Tracker(path, deleteStrategy, marker, q));
- }
-
- //-----------------------------------------------------------------------
- /**
- * Retrieve the number of files currently being tracked, and therefore
- * awaiting deletion.
- *
- * @return the number of files being tracked
- */
- public int getTrackCount() {
- return trackers.size();
- }
-
- /**
- * Call this method to cause the file cleaner thread to terminate when
- * there are no more objects being tracked for deletion.
- * <p>
- * In a simple environment, you don't need this method as the file cleaner
- * thread will simply exit when the JVM exits. In a more complex environment,
- * with multiple class loaders (such as an application server), you should be
- * aware that the file cleaner thread will continue running even if the class
- * loader it was started from terminates. This can consitute a memory leak.
- * <p>
- * For example, suppose that you have developed a web application, which
- * contains the commons-io jar file in your WEB-INF/lib directory. In other
- * words, the FileCleaner class is loaded through the class loader of your
- * web application. If the web application is terminated, but the servlet
- * container is still running, then the file cleaner thread will still exist,
- * posing a memory leak.
- * <p>
- * This method allows the thread to be terminated. Simply call this method
- * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}.
- * One called, no new objects can be tracked by the file cleaner.
- */
- public synchronized void exitWhenFinished() {
- // synchronized block protects reaper
- exitWhenFinished = true;
- if (reaper != null) {
- synchronized (reaper) {
- reaper.interrupt();
- }
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * The reaper thread.
- */
- private final class Reaper extends Thread {
- /** Construct a new Reaper */
- Reaper() {
- super("File Reaper");
- setPriority(Thread.MAX_PRIORITY);
- setDaemon(true);
- }
-
- /**
- * Run the reaper thread that will delete files as their associated
- * marker objects are reclaimed by the garbage collector.
- */
- @Override
- public void run() {
- // thread exits when exitWhenFinished is true and there are no more tracked objects
- while (exitWhenFinished == false || trackers.size() > 0) {
- Tracker tracker = null;
- try {
- // Wait for a tracker to remove.
- tracker = (Tracker) q.remove();
- } catch (Exception e) {
- continue;
- }
- if (tracker != null) {
- tracker.delete();
- tracker.clear();
- trackers.remove(tracker);
- }
- }
- }
- }
-
- //-----------------------------------------------------------------------
- /**
- * Inner class which acts as the reference for a file pending deletion.
- */
- private static final class Tracker extends PhantomReference {
-
- /**
- * The full path to the file being tracked.
- */
- private final String path;
- /**
- * The strategy for deleting files.
- */
- private final FileDeleteStrategy deleteStrategy;
-
- /**
- * Constructs an instance of this class from the supplied parameters.
- *
- * @param path the full path to the file to be tracked, not null
- * @param deleteStrategy the strategy to delete the file, null means normal
- * @param marker the marker object used to track the file, not null
- * @param queue the queue on to which the tracker will be pushed, not null
- */
- Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue queue) {
- super(marker, queue);
- this.path = path;
- this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy);
- }
-
- /**
- * Deletes the file associated with this tracker instance.
- *
- * @return <code>true</code> if the file was deleted successfully;
- * <code>false</code> otherwise.
- */
- public boolean delete() {
- return deleteStrategy.deleteQuietly(new File(path));
- }
- }
-
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload;
+
+import java.io.File;
+import java.lang.ref.PhantomReference;
+import java.lang.ref.ReferenceQueue;
+import java.util.Collection;
+import java.util.Vector;
+
+/**
+ * Keeps track of files awaiting deletion, and deletes them when an associated
+ * marker object is reclaimed by the garbage collector.
+ * <p>
+ * This utility creates a background thread to handle file deletion.
+ * Each file to be deleted is registered with a handler object.
+ * When the handler object is garbage collected, the file is deleted.
+ * <p>
+ * In an environment with multiple class loaders (a servlet container, for
+ * example), you should consider stopping the background thread if it is no
+ * longer needed. This is done by invoking the method
+ * {@link #exitWhenFinished}, typically in
+ * {@link javax.servlet.ServletContextListener#contextDestroyed} or similar.
+ *
+ * @author Noel Bergman
+ * @author Martin Cooper
+ * @version $Id: FileCleaner.java 490987 2006-12-29 12:11:48Z scolebourne $
+ */
+public class FileCleaningTracker {
+ /**
+ * Queue of <code>Tracker</code> instances being watched.
+ */
+ ReferenceQueue /* Tracker */ q = new ReferenceQueue();
+ /**
+ * Collection of <code>Tracker</code> instances in existence.
+ */
+ final Collection<Tracker> trackers = new Vector<Tracker>(); // synchronized
+ /**
+ * Whether to terminate the thread when the tracking is complete.
+ */
+ volatile boolean exitWhenFinished = false;
+ /**
+ * The thread that will clean up registered files.
+ */
+ Thread reaper;
+
+ //-----------------------------------------------------------------------
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the file is null
+ */
+ public void track(File file, Object marker) {
+ track(file, marker, (FileDeleteStrategy) null);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param file the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the file is null
+ */
+ public void track(File file, Object marker, FileDeleteStrategy deleteStrategy) {
+ if (file == null) {
+ throw new NullPointerException("The file must not be null");
+ }
+ addTracker(file.getPath(), marker, deleteStrategy);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The {@link FileDeleteStrategy#NORMAL normal} deletion strategy will be used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @throws NullPointerException if the path is null
+ */
+ public void track(String path, Object marker) {
+ track(path, marker, (FileDeleteStrategy) null);
+ }
+
+ /**
+ * Track the specified file, using the provided marker, deleting the file
+ * when the marker instance is garbage collected.
+ * The speified deletion strategy is used.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @throws NullPointerException if the path is null
+ */
+ public void track(String path, Object marker, FileDeleteStrategy deleteStrategy) {
+ if (path == null) {
+ throw new NullPointerException("The path must not be null");
+ }
+ addTracker(path, marker, deleteStrategy);
+ }
+
+ /**
+ * Adds a tracker to the list of trackers.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param marker the marker object used to track the file, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ */
+ private synchronized void addTracker(String path, Object marker, FileDeleteStrategy deleteStrategy) {
+ // synchronized block protects reaper
+ if (exitWhenFinished) {
+ throw new IllegalStateException("No new trackers can be added once exitWhenFinished() is called");
+ }
+ if (reaper == null) {
+ reaper = new Reaper();
+ reaper.start();
+ }
+ trackers.add(new Tracker(path, deleteStrategy, marker, q));
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Retrieve the number of files currently being tracked, and therefore
+ * awaiting deletion.
+ *
+ * @return the number of files being tracked
+ */
+ public int getTrackCount() {
+ return trackers.size();
+ }
+
+ /**
+ * Call this method to cause the file cleaner thread to terminate when
+ * there are no more objects being tracked for deletion.
+ * <p>
+ * In a simple environment, you don't need this method as the file cleaner
+ * thread will simply exit when the JVM exits. In a more complex environment,
+ * with multiple class loaders (such as an application server), you should be
+ * aware that the file cleaner thread will continue running even if the class
+ * loader it was started from terminates. This can consitute a memory leak.
+ * <p>
+ * For example, suppose that you have developed a web application, which
+ * contains the commons-io jar file in your WEB-INF/lib directory. In other
+ * words, the FileCleaner class is loaded through the class loader of your
+ * web application. If the web application is terminated, but the servlet
+ * container is still running, then the file cleaner thread will still exist,
+ * posing a memory leak.
+ * <p>
+ * This method allows the thread to be terminated. Simply call this method
+ * in the resource cleanup code, such as {@link javax.servlet.ServletContextListener#contextDestroyed}.
+ * One called, no new objects can be tracked by the file cleaner.
+ */
+ public synchronized void exitWhenFinished() {
+ // synchronized block protects reaper
+ exitWhenFinished = true;
+ if (reaper != null) {
+ synchronized (reaper) {
+ reaper.interrupt();
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * The reaper thread.
+ */
+ private final class Reaper extends Thread {
+ /** Construct a new Reaper */
+ Reaper() {
+ super("File Reaper");
+ setPriority(Thread.MAX_PRIORITY);
+ setDaemon(true);
+ }
+
+ /**
+ * Run the reaper thread that will delete files as their associated
+ * marker objects are reclaimed by the garbage collector.
+ */
+ @Override
+ public void run() {
+ // thread exits when exitWhenFinished is true and there are no more tracked objects
+ while (exitWhenFinished == false || trackers.size() > 0) {
+ Tracker tracker = null;
+ try {
+ // Wait for a tracker to remove.
+ tracker = (Tracker) q.remove();
+ } catch (Exception e) {
+ continue;
+ }
+ if (tracker != null) {
+ tracker.delete();
+ tracker.clear();
+ trackers.remove(tracker);
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------
+ /**
+ * Inner class which acts as the reference for a file pending deletion.
+ */
+ private static final class Tracker extends PhantomReference {
+
+ /**
+ * The full path to the file being tracked.
+ */
+ private final String path;
+ /**
+ * The strategy for deleting files.
+ */
+ private final FileDeleteStrategy deleteStrategy;
+
+ /**
+ * Constructs an instance of this class from the supplied parameters.
+ *
+ * @param path the full path to the file to be tracked, not null
+ * @param deleteStrategy the strategy to delete the file, null means normal
+ * @param marker the marker object used to track the file, not null
+ * @param queue the queue on to which the tracker will be pushed, not null
+ */
+ Tracker(String path, FileDeleteStrategy deleteStrategy, Object marker, ReferenceQueue queue) {
+ super(marker, queue);
+ this.path = path;
+ this.deleteStrategy = (deleteStrategy == null ? FileDeleteStrategy.NORMAL : deleteStrategy);
+ }
+
+ /**
+ * Deletes the file associated with this tracker instance.
+ *
+ * @return <code>true</code> if the file was deleted successfully;
+ * <code>false</code> otherwise.
+ */
+ public boolean delete() {
+ return deleteStrategy.deleteQuietly(new File(path));
+ }
+ }
+
+}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -28,8 +28,8 @@
* <code>multipart/form-data</code> POST request.
*
* <p> After retrieving an instance of this class from a {@link
- * org.apache.commons.fileupload.FileUpload FileUpload} instance (see
- * {@link org.apache.commons.fileupload.FileUpload
+ * org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} instance (see
+ * {@link org.apache.tomcat.util.http.fileupload.FileUpload
* #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
* either request all contents of the file at once using {@link #get()} or
* request an {@link java.io.InputStream InputStream} with
@@ -85,6 +85,10 @@
* the Opera browser, do include path information.
*
* @return The original filename in the client's filesystem.
+ * @throws InvalidFileNameException The file name contains a NUL character,
+ * which might be an indicator of a security attack. If you intend to
+ * use the file name anyways, catch the exception and use
+ * InvalidFileNameException#getName().
*/
String getName();
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeaders.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,77 +1,77 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.util.Iterator;
-
-/**
- * <p> This class provides support for accessing the headers for a file or form
- * item that was received within a <code>multipart/form-data</code> POST
- * request.</p>
- *
- * @author Michael C. Macaluso
- * @since 1.3
- */
-public interface FileItemHeaders {
- /**
- * Returns the value of the specified part header as a <code>String</code>.
- * If the part did not include a header of the specified name, this method
- * return <code>null</code>. If there are multiple headers with the same
- * name, this method returns the first header in the item. The header
- * name is case insensitive.
- *
- * @param name a <code>String</code> specifying the header name
- * @return a <code>String</code> containing the value of the requested
- * header, or <code>null</code> if the item does not have a header
- * of that name
- */
- String getHeader(String name);
-
- /**
- * <p>
- * Returns all the values of the specified item header as an
- * <code>Enumeration</code> of <code>String</code> objects.
- * </p>
- * <p>
- * If the item did not include any headers of the specified name, this
- * method returns an empty <code>Enumeration</code>. The header name is
- * case insensitive.
- * </p>
- *
- * @param name a <code>String</code> specifying the header name
- * @return an <code>Enumeration</code> containing the values of the
- * requested header. If the item does not have any headers of
- * that name, return an empty <code>Enumeration</code>
- */
- Iterator<String> getHeaders(String name);
-
- /**
- * <p>
- * Returns an <code>Enumeration</code> of all the header names.
- * </p>
- * <p>
- * If the item did not include any headers of the specified name, this
- * method returns an empty <code>Enumeration</code>. The header name is
- * case insensitive.
- * </p>
- *
- * @return an <code>Enumeration</code> containing the values of the
- * requested header. If the item does not have any headers of
- * that name return an empty <code>Enumeration</code>
- */
- Iterator<String> getHeaderNames();
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload;
+
+import java.util.Iterator;
+
+/**
+ * <p> This class provides support for accessing the headers for a file or form
+ * item that was received within a <code>multipart/form-data</code> POST
+ * request.</p>
+ *
+ * @author Michael C. Macaluso
+ * @since 1.3
+ */
+public interface FileItemHeaders {
+ /**
+ * Returns the value of the specified part header as a <code>String</code>.
+ * If the part did not include a header of the specified name, this method
+ * return <code>null</code>. If there are multiple headers with the same
+ * name, this method returns the first header in the item. The header
+ * name is case insensitive.
+ *
+ * @param name a <code>String</code> specifying the header name
+ * @return a <code>String</code> containing the value of the requested
+ * header, or <code>null</code> if the item does not have a header
+ * of that name
+ */
+ String getHeader(String name);
+
+ /**
+ * <p>
+ * Returns all the values of the specified item header as an
+ * <code>Enumeration</code> of <code>String</code> objects.
+ * </p>
+ * <p>
+ * If the item did not include any headers of the specified name, this
+ * method returns an empty <code>Enumeration</code>. The header name is
+ * case insensitive.
+ * </p>
+ *
+ * @param name a <code>String</code> specifying the header name
+ * @return an <code>Enumeration</code> containing the values of the
+ * requested header. If the item does not have any headers of
+ * that name, return an empty <code>Enumeration</code>
+ */
+ Iterator<String> getHeaders(String name);
+
+ /**
+ * <p>
+ * Returns an <code>Enumeration</code> of all the header names.
+ * </p>
+ * <p>
+ * If the item did not include any headers of the specified name, this
+ * method returns an empty <code>Enumeration</code>. The header name is
+ * case insensitive.
+ * </p>
+ *
+ * @return an <code>Enumeration</code> containing the values of the
+ * requested header. If the item does not have any headers of
+ * that name return an empty <code>Enumeration</code>
+ */
+ Iterator<String> getHeaderNames();
+}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-
-/**
- * Default implementation of the {@link FileItemHeaders} interface.
- *
- * @author Michael C. Macaluso
- * @since 1.3
- */
-public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
- private static final long serialVersionUID = -4455695752627032559L;
-
- /**
- * Map of <code>String</code> keys to a <code>List</code> of
- * <code>String</code> instances.
- */
- private final Map<String,List<String>> headerNameToValueListMap =
- new HashMap<String,List<String>>();
-
- /**
- * List to preserve order of headers as added. This would not be
- * needed if a <code>LinkedHashMap</code> could be used, but don't
- * want to depend on 1.4.
- */
- private final List<String> headerNameList = new ArrayList<String>();
-
- public String getHeader(String name) {
- String nameLower = name.toLowerCase(Locale.ENGLISH);
- List<String> headerValueList = headerNameToValueListMap.get(nameLower);
- if (null == headerValueList) {
- return null;
- }
- return headerValueList.get(0);
- }
-
- public Iterator<String> getHeaderNames() {
- return headerNameList.iterator();
- }
-
- public Iterator<String> getHeaders(String name) {
- String nameLower = name.toLowerCase(Locale.ENGLISH);
- List<String> headerValueList = headerNameToValueListMap.get(nameLower);
- if (null == headerValueList) {
- return Collections.<String>emptyList().iterator();
- }
- return headerValueList.iterator();
- }
-
- /**
- * Method to add header values to this instance.
- *
- * @param name name of this header
- * @param value value of this header
- */
- public synchronized void addHeader(String name, String value) {
- String nameLower = name.toLowerCase(Locale.ENGLISH);
- List<String> headerValueList = headerNameToValueListMap.get(nameLower);
- if (null == headerValueList) {
- headerValueList = new ArrayList<String>();
- headerNameToValueListMap.put(nameLower, headerValueList);
- headerNameList.add(nameLower);
- }
- headerValueList.add(value);
- }
-}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersSupport.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,47 +1,47 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-/**
- * Interface that will indicate that {@link FileItem} or {@link FileItemStream}
- * implementations will accept the headers read for the item.
- *
- * @author Michael C. Macaluso
- * @since 1.3
- *
- * @see FileItem
- * @see FileItemStream
- */
-public interface FileItemHeadersSupport {
- /**
- * Returns the collection of headers defined locally within this item.
- *
- * @return the {@link FileItemHeaders} present for this item.
- */
- FileItemHeaders getHeaders();
-
- /**
- * Sets the headers read from within an item. Implementations of
- * {@link FileItem} or {@link FileItemStream} should implement this
- * interface to be able to get the raw headers found within the item
- * header block.
- *
- * @param headers the instance that holds onto the headers
- * for this instance.
- */
- void setHeaders(FileItemHeaders headers);
-}
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload;
+
+/**
+ * Interface that will indicate that {@link FileItem} or {@link FileItemStream}
+ * implementations will accept the headers read for the item.
+ *
+ * @author Michael C. Macaluso
+ * @since 1.3
+ *
+ * @see FileItem
+ * @see FileItemStream
+ */
+public interface FileItemHeadersSupport {
+ /**
+ * Returns the collection of headers defined locally within this item.
+ *
+ * @return the {@link FileItemHeaders} present for this item.
+ */
+ FileItemHeaders getHeaders();
+
+ /**
+ * Sets the headers read from within an item. Implementations of
+ * {@link FileItem} or {@link FileItemStream} should implement this
+ * interface to be able to get the raw headers found within the item
+ * header block.
+ *
+ * @param headers the instance that holds onto the headers
+ * for this instance.
+ */
+ void setHeaders(FileItemHeaders headers);
+}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileUpload.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileUpload.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileUpload.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -23,8 +23,8 @@
* <p>This class handles multiple files per single HTML widget, sent using
* <code>multipart/mixed</code> encoding type, as specified by
* <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>. Use {@link
- * #parseRequest(javax.servlet.http.HttpServletRequest)} to acquire a list
- * of {@link org.apache.commons.fileupload.FileItem FileItems} associated
+ * #parseRequest(RequestContext)} to acquire a list
+ * of {@link org.apache.tomcat.util.http.fileupload.FileItem FileItems} associated
* with a given HTML widget.</p>
*
* <p>How the data for individual parts is stored is determined by the factory
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -20,6 +20,7 @@
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -28,6 +29,10 @@
import javax.servlet.http.HttpServletRequest;
import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream;
+import org.apache.tomcat.util.http.fileupload.util.Closeable;
+import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl;
+import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream;
+import org.apache.tomcat.util.http.fileupload.util.Streams;
/**
@@ -36,8 +41,8 @@
* <p>This class handles multiple files per single HTML widget, sent using
* <code>multipart/mixed</code> encoding type, as specified by
* <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>. Use {@link
- * #parseRequest(HttpServletRequest)} to acquire a list of {@link
- * org.apache.commons.fileupload.FileItem}s associated with a given HTML
+ * #parseRequest(RequestContext)} to acquire a list of {@link
+ * org.apache.tomcat.util.http.fileupload.FileItem}s associated with a given HTML
* widget.</p>
*
* <p>How the data for individual parts is stored is determined by the factory
@@ -293,19 +298,23 @@
*/
public List<FileItem> parseRequest(RequestContext ctx)
throws FileUploadException {
+ List<FileItem> items = new ArrayList<FileItem>();
+ boolean successful = false;
try {
FileItemIterator iter = getItemIterator(ctx);
- List<FileItem> items = new ArrayList<FileItem>();
FileItemFactory fac = getFileItemFactory();
if (fac == null) {
throw new NullPointerException(
"No FileItemFactory has been set.");
}
while (iter.hasNext()) {
- FileItemStream item = iter.next();
+ final FileItemStream item = iter.next();
+ // Don't use getName() here to prevent an InvalidFileNameException.
+ final String fileName = ((org.apache.tomcat.util.http.fileupload.FileUploadBase.FileItemIteratorImpl.FileItemStreamImpl) item).name;
FileItem fileItem = fac.createItem(item.getFieldName(),
item.getContentType(), item.isFormField(),
- item.getName());
+ fileName);
+ items.add(fileItem);
try {
Streams.copy(item.openStream(), fileItem.getOutputStream(),
true);
@@ -320,13 +329,24 @@
final FileItemHeaders fih = item.getHeaders();
((FileItemHeadersSupport) fileItem).setHeaders(fih);
}
- items.add(fileItem);
}
+ successful = true;
return items;
} catch (FileUploadIOException e) {
throw (FileUploadException) e.getCause();
} catch (IOException e) {
throw new FileUploadException(e.getMessage(), e);
+ } finally {
+ if (!successful) {
+ for (Iterator<FileItem> iterator = items.iterator(); iterator.hasNext();) {
+ FileItem fileItem = iterator.next();
+ try {
+ fileItem.delete();
+ } catch (Throwable e) {
+ // ignore it
+ }
+ }
+ }
}
}
@@ -543,7 +563,7 @@
/**
* Default implementation of {@link FileItemStream}.
*/
- private class FileItemStreamImpl implements FileItemStream {
+ class FileItemStreamImpl implements FileItemStream {
/** The file items content type.
*/
private final String contentType;
@@ -587,13 +607,15 @@
if (fileSizeMax != -1) {
if (pContentLength != -1
&& pContentLength > fileSizeMax) {
- FileUploadException e =
+ FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
"The field " + fieldName
+ " exceeds its maximum permitted "
+ " size of " + fileSizeMax
- + " characters.",
+ + " bytes.",
pContentLength, fileSizeMax);
+ e.setFileName(pName);
+ e.setFieldName(pFieldName);
throw new FileUploadIOException(e);
}
istream = new LimitedInputStream(istream, fileSizeMax) {
@@ -601,13 +623,15 @@
protected void raiseError(long pSizeMax, long pCount)
throws IOException {
itemStream.close(true);
- FileUploadException e =
+ FileSizeLimitExceededException e =
new FileSizeLimitExceededException(
"The field " + fieldName
+ " exceeds its maximum permitted "
+ " size of " + pSizeMax
- + " characters.",
+ + " bytes.",
pCount, pSizeMax);
+ e.setFieldName(fieldName);
+ e.setFileName(name);
throw new FileUploadIOException(e);
}
};
@@ -634,9 +658,13 @@
/**
* Returns the items file name.
* @return File name, if known, or null.
+ * @throws InvalidFileNameException The file name contains a NUL character,
+ * which might be an indicator of a security attack. If you intend to
+ * use the file name anyways, catch the exception and use
+ * InvalidFileNameException#getName().
*/
public String getName() {
- return name;
+ return Streams.checkFileName(name);
}
/**
@@ -1020,7 +1048,7 @@
*/
public abstract static class SizeException extends FileUploadException {
- private static final long serialVersionUID = 1L;
+ private static final long serialVersionUID = -8776225574705254126L;
/**
* The actual size of the request.
@@ -1096,6 +1124,16 @@
private static final long serialVersionUID = 8150776562029630058L;
/**
+ * File name of the item, which caused the exception.
+ */
+ private String fileName;
+
+ /**
+ * Field name of the item, which caused the exception.
+ */
+ private String fieldName;
+
+ /**
* Constructs a <code>SizeExceededException</code> with
* the specified detail message, and actual and permitted sizes.
*
@@ -1107,6 +1145,40 @@
long permitted) {
super(message, actual, permitted);
}
+
+ /**
+ * Returns the file name of the item, which caused the
+ * exception.
+ * @return File name, if known, or null.
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Sets the file name of the item, which caused the
+ * exception.
+ */
+ public void setFileName(String pFileName) {
+ fileName = pFileName;
+ }
+
+ /**
+ * Returns the field name of the item, which caused the
+ * exception.
+ * @return Field name, if known, or null.
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+ /**
+ * Sets the field name of the item, which caused the
+ * exception.
+ */
+ public void setFieldName(String pFieldName) {
+ fieldName = pFieldName;
+ }
}
/**
Added: trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload;
+
+
+/**
+ * This exception is thrown in case of an invalid file name.
+ * A file name is invalid, if it contains a NUL character.
+ * Attackers might use this to circumvent security checks:
+ * For example, a malicious user might upload a file with the name
+ * "foo.exe\0.png". This file name might pass security checks (i.e.
+ * checks for the extension ".png"), while, depending on the underlying
+ * C library, it might create a file named "foo.exe", as the NUL
+ * character is the string terminator in C.
+ */
+public class InvalidFileNameException extends RuntimeException {
+ private static final long serialVersionUID = 7922042602454350470L;
+ private final String name;
+
+ /**
+ * Creates a new instance.
+ * @param pName The file name causing the exception.
+ * @param pMessage A human readable error message.
+ */
+ public InvalidFileNameException(String pName, String pMessage) {
+ super(pMessage);
+ name = pName;
+ }
+
+ /**
+ * Returns the invalid file name.
+ */
+ public String getName() {
+ return name;
+ }
+}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,158 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.FilterInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-
-/**
- * An input stream, which limits its data size. This stream is
- * used, if the content length is unknown.
- */
-public abstract class LimitedInputStream
- extends FilterInputStream implements Closeable {
- /**
- * The maximum size of an item, in bytes.
- */
- private long sizeMax;
- /**
- * The current number of bytes.
- */
- private long count;
- /**
- * Whether this stream is already closed.
- */
- private boolean closed;
-
- /**
- * Creates a new instance.
- * @param pIn The input stream, which shall be limited.
- * @param pSizeMax The limit; no more than this number of bytes
- * shall be returned by the source stream.
- */
- public LimitedInputStream(InputStream pIn, long pSizeMax) {
- super(pIn);
- sizeMax = pSizeMax;
- }
-
- /**
- * Called to indicate, that the input streams limit has
- * been exceeded.
- * @param pSizeMax The input streams limit, in bytes.
- * @param pCount The actual number of bytes.
- * @throws IOException The called method is expected
- * to raise an IOException.
- */
- protected abstract void raiseError(long pSizeMax, long pCount)
- throws IOException;
-
- /** Called to check, whether the input streams
- * limit is reached.
- * @throws IOException The given limit is exceeded.
- */
- private void checkLimit() throws IOException {
- if (count > sizeMax) {
- raiseError(sizeMax, count);
- }
- }
-
- /**
- * Reads the next byte of data from this input stream. The value
- * byte is returned as an <code>int</code> in the range
- * <code>0</code> to <code>255</code>. If no byte is available
- * because the end of the stream has been reached, the value
- * <code>-1</code> is returned. This method blocks until input data
- * is available, the end of the stream is detected, or an exception
- * is thrown.
- * <p>
- * This method
- * simply performs <code>in.read()</code> and returns the result.
- *
- * @return the next byte of data, or <code>-1</code> if the end of the
- * stream is reached.
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- public int read() throws IOException {
- int res = super.read();
- if (res != -1) {
- count++;
- checkLimit();
- }
- return res;
- }
-
- /**
- * Reads up to <code>len</code> bytes of data from this input stream
- * into an array of bytes. If <code>len</code> is not zero, the method
- * blocks until some input is available; otherwise, no
- * bytes are read and <code>0</code> is returned.
- * <p>
- * This method simply performs <code>in.read(b, off, len)</code>
- * and returns the result.
- *
- * @param b the buffer into which the data is read.
- * @param off The start offset in the destination array
- * <code>b</code>.
- * @param len the maximum number of bytes read.
- * @return the total number of bytes read into the buffer, or
- * <code>-1</code> if there is no more data because the end of
- * the stream has been reached.
- * @exception NullPointerException If <code>b</code> is <code>null</code>.
- * @exception IndexOutOfBoundsException If <code>off</code> is negative,
- * <code>len</code> is negative, or <code>len</code> is greater than
- * <code>b.length - off</code>
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- public int read(byte[] b, int off, int len) throws IOException {
- int res = super.read(b, off, len);
- if (res > 0) {
- count += res;
- checkLimit();
- }
- return res;
- }
-
- /**
- * Returns, whether this stream is already closed.
- * @return True, if the stream is closed, otherwise false.
- * @throws IOException An I/O error occurred.
- */
- public boolean isClosed() throws IOException {
- return closed;
- }
-
- /**
- * Closes this input stream and releases any system resources
- * associated with the stream.
- * This
- * method simply performs <code>in.close()</code>.
- *
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- public void close() throws IOException {
- closed = true;
- super.close();
- }
-}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -22,7 +22,10 @@
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import org.apache.tomcat.util.http.fileupload.util.Closeable;
+import org.apache.tomcat.util.http.fileupload.util.Streams;
+
/**
* <p> Low level API for processing file uploads.
*
@@ -58,24 +61,22 @@
* <p>Here is an example of usage of this class.<br>
*
* <pre>
- * try {
- * MultipartStream multipartStream = new MultipartStream(input,
- * boundary);
- * boolean nextPart = multipartStream.skipPreamble();
- * OutputStream output;
- * while(nextPart) {
- * header = chunks.readHeader();
- * // process headers
- * // create some output stream
- * multipartStream.readBodyPart(output);
- * nextPart = multipartStream.readBoundary();
- * }
- * } catch(MultipartStream.MalformedStreamException e) {
- * // the stream failed to follow required syntax
- * } catch(IOException) {
- * // a read or write error occurred
- * }
- *
+ * try {
+ * MultipartStream multipartStream = new MultipartStream(input, boundary);
+ * boolean nextPart = multipartStream.skipPreamble();
+ * OutputStream output;
+ * while(nextPart) {
+ * String header = multipartStream.readHeaders();
+ * // process headers
+ * // create some output stream
+ * multipartStream.readBodyData(output);
+ * nextPart = multipartStream.readBoundary();
+ * }
+ * } catch(MultipartStream.MalformedStreamException e) {
+ * // the stream failed to follow required syntax
+ * } catch(IOException e) {
+ * // a read or write error occurred
+ * }
* </pre>
*
* @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
@@ -89,7 +90,7 @@
* Internal class, which is used to invoke the
* {@link ProgressListener}.
*/
- static class ProgressNotifier {
+ public static class ProgressNotifier {
/** The listener to invoke.
*/
private final ProgressListener listener;
@@ -125,6 +126,7 @@
*/
void noteItem() {
++items;
+ notifyListener();
}
/** Called for notifying the listener.
*/
@@ -962,70 +964,4 @@
return closed;
}
}
-
- // ------------------------------------------------------ Debugging methods
-
-
- // These are the methods that were used to debug this stuff.
- /*
-
- // Dump data.
- protected void dump()
- {
- System.out.println("01234567890");
- byte[] temp = new byte[buffer.length];
- for(int i=0; i<buffer.length; i++)
- {
- if (buffer[i] == 0x0D || buffer[i] == 0x0A)
- {
- temp[i] = 0x21;
- }
- else
- {
- temp[i] = buffer[i];
- }
- }
- System.out.println(new String(temp));
- int i;
- for (i=0; i<head; i++)
- System.out.print(" ");
- System.out.println("h");
- for (i=0; i<tail; i++)
- System.out.print(" ");
- System.out.println("t");
- System.out.flush();
- }
-
- // Main routine, for testing purposes only.
- //
- // @param args A String[] with the command line arguments.
- // @throws Exception, a generic exception.
- public static void main( String[] args )
- throws Exception
- {
- File boundaryFile = new File("boundary.dat");
- int boundarySize = (int)boundaryFile.length();
- byte[] boundary = new byte[boundarySize];
- FileInputStream input = new FileInputStream(boundaryFile);
- input.read(boundary,0,boundarySize);
-
- input = new FileInputStream("multipart.dat");
- MultipartStream chunks = new MultipartStream(input, boundary);
-
- int i = 0;
- String header;
- OutputStream output;
- boolean nextChunk = chunks.skipPreamble();
- while (nextChunk)
- {
- header = chunks.readHeaders();
- System.out.println("!"+header+"!");
- System.out.println("wrote part"+i+".dat");
- output = new FileOutputStream("part"+(i++)+".dat");
- chunks.readBodyData(output);
- nextChunk = chunks.readBoundary();
- }
- }
-
- */
}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/ParameterParser.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -17,6 +17,7 @@
package org.apache.tomcat.util.http.fileupload;
import java.util.HashMap;
+import java.util.Locale;
import java.util.Map;
/**
@@ -264,7 +265,7 @@
* Extracts a map of name/value pairs from the given array of
* characters. Names are expected to be unique.
*
- * @param chars the array of characters that contains a sequence of
+ * @param inputChars the array of characters that contains a sequence of
* name/value pairs
* @param separator the name/value pairs separator
*
@@ -281,7 +282,7 @@
* Extracts a map of name/value pairs from the given array of
* characters. Names are expected to be unique.
*
- * @param chars the array of characters that contains a sequence of
+ * @param inputChars the array of characters that contains a sequence of
* name/value pairs
* @param offset - the initial offset.
* @param length - the length.
@@ -319,7 +320,7 @@
}
if ((paramName != null) && (paramName.length() > 0)) {
if (this.lowerCaseNames) {
- paramName = paramName.toLowerCase();
+ paramName = paramName.toLowerCase(Locale.ENGLISH);
}
params.put(paramName, paramValue);
}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,147 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Locale;
-
-import javax.servlet.http.HttpServletRequest;
-
-
-/**
- * <p>High level API for processing file uploads.</p>
- *
- * <p>This class handles multiple files per single HTML widget, sent using
- * <code>multipart/mixed</code> encoding type, as specified by
- * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>. Use {@link
- * #parseRequest(HttpServletRequest)} to acquire a list of {@link
- * org.apache.commons.fileupload.FileItem}s associated with a given HTML
- * widget.</p>
- *
- * <p>How the data for individual parts is stored is determined by the factory
- * used to create them; a given part may be in memory, on disk, or somewhere
- * else.</p>
- *
- * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
- * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
- * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
- * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
- * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
- * @author Sean C. Sullivan
- *
- * @version $Id: ServletFileUpload.java 881562 2009-11-17 22:03:22Z markt $
- */
-public class ServletFileUpload extends FileUpload {
-
- // ---------------------------------------------------------- Class methods
-
-
- /**
- * Utility method that determines whether the request contains multipart
- * content.
- *
- * @param request The servlet request to be evaluated. Must be non-null.
- *
- * @return <code>true</code> if the request is multipart;
- * <code>false</code> otherwise.
- */
- public static final boolean isMultipartContent(
- HttpServletRequest request) {
- if (!"post".equals(request.getMethod().toLowerCase(Locale.ENGLISH))) {
- return false;
- }
- String contentType = request.getContentType();
- if (contentType == null) {
- return false;
- }
- if (contentType.toLowerCase().startsWith(MULTIPART)) {
- return true;
- }
- return false;
- }
-
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Constructs an uninitialised instance of this class. A factory must be
- * configured, using <code>setFileItemFactory()</code>, before attempting
- * to parse requests.
- *
- * @see FileUpload#FileUpload(FileItemFactory)
- */
- public ServletFileUpload() {
- super();
- }
-
-
- /**
- * Constructs an instance of this class which uses the supplied factory to
- * create <code>FileItem</code> instances.
- *
- * @see FileUpload#FileUpload()
- * @param fileItemFactory The factory to use for creating file items.
- */
- public ServletFileUpload(FileItemFactory fileItemFactory) {
- super(fileItemFactory);
- }
-
-
- // --------------------------------------------------------- Public methods
-
-
- /**
- * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
- * compliant <code>multipart/form-data</code> stream.
- *
- * @param request The servlet request to be parsed.
- *
- * @return A list of <code>FileItem</code> instances parsed from the
- * request, in the order that they were transmitted.
- *
- * @throws FileUploadException if there are problems reading/parsing
- * the request or storing files.
- */
- public List<FileItem> parseRequest(HttpServletRequest request)
- throws FileUploadException {
- return parseRequest(new ServletRequestContext(request));
- }
-
-
- /**
- * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
- * compliant <code>multipart/form-data</code> stream.
- *
- * @param request The servlet request to be parsed.
- *
- * @return An iterator to instances of <code>FileItemStream</code>
- * parsed from the request, in the order that they were
- * transmitted.
- *
- * @throws FileUploadException if there are problems reading/parsing
- * the request or storing files.
- * @throws IOException An I/O error occurred. This may be a network
- * error while communicating with the client or a problem while
- * storing the uploaded content.
- */
- public FileItemIterator getItemIterator(HttpServletRequest request)
- throws FileUploadException, IOException {
- return super.getItemIterator(new ServletRequestContext(request));
- }
-}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.InputStream;
-import java.io.IOException;
-import javax.servlet.http.HttpServletRequest;
-
-
-/**
- * <p>Provides access to the request information needed for a request made to
- * an HTTP servlet.</p>
- *
- * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
- *
- * @since FileUpload 1.1
- *
- * @version $Id: ServletRequestContext.java 881533 2009-11-17 21:21:41Z markt $
- */
-public class ServletRequestContext implements RequestContext {
-
- // ----------------------------------------------------- Instance Variables
-
- /**
- * The request for which the context is being provided.
- */
- private HttpServletRequest request;
-
-
- // ----------------------------------------------------------- Constructors
-
- /**
- * Construct a context for this request.
- *
- * @param request The request to which this context applies.
- */
- public ServletRequestContext(HttpServletRequest request) {
- this.request = request;
- }
-
-
- // --------------------------------------------------------- Public Methods
-
- /**
- * Retrieve the character encoding for the request.
- *
- * @return The character encoding for the request.
- */
- public String getCharacterEncoding() {
- return request.getCharacterEncoding();
- }
-
- /**
- * Retrieve the content type of the request.
- *
- * @return The content type of the request.
- */
- public String getContentType() {
- return request.getContentType();
- }
-
- /**
- * Retrieve the content length of the request.
- *
- * @return The content length of the request.
- */
- public int getContentLength() {
- return request.getContentLength();
- }
-
- /**
- * Retrieve the input stream for the request.
- *
- * @return The input stream for the request.
- *
- * @throws IOException if a problem occurs.
- */
- public InputStream getInputStream() throws IOException {
- return request.getInputStream();
- }
-
- /**
- * Returns a string representation of this object.
- *
- * @return a string representation of this object.
- */
- @Override
- public String toString() {
- return "ContentLength="
- + this.getContentLength()
- + ", ContentType="
- + this.getContentType();
- }
-}
Deleted: trunk/java/org/apache/tomcat/util/http/fileupload/Streams.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/Streams.java 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/Streams.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -1,166 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.tomcat.util.http.fileupload;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-
-
-/** Utility class for working with streams.
- */
-public final class Streams {
- /**
- * Private constructor, to prevent instantiation.
- * This class has only static methods.
- */
- private Streams() {
- // Does nothing
- }
-
- /**
- * Default buffer size for use in
- * {@link #copy(InputStream, OutputStream, boolean)}.
- */
- private static final int DEFAULT_BUFFER_SIZE = 8192;
-
- /**
- * Copies the contents of the given {@link InputStream}
- * to the given {@link OutputStream}. Shortcut for
- * <pre>
- * copy(pInputStream, pOutputStream, new byte[8192]);
- * </pre>
- * @param pInputStream The input stream, which is being read.
- * It is guaranteed, that {@link InputStream#close()} is called
- * on the stream.
- * @param pOutputStream The output stream, to which data should
- * be written. May be null, in which case the input streams
- * contents are simply discarded.
- * @param pClose True guarantees, that {@link OutputStream#close()}
- * is called on the stream. False indicates, that only
- * {@link OutputStream#flush()} should be called finally.
- *
- * @return Number of bytes, which have been copied.
- * @throws IOException An I/O error occurred.
- */
- public static long copy(InputStream pInputStream,
- OutputStream pOutputStream, boolean pClose)
- throws IOException {
- return copy(pInputStream, pOutputStream, pClose,
- new byte[DEFAULT_BUFFER_SIZE]);
- }
-
- /**
- * Copies the contents of the given {@link InputStream}
- * to the given {@link OutputStream}.
- * @param pIn The input stream, which is being read.
- * It is guaranteed, that {@link InputStream#close()} is called
- * on the stream.
- * @param pOut The output stream, to which data should
- * be written. May be null, in which case the input streams
- * contents are simply discarded.
- * @param pClose True guarantees, that {@link OutputStream#close()}
- * is called on the stream. False indicates, that only
- * {@link OutputStream#flush()} should be called finally.
- * @param pBuffer Temporary buffer, which is to be used for
- * copying data.
- * @return Number of bytes, which have been copied.
- * @throws IOException An I/O error occurred.
- */
- public static long copy(InputStream pIn,
- OutputStream pOut, boolean pClose,
- byte[] pBuffer)
- throws IOException {
- OutputStream out = pOut;
- InputStream in = pIn;
- try {
- long total = 0;
- for (;;) {
- int res = in.read(pBuffer);
- if (res == -1) {
- break;
- }
- if (res > 0) {
- total += res;
- if (out != null) {
- out.write(pBuffer, 0, res);
- }
- }
- }
- if (out != null) {
- if (pClose) {
- out.close();
- } else {
- out.flush();
- }
- out = null;
- }
- in.close();
- in = null;
- return total;
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (Throwable t) {
- /* Ignore me */
- }
- }
- if (pClose && out != null) {
- try {
- out.close();
- } catch (Throwable t) {
- /* Ignore me */
- }
- }
- }
- }
-
- /**
- * This convenience method allows to read a
- * {@link org.apache.commons.fileupload.FileItemStream}'s
- * content into a string. The platform's default character encoding
- * is used for converting bytes into characters.
- * @param pStream The input stream to read.
- * @see #asString(InputStream, String)
- * @return The streams contents, as a string.
- * @throws IOException An I/O error occurred.
- */
- public static String asString(InputStream pStream) throws IOException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- copy(pStream, baos, true);
- return baos.toString();
- }
-
- /**
- * This convenience method allows to read a
- * {@link org.apache.commons.fileupload.FileItemStream}'s
- * content into a string, using the given character encoding.
- * @param pStream The input stream to read.
- * @param pEncoding The character encoding, typically "UTF-8".
- * @see #asString(InputStream)
- * @return The streams contents, as a string.
- * @throws IOException An I/O error occurred.
- */
- public static String asString(InputStream pStream, String pEncoding)
- throws IOException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- copy(pStream, baos, true);
- return baos.toString(pEncoding);
- }
-}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,747 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.disk;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Map;
+
+import org.apache.tomcat.util.http.fileupload.DeferredFileOutputStream;
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
+import org.apache.tomcat.util.http.fileupload.FileItemHeadersSupport;
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+import org.apache.tomcat.util.http.fileupload.InvalidFileNameException;
+import org.apache.tomcat.util.http.fileupload.IOUtils;
+import org.apache.tomcat.util.http.fileupload.ParameterParser;
+import org.apache.tomcat.util.http.fileupload.RequestContext;
+import org.apache.tomcat.util.http.fileupload.util.Streams;
+
+
+/**
+ * <p> The default implementation of the
+ * {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} interface.
+ *
+ * <p> After retrieving an instance of this class from a {@link
+ * org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} instance (see
+ * {@link org.apache.tomcat.util.http.fileupload.FileUpload
+ * #parseRequest(RequestContext)}), you may
+ * either request all contents of file at once using {@link #get()} or
+ * request an {@link java.io.InputStream InputStream} with
+ * {@link #getInputStream()} and process the file without attempting to load
+ * it into memory, which may come handy with large files.
+ *
+ * <p>Temporary files, which are created for file items, should be
+ * deleted later on. The best way to do this is using a
+ * {@link org.apache.tomcat.util.http.fileupload.FileCleaningTracker
+ * FileCleaningTracker}, which you can set on the
+ * {@link DiskFileItemFactory}. However, if you do use such a tracker,
+ * then you must consider the following: Temporary files are automatically
+ * deleted as soon as they are no longer needed. (More precisely, when the
+ * corresponding instance of {@link java.io.File} is garbage collected.)
+ * This is done by the so-called reaper thread, which is started
+ * automatically when the class {@link org.apache.commons.io.FileCleaner}
+ * is loaded.
+ * It might make sense to terminate that thread, for example, if
+ * your web application ends. See the section on "Resource cleanup"
+ * in the users guide of commons-fileupload.</p>
+ *
+ * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
+ * @author <a href="mailto:sean@informage.net">Sean Legassick</a>
+ * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
+ * @author <a href="mailto:jmcnally@apache.org">John McNally</a>
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ * @author Sean C. Sullivan
+ *
+ * @since FileUpload 1.1
+ *
+ * @version $Id: DiskFileItem.java 981816 2010-08-03 10:44:58Z markt $
+ */
+public class DiskFileItem
+ implements FileItem, FileItemHeadersSupport {
+
+ // ----------------------------------------------------- Manifest constants
+
+ /**
+ * The UID to use when serializing this instance.
+ */
+ private static final long serialVersionUID = 2237570099615271025L;
+
+
+ /**
+ * Default content charset to be used when no explicit charset
+ * parameter is provided by the sender. Media subtypes of the
+ * "text" type are defined to have a default charset value of
+ * "ISO-8859-1" when received via HTTP.
+ */
+ public static final String DEFAULT_CHARSET = "ISO-8859-1";
+
+
+ // ----------------------------------------------------------- Data members
+
+
+ /**
+ * UID used in unique file name generation.
+ */
+ private static final String UID =
+ new java.rmi.server.UID().toString()
+ .replace(':', '_').replace('-', '_');
+
+ /**
+ * Counter used in unique identifier generation.
+ */
+ private static int counter = 0;
+
+
+ /**
+ * The name of the form field as provided by the browser.
+ */
+ private String fieldName;
+
+
+ /**
+ * The content type passed by the browser, or <code>null</code> if
+ * not defined.
+ */
+ private String contentType;
+
+
+ /**
+ * Whether or not this item is a simple form field.
+ */
+ private boolean isFormField;
+
+
+ /**
+ * The original filename in the user's filesystem.
+ */
+ private String fileName;
+
+
+ /**
+ * The size of the item, in bytes. This is used to cache the size when a
+ * file item is moved from its original location.
+ */
+ private long size = -1;
+
+
+ /**
+ * The threshold above which uploads will be stored on disk.
+ */
+ private int sizeThreshold;
+
+
+ /**
+ * The directory in which uploaded files will be stored, if stored on disk.
+ */
+ private File repository;
+
+
+ /**
+ * Cached contents of the file.
+ */
+ private byte[] cachedContent;
+
+
+ /**
+ * Output stream for this item.
+ */
+ private transient DeferredFileOutputStream dfos;
+
+ /**
+ * The temporary file to use.
+ */
+ private transient File tempFile;
+
+ /**
+ * File to allow for serialization of the content of this item.
+ */
+ private File dfosFile;
+
+ /**
+ * The file items headers.
+ */
+ private FileItemHeaders headers;
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs a new <code>DiskFileItem</code> instance.
+ *
+ * @param fieldName The name of the form field.
+ * @param contentType The content type passed by the browser or
+ * <code>null</code> if not specified.
+ * @param isFormField Whether or not this item is a plain form field, as
+ * opposed to a file upload.
+ * @param fileName The original filename in the user's filesystem, or
+ * <code>null</code> if not specified.
+ * @param sizeThreshold The threshold, in bytes, below which items will be
+ * retained in memory and above which they will be
+ * stored as a file.
+ * @param repository The data repository, which is the directory in
+ * which files will be created, should the item size
+ * exceed the threshold.
+ */
+ public DiskFileItem(String fieldName,
+ String contentType, boolean isFormField, String fileName,
+ int sizeThreshold, File repository) {
+ this.fieldName = fieldName;
+ this.contentType = contentType;
+ this.isFormField = isFormField;
+ this.fileName = fileName;
+ this.sizeThreshold = sizeThreshold;
+ this.repository = repository;
+ }
+
+
+ // ------------------------------- Methods from javax.activation.DataSource
+
+
+ /**
+ * Returns an {@link java.io.InputStream InputStream} that can be
+ * used to retrieve the contents of the file.
+ *
+ * @return An {@link java.io.InputStream InputStream} that can be
+ * used to retrieve the contents of the file.
+ *
+ * @throws IOException if an error occurs.
+ */
+ public InputStream getInputStream()
+ throws IOException {
+ if (!isInMemory()) {
+ return new FileInputStream(dfos.getFile());
+ }
+
+ if (cachedContent == null) {
+ cachedContent = dfos.getData();
+ }
+ return new ByteArrayInputStream(cachedContent);
+ }
+
+
+ /**
+ * Returns the content type passed by the agent or <code>null</code> if
+ * not defined.
+ *
+ * @return The content type passed by the agent or <code>null</code> if
+ * not defined.
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+
+ /**
+ * Returns the content charset passed by the agent or <code>null</code> if
+ * not defined.
+ *
+ * @return The content charset passed by the agent or <code>null</code> if
+ * not defined.
+ */
+ public String getCharSet() {
+ ParameterParser parser = new ParameterParser();
+ parser.setLowerCaseNames(true);
+ // Parameter parser can handle null input
+ Map<String,String> params = parser.parse(getContentType(), ';');
+ return params.get("charset");
+ }
+
+
+ /**
+ * Returns the original filename in the client's filesystem.
+ *
+ * @return The original filename in the client's filesystem.
+ * @throws InvalidFileNameException The file name contains a NUL character,
+ * which might be an indicator of a security attack. If you intend to
+ * use the file name anyways, catch the exception and use
+ * InvalidFileNameException#getName().
+ */
+ public String getName() {
+ return Streams.checkFileName(fileName);
+ }
+
+
+ // ------------------------------------------------------- FileItem methods
+
+
+ /**
+ * Provides a hint as to whether or not the file contents will be read
+ * from memory.
+ *
+ * @return <code>true</code> if the file contents will be read
+ * from memory; <code>false</code> otherwise.
+ */
+ public boolean isInMemory() {
+ if (cachedContent != null) {
+ return true;
+ }
+ return dfos.isInMemory();
+ }
+
+
+ /**
+ * Returns the size of the file.
+ *
+ * @return The size of the file, in bytes.
+ */
+ public long getSize() {
+ if (size >= 0) {
+ return size;
+ } else if (cachedContent != null) {
+ return cachedContent.length;
+ } else if (dfos.isInMemory()) {
+ return dfos.getData().length;
+ } else {
+ return dfos.getFile().length();
+ }
+ }
+
+
+ /**
+ * Returns the contents of the file as an array of bytes. If the
+ * contents of the file were not yet cached in memory, they will be
+ * loaded from the disk storage and cached.
+ *
+ * @return The contents of the file as an array of bytes.
+ */
+ public byte[] get() {
+ if (isInMemory()) {
+ if (cachedContent == null) {
+ cachedContent = dfos.getData();
+ }
+ return cachedContent;
+ }
+
+ byte[] fileData = new byte[(int) getSize()];
+ FileInputStream fis = null;
+
+ try {
+ fis = new FileInputStream(dfos.getFile());
+ fis.read(fileData);
+ } catch (IOException e) {
+ fileData = null;
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ return fileData;
+ }
+
+
+ /**
+ * Returns the contents of the file as a String, using the specified
+ * encoding. This method uses {@link #get()} to retrieve the
+ * contents of the file.
+ *
+ * @param charset The charset to use.
+ *
+ * @return The contents of the file, as a string.
+ *
+ * @throws UnsupportedEncodingException if the requested character
+ * encoding is not available.
+ */
+ public String getString(final String charset)
+ throws UnsupportedEncodingException {
+ return new String(get(), charset);
+ }
+
+
+ /**
+ * Returns the contents of the file as a String, using the default
+ * character encoding. This method uses {@link #get()} to retrieve the
+ * contents of the file.
+ *
+ * @return The contents of the file, as a string.
+ *
+ * TODO Consider making this method throw UnsupportedEncodingException.
+ */
+ public String getString() {
+ byte[] rawdata = get();
+ String charset = getCharSet();
+ if (charset == null) {
+ charset = DEFAULT_CHARSET;
+ }
+ try {
+ return new String(rawdata, charset);
+ } catch (UnsupportedEncodingException e) {
+ return new String(rawdata);
+ }
+ }
+
+
+ /**
+ * A convenience method to write an uploaded item to disk. The client code
+ * is not concerned with whether or not the item is stored in memory, or on
+ * disk in a temporary location. They just want to write the uploaded item
+ * to a file.
+ * <p>
+ * This implementation first attempts to rename the uploaded item to the
+ * specified destination file, if the item was originally written to disk.
+ * Otherwise, the data will be copied to the specified file.
+ * <p>
+ * This method is only guaranteed to work <em>once</em>, the first time it
+ * is invoked for a particular item. This is because, in the event that the
+ * method renames a temporary file, that file will no longer be available
+ * to copy or rename again at a later time.
+ *
+ * @param file The <code>File</code> into which the uploaded item should
+ * be stored.
+ *
+ * @throws Exception if an error occurs.
+ */
+ public void write(File file) throws Exception {
+ if (isInMemory()) {
+ FileOutputStream fout = null;
+ try {
+ fout = new FileOutputStream(file);
+ fout.write(get());
+ } finally {
+ if (fout != null) {
+ fout.close();
+ }
+ }
+ } else {
+ File outputFile = getStoreLocation();
+ if (outputFile != null) {
+ // Save the length of the file
+ size = outputFile.length();
+ /*
+ * The uploaded file is being stored on disk
+ * in a temporary location so move it to the
+ * desired file.
+ */
+ if (!outputFile.renameTo(file)) {
+ BufferedInputStream in = null;
+ BufferedOutputStream out = null;
+ try {
+ in = new BufferedInputStream(
+ new FileInputStream(outputFile));
+ out = new BufferedOutputStream(
+ new FileOutputStream(file));
+ IOUtils.copy(in, out);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * For whatever reason we cannot write the
+ * file to disk.
+ */
+ throw new FileUploadException(
+ "Cannot write uploaded file to disk!");
+ }
+ }
+ }
+
+
+ /**
+ * Deletes the underlying storage for a file item, including deleting any
+ * associated temporary disk file. Although this storage will be deleted
+ * automatically when the <code>FileItem</code> instance is garbage
+ * collected, this method can be used to ensure that this is done at an
+ * earlier time, thus preserving system resources.
+ */
+ public void delete() {
+ cachedContent = null;
+ File outputFile = getStoreLocation();
+ if (outputFile != null && outputFile.exists()) {
+ outputFile.delete();
+ }
+ }
+
+
+ /**
+ * Returns the name of the field in the multipart form corresponding to
+ * this file item.
+ *
+ * @return The name of the form field.
+ *
+ * @see #setFieldName(java.lang.String)
+ *
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+
+ /**
+ * Sets the field name used to reference this file item.
+ *
+ * @param fieldName The name of the form field.
+ *
+ * @see #getFieldName()
+ *
+ */
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+
+ /**
+ * Determines whether or not a <code>FileItem</code> instance represents
+ * a simple form field.
+ *
+ * @return <code>true</code> if the instance represents a simple form
+ * field; <code>false</code> if it represents an uploaded file.
+ *
+ * @see #setFormField(boolean)
+ *
+ */
+ public boolean isFormField() {
+ return isFormField;
+ }
+
+
+ /**
+ * Specifies whether or not a <code>FileItem</code> instance represents
+ * a simple form field.
+ *
+ * @param state <code>true</code> if the instance represents a simple form
+ * field; <code>false</code> if it represents an uploaded file.
+ *
+ * @see #isFormField()
+ *
+ */
+ public void setFormField(boolean state) {
+ isFormField = state;
+ }
+
+
+ /**
+ * Returns an {@link java.io.OutputStream OutputStream} that can
+ * be used for storing the contents of the file.
+ *
+ * @return An {@link java.io.OutputStream OutputStream} that can be used
+ * for storing the contensts of the file.
+ *
+ * @throws IOException if an error occurs.
+ */
+ public OutputStream getOutputStream()
+ throws IOException {
+ if (dfos == null) {
+ File outputFile = getTempFile();
+ dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
+ }
+ return dfos;
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Returns the {@link java.io.File} object for the <code>FileItem</code>'s
+ * data's temporary location on the disk. Note that for
+ * <code>FileItem</code>s that have their data stored in memory,
+ * this method will return <code>null</code>. When handling large
+ * files, you can use {@link java.io.File#renameTo(java.io.File)} to
+ * move the file to new location without copying the data, if the
+ * source and destination locations reside within the same logical
+ * volume.
+ *
+ * @return The data file, or <code>null</code> if the data is stored in
+ * memory.
+ */
+ public File getStoreLocation() {
+ return dfos == null ? null : dfos.getFile();
+ }
+
+
+ // ------------------------------------------------------ Protected methods
+
+
+ /**
+ * Removes the file contents from the temporary storage.
+ */
+ @Override
+ protected void finalize() {
+ File outputFile = dfos.getFile();
+
+ if (outputFile != null && outputFile.exists()) {
+ outputFile.delete();
+ }
+ }
+
+
+ /**
+ * Creates and returns a {@link java.io.File File} representing a uniquely
+ * named temporary file in the configured repository path. The lifetime of
+ * the file is tied to the lifetime of the <code>FileItem</code> instance;
+ * the file will be deleted when the instance is garbage collected.
+ *
+ * @return The {@link java.io.File File} to be used for temporary storage.
+ */
+ protected File getTempFile() {
+ if (tempFile == null) {
+ File tempDir = repository;
+ if (tempDir == null) {
+ tempDir = new File(System.getProperty("java.io.tmpdir"));
+ }
+
+ String tempFileName =
+ "upload_" + UID + "_" + getUniqueId() + ".tmp";
+
+ tempFile = new File(tempDir, tempFileName);
+ }
+ return tempFile;
+ }
+
+
+ // -------------------------------------------------------- Private methods
+
+
+ /**
+ * Returns an identifier that is unique within the class loader used to
+ * load this class, but does not have random-like apearance.
+ *
+ * @return A String with the non-random looking instance identifier.
+ */
+ private static String getUniqueId() {
+ final int limit = 100000000;
+ int current;
+ synchronized (DiskFileItem.class) {
+ current = counter++;
+ }
+ String id = Integer.toString(current);
+
+ // If you manage to get more than 100 million of ids, you'll
+ // start getting ids longer than 8 characters.
+ if (current < limit) {
+ id = ("00000000" + id).substring(id.length());
+ }
+ return id;
+ }
+
+
+
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return a string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return "name=" + this.getName()
+ + ", StoreLocation="
+ + String.valueOf(this.getStoreLocation())
+ + ", size="
+ + this.getSize()
+ + "bytes, "
+ + "isFormField=" + isFormField()
+ + ", FieldName="
+ + this.getFieldName();
+ }
+
+
+ // -------------------------------------------------- Serialization methods
+
+
+ /**
+ * Writes the state of this object during serialization.
+ *
+ * @param out The stream to which the state should be written.
+ *
+ * @throws IOException if an error occurs.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ // Read the data
+ if (dfos.isInMemory()) {
+ cachedContent = get();
+ } else {
+ cachedContent = null;
+ dfosFile = dfos.getFile();
+ }
+
+ // write out values
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Reads the state of this object during deserialization.
+ *
+ * @param in The stream from which the state should be read.
+ *
+ * @throws IOException if an error occurs.
+ * @throws ClassNotFoundException if class cannot be found.
+ */
+ private void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ // read values
+ in.defaultReadObject();
+
+ OutputStream output = getOutputStream();
+ if (cachedContent != null) {
+ output.write(cachedContent);
+ } else {
+ FileInputStream input = new FileInputStream(dfosFile);
+ IOUtils.copy(input, output);
+ dfosFile.delete();
+ dfosFile = null;
+ }
+ output.close();
+
+ cachedContent = null;
+ }
+
+ /**
+ * Returns the file item headers.
+ * @return The file items headers.
+ */
+ public FileItemHeaders getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Sets the file item headers.
+ * @param pHeaders The file items headers.
+ */
+ public void setHeaders(FileItemHeaders pHeaders) {
+ headers = pHeaders;
+ }
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,230 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.disk;
+
+import java.io.File;
+
+import org.apache.tomcat.util.http.fileupload.FileCleaningTracker;
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemFactory;
+
+
+/**
+ * <p>The default {@link org.apache.tomcat.util.http.fileupload.FileItemFactory}
+ * implementation. This implementation creates
+ * {@link org.apache.tomcat.util.http.fileupload.FileItem} instances which keep
+ * their
+ * content either in memory, for smaller items, or in a temporary file on disk,
+ * for larger items. The size threshold, above which content will be stored on
+ * disk, is configurable, as is the directory in which temporary files will be
+ * created.</p>
+ *
+ * <p>If not otherwise configured, the default configuration values are as
+ * follows:
+ * <ul>
+ * <li>Size threshold is 10KB.</li>
+ * <li>Repository is the system default temp directory, as returned by
+ * <code>System.getProperty("java.io.tmpdir")</code>.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>Temporary files, which are created for file items, should be
+ * deleted later on. The best way to do this is using a
+ * {@link FileCleaningTracker}, which you can set on the
+ * {@link DiskFileItemFactory}. However, if you do use such a tracker,
+ * then you must consider the following: Temporary files are automatically
+ * deleted as soon as they are no longer needed. (More precisely, when the
+ * corresponding instance of {@link java.io.File} is garbage collected.)
+ * This is done by the so-called reaper thread, which is started
+ * automatically when the class {@link org.apache.commons.io.FileCleaner}
+ * is loaded.
+ * It might make sense to terminate that thread, for example, if
+ * your web application ends. See the section on "Resource cleanup"
+ * in the users guide of commons-fileupload.</p>
+ *
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ *
+ * @since FileUpload 1.1
+ *
+ * @version $Id: DiskFileItemFactory.java 981816 2010-08-03 10:44:58Z markt $
+ */
+public class DiskFileItemFactory implements FileItemFactory {
+
+ // ----------------------------------------------------- Manifest constants
+
+
+ /**
+ * The default threshold above which uploads will be stored on disk.
+ */
+ public static final int DEFAULT_SIZE_THRESHOLD = 10240;
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * The directory in which uploaded files will be stored, if stored on disk.
+ */
+ private File repository;
+
+
+ /**
+ * The threshold above which uploads will be stored on disk.
+ */
+ private int sizeThreshold = DEFAULT_SIZE_THRESHOLD;
+
+
+ /**
+ * <p>The instance of {@link FileCleaningTracker}, which is responsible
+ * for deleting temporary files.</p>
+ * <p>May be null, if tracking files is not required.</p>
+ */
+ private FileCleaningTracker fileCleaningTracker;
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs an unconfigured instance of this class. The resulting factory
+ * may be configured by calling the appropriate setter methods.
+ */
+ public DiskFileItemFactory() {
+ this(DEFAULT_SIZE_THRESHOLD, null);
+ }
+
+
+ /**
+ * Constructs a preconfigured instance of this class.
+ *
+ * @param sizeThreshold The threshold, in bytes, below which items will be
+ * retained in memory and above which they will be
+ * stored as a file.
+ * @param repository The data repository, which is the directory in
+ * which files will be created, should the item size
+ * exceed the threshold.
+ */
+ public DiskFileItemFactory(int sizeThreshold, File repository) {
+ this.sizeThreshold = sizeThreshold;
+ this.repository = repository;
+ }
+
+ // ------------------------------------------------------------- Properties
+
+
+ /**
+ * Returns the directory used to temporarily store files that are larger
+ * than the configured size threshold.
+ *
+ * @return The directory in which temporary files will be located.
+ *
+ * @see #setRepository(java.io.File)
+ *
+ */
+ public File getRepository() {
+ return repository;
+ }
+
+
+ /**
+ * Sets the directory used to temporarily store files that are larger
+ * than the configured size threshold.
+ *
+ * @param repository The directory in which temporary files will be located.
+ *
+ * @see #getRepository()
+ *
+ */
+ public void setRepository(File repository) {
+ this.repository = repository;
+ }
+
+
+ /**
+ * Returns the size threshold beyond which files are written directly to
+ * disk. The default value is 10240 bytes.
+ *
+ * @return The size threshold, in bytes.
+ *
+ * @see #setSizeThreshold(int)
+ */
+ public int getSizeThreshold() {
+ return sizeThreshold;
+ }
+
+
+ /**
+ * Sets the size threshold beyond which files are written directly to disk.
+ *
+ * @param sizeThreshold The size threshold, in bytes.
+ *
+ * @see #getSizeThreshold()
+ *
+ */
+ public void setSizeThreshold(int sizeThreshold) {
+ this.sizeThreshold = sizeThreshold;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * Create a new {@link DiskFileItem}
+ * instance from the supplied parameters and the local factory
+ * configuration.
+ *
+ * @param fieldName The name of the form field.
+ * @param contentType The content type of the form field.
+ * @param isFormField <code>true</code> if this is a plain form field;
+ * <code>false</code> otherwise.
+ * @param fileName The name of the uploaded file, if any, as supplied
+ * by the browser or other client.
+ *
+ * @return The newly created file item.
+ */
+ public FileItem createItem(String fieldName, String contentType,
+ boolean isFormField, String fileName) {
+ DiskFileItem result = new DiskFileItem(fieldName, contentType,
+ isFormField, fileName, sizeThreshold, repository);
+ FileCleaningTracker tracker = getFileCleaningTracker();
+ if (tracker != null) {
+ tracker.track(result.getTempFile(), this);
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the tracker, which is responsible for deleting temporary
+ * files.
+ * @return An instance of {@link FileCleaningTracker}, or null
+ * (default), if temporary files aren't tracked.
+ */
+ public FileCleaningTracker getFileCleaningTracker() {
+ return fileCleaningTracker;
+ }
+
+ /**
+ * Sets the tracker, which is responsible for deleting temporary
+ * files.
+ * @param pTracker An instance of {@link FileCleaningTracker},
+ * which will from now on track the created files, or null
+ * (default), to disable tracking.
+ */
+ public void setFileCleaningTracker(FileCleaningTracker pTracker) {
+ fileCleaningTracker = pTracker;
+ }
+}
Modified: trunk/java/org/apache/tomcat/util/http/fileupload/package.html
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/package.html 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/package.html 2010-08-18 10:01:08 UTC (rev 1533)
@@ -14,10 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<!-- $Id: package.html 881493 2009-11-17 20:30:39Z markt $ -->
+<!-- $Id: package.html 981816 2010-08-03 10:44:58Z markt $ -->
<html>
<head>
- <title>Overview of the org.apache.commons.fileupload component</title>
+ <title>
+ Overview of the org.apache.tomcat.util.http.fileupload component
+ </title>
</head>
<body>
<p><b>NOTE:</b> This code has been copied from commons-fileupload 1.2.1 and
@@ -34,14 +36,12 @@
While this package provides the generic functionality for file uploads,
these classes are not typically used directly. Instead, normal usage
involves one of the provided extensions of
- {@link org.apache.commons.fileupload.FileUpload FileUpload} such as
- {@link org.apache.commons.fileupload.servlet.ServletFileUpload ServletFileUpload}
- or
- {@link org.apache.commons.fileupload.portlet.PortletFileUpload PortletFileUpload},
+ {@link org.apache.tomcat.util.http.fileupload.FileUpload FileUpload} such as
+ {@link org.apache.tomcat.util.http.fileupload.servlet.ServletFileUpload ServletFileUpload}
together with a factory for
- {@link org.apache.commons.fileupload.FileItem FileItem} instances,
+ {@link org.apache.tomcat.util.http.fileupload.FileItem FileItem} instances,
such as
- {@link org.apache.commons.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}.
+ {@link org.apache.tomcat.util.http.fileupload.disk.DiskFileItemFactory DiskFileItemFactory}.
</p>
<p>
The following is a brief example of typical usage in a servlet, storing
Added: trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.servlet;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemFactory;
+import org.apache.tomcat.util.http.fileupload.FileItemIterator;
+import org.apache.tomcat.util.http.fileupload.FileUpload;
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+
+
+/**
+ * <p>High level API for processing file uploads.</p>
+ *
+ * <p>This class handles multiple files per single HTML widget, sent using
+ * <code>multipart/mixed</code> encoding type, as specified by
+ * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>. Use {@link
+ * #parseRequest(HttpServletRequest)} to acquire a list of {@link
+ * org.apache.tomcat.util.http.fileupload.FileItem}s associated with a given HTML
+ * widget.</p>
+ *
+ * <p>How the data for individual parts is stored is determined by the factory
+ * used to create them; a given part may be in memory, on disk, or somewhere
+ * else.</p>
+ *
+ * @author <a href="mailto:Rafal.Krzewski@e-point.pl">Rafal Krzewski</a>
+ * @author <a href="mailto:dlr@collab.net">Daniel Rall</a>
+ * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
+ * @author <a href="mailto:jmcnally@collab.net">John McNally</a>
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ * @author Sean C. Sullivan
+ *
+ * @version $Id: ServletFileUpload.java 981816 2010-08-03 10:44:58Z markt $
+ */
+public class ServletFileUpload extends FileUpload {
+
+ // ---------------------------------------------------------- Class methods
+
+
+ /**
+ * Utility method that determines whether the request contains multipart
+ * content.
+ *
+ * @param request The servlet request to be evaluated. Must be non-null.
+ *
+ * @return <code>true</code> if the request is multipart;
+ * <code>false</code> otherwise.
+ */
+ public static final boolean isMultipartContent(
+ HttpServletRequest request) {
+ if (!"post".equals(request.getMethod().toLowerCase(Locale.ENGLISH))) {
+ return false;
+ }
+ String contentType = request.getContentType();
+ if (contentType == null) {
+ return false;
+ }
+ if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
+ return true;
+ }
+ return false;
+ }
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs an uninitialised instance of this class. A factory must be
+ * configured, using <code>setFileItemFactory()</code>, before attempting
+ * to parse requests.
+ *
+ * @see FileUpload#FileUpload(FileItemFactory)
+ */
+ public ServletFileUpload() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of this class which uses the supplied factory to
+ * create <code>FileItem</code> instances.
+ *
+ * @see FileUpload#FileUpload()
+ * @param fileItemFactory The factory to use for creating file items.
+ */
+ public ServletFileUpload(FileItemFactory fileItemFactory) {
+ super(fileItemFactory);
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+ * compliant <code>multipart/form-data</code> stream.
+ *
+ * @param request The servlet request to be parsed.
+ *
+ * @return A list of <code>FileItem</code> instances parsed from the
+ * request, in the order that they were transmitted.
+ *
+ * @throws FileUploadException if there are problems reading/parsing
+ * the request or storing files.
+ */
+ public List<FileItem> parseRequest(HttpServletRequest request)
+ throws FileUploadException {
+ return parseRequest(new ServletRequestContext(request));
+ }
+
+
+ /**
+ * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+ * compliant <code>multipart/form-data</code> stream.
+ *
+ * @param request The servlet request to be parsed.
+ *
+ * @return An iterator to instances of <code>FileItemStream</code>
+ * parsed from the request, in the order that they were
+ * transmitted.
+ *
+ * @throws FileUploadException if there are problems reading/parsing
+ * the request or storing files.
+ * @throws IOException An I/O error occurred. This may be a network
+ * error while communicating with the client or a problem while
+ * storing the uploaded content.
+ */
+ public FileItemIterator getItemIterator(HttpServletRequest request)
+ throws FileUploadException, IOException {
+ return super.getItemIterator(new ServletRequestContext(request));
+ }
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.servlet;
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.util.http.fileupload.RequestContext;
+
+
+/**
+ * <p>Provides access to the request information needed for a request made to
+ * an HTTP servlet.</p>
+ *
+ * @author <a href="mailto:martinc@apache.org">Martin Cooper</a>
+ *
+ * @since FileUpload 1.1
+ *
+ * @version $Id: ServletRequestContext.java 981187 2010-08-01 09:28:02Z markt $
+ */
+public class ServletRequestContext implements RequestContext {
+
+ // ----------------------------------------------------- Instance Variables
+
+ /**
+ * The request for which the context is being provided.
+ */
+ private HttpServletRequest request;
+
+
+ // ----------------------------------------------------------- Constructors
+
+ /**
+ * Construct a context for this request.
+ *
+ * @param request The request to which this context applies.
+ */
+ public ServletRequestContext(HttpServletRequest request) {
+ this.request = request;
+ }
+
+
+ // --------------------------------------------------------- Public Methods
+
+ /**
+ * Retrieve the character encoding for the request.
+ *
+ * @return The character encoding for the request.
+ */
+ public String getCharacterEncoding() {
+ return request.getCharacterEncoding();
+ }
+
+ /**
+ * Retrieve the content type of the request.
+ *
+ * @return The content type of the request.
+ */
+ public String getContentType() {
+ return request.getContentType();
+ }
+
+ /**
+ * Retrieve the content length of the request.
+ *
+ * @return The content length of the request.
+ */
+ public int getContentLength() {
+ return request.getContentLength();
+ }
+
+ /**
+ * Retrieve the input stream for the request.
+ *
+ * @return The input stream for the request.
+ *
+ * @throws IOException if a problem occurs.
+ */
+ public InputStream getInputStream() throws IOException {
+ return request.getInputStream();
+ }
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return a string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return "ContentLength="
+ + this.getContentLength()
+ + ", ContentType="
+ + this.getContentType();
+ }
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util;
+
+import java.io.IOException;
+
+
+/**
+ * Interface of an object, which may be closed.
+ */
+public interface Closeable {
+ /**
+ * Closes the object.
+ * @throws IOException An I/O error occurred.
+ */
+ void close() throws IOException;
+
+ /**
+ * Returns, whether the object is already closed.
+ * @return True, if the object is closed, otherwise false.
+ * @throws IOException An I/O error occurred.
+ */
+ boolean isClosed() throws IOException;
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.tomcat.util.http.fileupload.FileItemHeaders;
+
+
+/**
+ * Default implementation of the {@link FileItemHeaders} interface.
+ *
+ * @author Michael C. Macaluso
+ * @since 1.3
+ */
+public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
+ private static final long serialVersionUID = -4455695752627032559L;
+
+ /**
+ * Map of <code>String</code> keys to a <code>List</code> of
+ * <code>String</code> instances.
+ */
+ private final Map<String,List<String>> headerNameToValueListMap =
+ new HashMap<String,List<String>>();
+
+ /**
+ * List to preserve order of headers as added. This would not be
+ * needed if a <code>LinkedHashMap</code> could be used, but don't
+ * want to depend on 1.4.
+ */
+ private final List<String> headerNameList = new ArrayList<String>();
+
+ public String getHeader(String name) {
+ String nameLower = name.toLowerCase(Locale.ENGLISH);
+ List<String> headerValueList = headerNameToValueListMap.get(nameLower);
+ if (null == headerValueList) {
+ return null;
+ }
+ return headerValueList.get(0);
+ }
+
+ public Iterator<String> getHeaderNames() {
+ return headerNameList.iterator();
+ }
+
+ public Iterator<String> getHeaders(String name) {
+ String nameLower = name.toLowerCase(Locale.ENGLISH);
+ List<String> headerValueList = headerNameToValueListMap.get(nameLower);
+ if (null == headerValueList) {
+ return Collections.<String>emptyList().iterator();
+ }
+ return headerValueList.iterator();
+ }
+
+ /**
+ * Method to add header values to this instance.
+ *
+ * @param name name of this header
+ * @param value value of this header
+ */
+ public synchronized void addHeader(String name, String value) {
+ String nameLower = name.toLowerCase();
+ List<String> headerValueList = headerNameToValueListMap.get(nameLower);
+ if (null == headerValueList) {
+ headerValueList = new ArrayList<String>();
+ headerNameToValueListMap.put(nameLower, headerValueList);
+ headerNameList.add(nameLower);
+ }
+ headerValueList.add(value);
+ }
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+
+/**
+ * An input stream, which limits its data size. This stream is
+ * used, if the content length is unknown.
+ */
+public abstract class LimitedInputStream
+ extends FilterInputStream implements Closeable {
+ /**
+ * The maximum size of an item, in bytes.
+ */
+ private long sizeMax;
+ /**
+ * The current number of bytes.
+ */
+ private long count;
+ /**
+ * Whether this stream is already closed.
+ */
+ private boolean closed;
+
+ /**
+ * Creates a new instance.
+ * @param pIn The input stream, which shall be limited.
+ * @param pSizeMax The limit; no more than this number of bytes
+ * shall be returned by the source stream.
+ */
+ public LimitedInputStream(InputStream pIn, long pSizeMax) {
+ super(pIn);
+ sizeMax = pSizeMax;
+ }
+
+ /**
+ * Called to indicate, that the input streams limit has
+ * been exceeded.
+ * @param pSizeMax The input streams limit, in bytes.
+ * @param pCount The actual number of bytes.
+ * @throws IOException The called method is expected
+ * to raise an IOException.
+ */
+ protected abstract void raiseError(long pSizeMax, long pCount)
+ throws IOException;
+
+ /** Called to check, whether the input streams
+ * limit is reached.
+ * @throws IOException The given limit is exceeded.
+ */
+ private void checkLimit() throws IOException {
+ if (count > sizeMax) {
+ raiseError(sizeMax, count);
+ }
+ }
+
+ /**
+ * Reads the next byte of data from this input stream. The value
+ * byte is returned as an <code>int</code> in the range
+ * <code>0</code> to <code>255</code>. If no byte is available
+ * because the end of the stream has been reached, the value
+ * <code>-1</code> is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ * <p>
+ * This method
+ * simply performs <code>in.read()</code> and returns the result.
+ *
+ * @return the next byte of data, or <code>-1</code> if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ public int read() throws IOException {
+ int res = super.read();
+ if (res != -1) {
+ count++;
+ checkLimit();
+ }
+ return res;
+ }
+
+ /**
+ * Reads up to <code>len</code> bytes of data from this input stream
+ * into an array of bytes. If <code>len</code> is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ * <p>
+ * This method simply performs <code>in.read(b, off, len)</code>
+ * and returns the result.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off The start offset in the destination array
+ * <code>b</code>.
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * <code>-1</code> if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ int res = super.read(b, off, len);
+ if (res > 0) {
+ count += res;
+ checkLimit();
+ }
+ return res;
+ }
+
+ /**
+ * Returns, whether this stream is already closed.
+ * @return True, if the stream is closed, otherwise false.
+ * @throws IOException An I/O error occurred.
+ */
+ public boolean isClosed() throws IOException {
+ return closed;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * This
+ * method simply performs <code>in.close()</code>.
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+}
Added: trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
===================================================================
--- trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java (rev 0)
+++ trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java 2010-08-18 10:01:08 UTC (rev 1533)
@@ -0,0 +1,198 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomcat.util.http.fileupload.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.tomcat.util.http.fileupload.InvalidFileNameException;
+
+
+/** Utility class for working with streams.
+ */
+public final class Streams {
+ /**
+ * Private constructor, to prevent instantiation.
+ * This class has only static methods.
+ */
+ private Streams() {
+ // Does nothing
+ }
+
+ /**
+ * Default buffer size for use in
+ * {@link #copy(InputStream, OutputStream, boolean)}.
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * Copies the contents of the given {@link InputStream}
+ * to the given {@link OutputStream}. Shortcut for
+ * <pre>
+ * copy(pInputStream, pOutputStream, new byte[8192]);
+ * </pre>
+ * @param pInputStream The input stream, which is being read.
+ * It is guaranteed, that {@link InputStream#close()} is called
+ * on the stream.
+ * @param pOutputStream The output stream, to which data should
+ * be written. May be null, in which case the input streams
+ * contents are simply discarded.
+ * @param pClose True guarantees, that {@link OutputStream#close()}
+ * is called on the stream. False indicates, that only
+ * {@link OutputStream#flush()} should be called finally.
+ *
+ * @return Number of bytes, which have been copied.
+ * @throws IOException An I/O error occurred.
+ */
+ public static long copy(InputStream pInputStream,
+ OutputStream pOutputStream, boolean pClose)
+ throws IOException {
+ return copy(pInputStream, pOutputStream, pClose,
+ new byte[DEFAULT_BUFFER_SIZE]);
+ }
+
+ /**
+ * Copies the contents of the given {@link InputStream}
+ * to the given {@link OutputStream}.
+ * @param pIn The input stream, which is being read.
+ * It is guaranteed, that {@link InputStream#close()} is called
+ * on the stream.
+ * @param pOut The output stream, to which data should
+ * be written. May be null, in which case the input streams
+ * contents are simply discarded.
+ * @param pClose True guarantees, that {@link OutputStream#close()}
+ * is called on the stream. False indicates, that only
+ * {@link OutputStream#flush()} should be called finally.
+ * @param pBuffer Temporary buffer, which is to be used for
+ * copying data.
+ * @return Number of bytes, which have been copied.
+ * @throws IOException An I/O error occurred.
+ */
+ public static long copy(InputStream pIn,
+ OutputStream pOut, boolean pClose,
+ byte[] pBuffer)
+ throws IOException {
+ OutputStream out = pOut;
+ InputStream in = pIn;
+ try {
+ long total = 0;
+ for (;;) {
+ int res = in.read(pBuffer);
+ if (res == -1) {
+ break;
+ }
+ if (res > 0) {
+ total += res;
+ if (out != null) {
+ out.write(pBuffer, 0, res);
+ }
+ }
+ }
+ if (out != null) {
+ if (pClose) {
+ out.close();
+ } else {
+ out.flush();
+ }
+ out = null;
+ }
+ in.close();
+ in = null;
+ return total;
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (Throwable t) {
+ /* Ignore me */
+ }
+ }
+ if (pClose && out != null) {
+ try {
+ out.close();
+ } catch (Throwable t) {
+ /* Ignore me */
+ }
+ }
+ }
+ }
+
+ /**
+ * This convenience method allows to read a
+ * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s
+ * content into a string. The platform's default character encoding
+ * is used for converting bytes into characters.
+ * @param pStream The input stream to read.
+ * @see #asString(InputStream, String)
+ * @return The streams contents, as a string.
+ * @throws IOException An I/O error occurred.
+ */
+ public static String asString(InputStream pStream) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ copy(pStream, baos, true);
+ return baos.toString();
+ }
+
+ /**
+ * This convenience method allows to read a
+ * {@link org.apache.tomcat.util.http.fileupload.FileItemStream}'s
+ * content into a string, using the given character encoding.
+ * @param pStream The input stream to read.
+ * @param pEncoding The character encoding, typically "UTF-8".
+ * @see #asString(InputStream)
+ * @return The streams contents, as a string.
+ * @throws IOException An I/O error occurred.
+ */
+ public static String asString(InputStream pStream, String pEncoding)
+ throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ copy(pStream, baos, true);
+ return baos.toString(pEncoding);
+ }
+
+ /**
+ * Checks, whether the given file name is valid in the sense,
+ * that it doesn't contain any NUL characters. If the file name
+ * is valid, it will be returned without any modifications. Otherwise,
+ * an {@link InvalidFileNameException} is raised.
+ * @param pFileName The file name to check
+ * @return Unmodified file name, if valid.
+ * @throws InvalidFileNameException The file name was found to be invalid.
+ */
+ public static String checkFileName(String pFileName) {
+ if (pFileName != null && pFileName.indexOf('\u0000') != -1) {
+ // pFileName.replace("\u0000", "\\0")
+ final StringBuffer sb = new StringBuffer();
+ for (int i = 0; i < pFileName.length(); i++) {
+ char c = pFileName.charAt(i);
+ switch (c) {
+ case 0:
+ sb.append("\\0");
+ break;
+ default:
+ sb.append(c);
+ break;
+ }
+ }
+ throw new InvalidFileNameException(pFileName,
+ "Invalid file name: " + sb);
+ }
+ return pFileName;
+ }
+}
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2010-08-17 14:39:54 UTC (rev 1532)
+++ trunk/webapps/docs/changelog.xml 2010-08-18 10:01:08 UTC (rev 1533)
@@ -17,6 +17,13 @@
<body>
<section name="JBoss Web 3.0.0.Beta7 (remm)">
+ <subsection name="Genral">
+ <changelog>
+ <fix>
+ Use a more standard fileupload and update to 1.2. (markt)
+ </fix>
+ </changelog>
+ </subsection>
<subsection name="Catalina">
<changelog>
<fix>
14 years, 4 months
JBossWeb SVN: r1532 - tags.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2010-08-17 10:39:54 -0400 (Tue, 17 Aug 2010)
New Revision: 1532
Added:
tags/JBOSSWEB_2_1_10_GA/
Log:
- Web 2.1.10 GA.
Copied: tags/JBOSSWEB_2_1_10_GA (from rev 1531, branches/2.1.x)
14 years, 4 months
JBossWeb SVN: r1531 - branches/2.1.x/webapps/docs.
by jbossweb-commits@lists.jboss.org
Author: remy.maucherat(a)jboss.com
Date: 2010-08-17 10:36:15 -0400 (Tue, 17 Aug 2010)
New Revision: 1531
Modified:
branches/2.1.x/webapps/docs/changelog.xml
Log:
- Update changelog.
Modified: branches/2.1.x/webapps/docs/changelog.xml
===================================================================
--- branches/2.1.x/webapps/docs/changelog.xml 2010-08-17 02:14:12 UTC (rev 1530)
+++ branches/2.1.x/webapps/docs/changelog.xml 2010-08-17 14:36:15 UTC (rev 1531)
@@ -16,6 +16,21 @@
<body>
+<section name="JBoss Web 2.1.10.GA (remm)">
+ <subsection name="Coyote">
+ <changelog>
+ <fix>
+ <jboss-jira>JBPAPP-4753</jboss-jira>: Avoid possible shutdown crash with native,
+ caused by APR terminate. (jfclere)
+ </fix>
+ <fix>
+ <jboss-jira>JBPAPP-4779</jboss-jira>: Don't wait if no threads are immediately
+ available in the connector. (jfclere)
+ </fix>
+ </changelog>
+ </subsection>
+</section>
+
<section name="JBoss Web 2.1.9.GA (remm)">
<subsection name="Catalina">
<changelog>
14 years, 4 months
JBossWeb SVN: r1530 - branches/JBOSSWEB_2_0_0_GA_CP/src/share/classes/org/apache/catalina/session.
by jbossweb-commits@lists.jboss.org
Author: mmillson
Date: 2010-08-16 22:14:12 -0400 (Mon, 16 Aug 2010)
New Revision: 1530
Modified:
branches/JBOSSWEB_2_0_0_GA_CP/src/share/classes/org/apache/catalina/session/StandardSession.java
Log:
Fix session attribute NullPointerException for [JBPAPP-4890].
Modified: branches/JBOSSWEB_2_0_0_GA_CP/src/share/classes/org/apache/catalina/session/StandardSession.java
===================================================================
--- branches/JBOSSWEB_2_0_0_GA_CP/src/share/classes/org/apache/catalina/session/StandardSession.java 2010-08-17 01:53:25 UTC (rev 1529)
+++ branches/JBOSSWEB_2_0_0_GA_CP/src/share/classes/org/apache/catalina/session/StandardSession.java 2010-08-17 02:14:12 UTC (rev 1530)
@@ -1032,6 +1032,10 @@
throw new IllegalStateException
(sm.getString("standardSession.getAttribute.ise"));
+ if (name == null) {
+ return null;
+ }
+
return (attributes.get(name));
}
@@ -1634,6 +1638,9 @@
*/
protected void removeAttributeInternal(String name, boolean notify) {
+ // Avoid NPE
+ if (name == null) return;
+
// Remove this attribute from our collection
Object value = attributes.remove(name);
14 years, 4 months
JBossWeb SVN: r1529 - branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/src/share/classes/org/apache/catalina/session.
by jbossweb-commits@lists.jboss.org
Author: mmillson
Date: 2010-08-16 21:53:25 -0400 (Mon, 16 Aug 2010)
New Revision: 1529
Modified:
branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/src/share/classes/org/apache/catalina/session/StandardSession.java
Log:
Fix session attribute NullPointerException for [JBPAPP-4889].
Modified: branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/src/share/classes/org/apache/catalina/session/StandardSession.java
===================================================================
--- branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/src/share/classes/org/apache/catalina/session/StandardSession.java 2010-08-17 01:03:01 UTC (rev 1528)
+++ branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/src/share/classes/org/apache/catalina/session/StandardSession.java 2010-08-17 01:53:25 UTC (rev 1529)
@@ -1032,6 +1032,10 @@
throw new IllegalStateException
(sm.getString("standardSession.getAttribute.ise"));
+ if (name == null) {
+ return null;
+ }
+
return (attributes.get(name));
}
@@ -1634,6 +1638,9 @@
*/
protected void removeAttributeInternal(String name, boolean notify) {
+ // Avoid NPE
+ if (name == null) return;
+
// Remove this attribute from our collection
Object value = attributes.remove(name);
14 years, 4 months
JBossWeb SVN: r1528 - branches.
by jbossweb-commits@lists.jboss.org
Author: mmillson
Date: 2010-08-16 21:03:01 -0400 (Mon, 16 Aug 2010)
New Revision: 1528
Added:
branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889/
Log:
Create JBPAPP-4889 patch branch from JBOSSWEB_2_0_0_GA_CP11 tag
Copied: branches/JBOSSWEB_2_0_0_GA_CP11_JBPAPP-4889 (from rev 1527, tags/JBOSSWEB_2_0_0_GA_CP11)
14 years, 4 months