Author: markt Date: Sun Aug 1 09:52:35 2010 New Revision: 981190 URL: http://svn.apache.org/viewvc?rev=981190&view=rev Log: Update to commons-fileupload 1.2.2
Added: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java - copied, changed from r981187, commons/proper/fileupload/tags/commons-fileupload-1.2.2/src/java/org/apache/commons/fileupload/InvalidFileNameException.java Modified: tomcat/trunk/java/org/apache/catalina/connector/Request.java tomcat/trunk/java/org/apache/catalina/core/ApplicationPart.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/connector/Request.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Request.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/connector/Request.java (original) +++ tomcat/trunk/java/org/apache/catalina/connector/Request.java Sun Aug 1 09:52:35 2010 @@ -82,12 +82,12 @@ import org.apache.tomcat.util.http.Cooki 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.FileUploadBase; import org.apache.tomcat.util.http.fileupload.FileUploadException; -import org.apache.tomcat.util.http.fileupload.ServletFileUpload; import org.apache.tomcat.util.http.fileupload.FileUploadBase.InvalidContentTypeException; +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; import org.apache.tomcat.util.res.StringManager; Modified: tomcat/trunk/java/org/apache/catalina/core/ApplicationPart.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/ApplicationPart.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/core/ApplicationPart.java (original) +++ tomcat/trunk/java/org/apache/catalina/core/ApplicationPart.java Sun Aug 1 09:52:35 2010 @@ -31,9 +31,9 @@ import java.util.Map; import javax.servlet.MultipartConfigElement; import javax.servlet.http.Part; -import org.apache.tomcat.util.http.fileupload.DiskFileItem; import org.apache.tomcat.util.http.fileupload.FileItem; import org.apache.tomcat.util.http.fileupload.ParameterParser; +import org.apache.tomcat.util.http.fileupload.disk.DiskFileItem; /** * Adaptor to allow {...@link FileItem} objects generated by the package renamed Modified: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileItem.java Sun Aug 1 09:52:35 2010 @@ -85,6 +85,10 @@ public interface FileItem extends Serial * 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: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java Sun Aug 1 09:52:35 2010 @@ -20,6 +20,7 @@ import java.io.IOException; 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; @@ -297,19 +298,23 @@ public abstract class FileUploadBase { */ 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); @@ -324,13 +329,24 @@ public abstract class FileUploadBase { 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 + } + } + } } } @@ -547,7 +563,7 @@ public abstract class FileUploadBase { /** * Default implementation of {...@link FileItemStream}. */ - private class FileItemStreamImpl implements FileItemStream { + class FileItemStreamImpl implements FileItemStream { /** The file items content type. */ private final String contentType; @@ -591,13 +607,15 @@ public abstract class FileUploadBase { 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) { @@ -605,14 +623,16 @@ public abstract class FileUploadBase { 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); - throw new FileUploadIOException(e); + e.setFieldName(fieldName); + e.setFileName(name); + throw new FileUploadIOException(e); } }; } @@ -638,9 +658,13 @@ public abstract class FileUploadBase { /** * 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); } /** @@ -1024,7 +1048,7 @@ public abstract class FileUploadBase { */ 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. @@ -1100,6 +1124,16 @@ public abstract class FileUploadBase { 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. * @@ -1111,6 +1145,40 @@ public abstract class FileUploadBase { 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; + } } /** Copied: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java (from r981187, commons/proper/fileupload/tags/commons-fileupload-1.2.2/src/java/org/apache/commons/fileupload/InvalidFileNameException.java) URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java?p2=tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java&p1=commons/proper/fileupload/tags/commons-fileupload-1.2.2/src/java/org/apache/commons/fileupload/InvalidFileNameException.java&r1=981187&r2=981190&rev=981190&view=diff ============================================================================== --- commons/proper/fileupload/tags/commons-fileupload-1.2.2/src/java/org/apache/commons/fileupload/InvalidFileNameException.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/InvalidFileNameException.java Sun Aug 1 09:52:35 2010 @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.commons.fileupload; +package org.apache.tomcat.util.http.fileupload; /** Modified: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java Sun Aug 1 09:52:35 2010 @@ -61,24 +61,22 @@ import org.apache.tomcat.util.http.fileu * <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.krzew...@e-point.pl">Rafal Krzewski</a> @@ -92,7 +90,7 @@ public class MultipartStream { * 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; @@ -128,6 +126,7 @@ public class MultipartStream { */ void noteItem() { ++items; + notifyListener(); } /** Called for notifying the listener. */ @@ -965,70 +964,4 @@ public class MultipartStream { 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: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java Sun Aug 1 09:52:35 2010 @@ -35,8 +35,10 @@ import org.apache.tomcat.util.http.fileu 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.util.Streams; /** @@ -52,9 +54,12 @@ import org.apache.tomcat.util.http.fileu * {...@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 + * <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} @@ -269,9 +274,13 @@ public class DiskFileItem * 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 fileName; + return Streams.checkFileName(fileName); } Modified: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java Sun Aug 1 09:52:35 2010 @@ -41,15 +41,18 @@ import org.apache.tomcat.util.http.fileu * </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 + * <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.) - * 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" + * 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:mart...@apache.org">Martin Cooper</a> @@ -206,20 +209,19 @@ public class DiskFileItemFactory impleme /** * 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. + * @return An instance of {...@link FileCleaningTracker}, or null + * (default), if temporary files aren't tracked. */ public FileCleaningTracker getFileCleaningTracker() { return fileCleaningTracker; } /** - * Returns the tracker, which is responsible for deleting temporary + * 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. May be null - * to disable tracking. + * which will from now on track the created files, or null + * (default), to disable tracking. */ public void setFileCleaningTracker(FileCleaningTracker pTracker) { fileCleaningTracker = pTracker; Modified: tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/http/fileupload/util/Streams.java Sun Aug 1 09:52:35 2010 @@ -21,6 +21,8 @@ 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. */ @@ -163,4 +165,34 @@ public final class Streams { 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: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=981190&r1=981189&r2=981190&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Sun Aug 1 09:52:35 2010 @@ -327,6 +327,12 @@ Updated to Ant 1.8.1. The build now requires a minimum of Ant 1.8.x. (markt) </update> + <update> + Update the re-packaged version of commons-fileupload from 1.2.1 to + 1.2.2. The layout of re-packaged version was also restored to the + original commons-fileupload layout to make merging of future updates + easier. (markt) + </update> </changelog> </subsection> </section> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org