Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 68561 invoked from network); 7 Aug 2006 20:55:19 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 7 Aug 2006 20:55:19 -0000 Received: (qmail 69179 invoked by uid 500); 7 Aug 2006 20:55:17 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 69112 invoked by uid 500); 7 Aug 2006 20:55:17 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 69101 invoked by uid 500); 7 Aug 2006 20:55:17 -0000 Received: (qmail 69097 invoked by uid 99); 7 Aug 2006 20:55:17 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 Aug 2006 13:55:17 -0700 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received-SPF: pass (asf.osuosl.org: local policy) Received: from [140.211.166.113] (HELO eris.apache.org) (140.211.166.113) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 07 Aug 2006 13:55:16 -0700 Received: by eris.apache.org (Postfix, from userid 65534) id 0A6521A981A; Mon, 7 Aug 2006 13:54:56 -0700 (PDT) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r429474 - in /jakarta/commons/proper/fileupload/trunk: src/java/org/apache/commons/fileupload/ src/java/org/apache/commons/fileupload/util/ src/test/org/apache/commons/fileupload/ xdocs/ Date: Mon, 07 Aug 2006 20:54:54 -0000 To: commons-cvs@jakarta.apache.org From: jochen@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20060807205456.0A6521A981A@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: jochen Date: Mon Aug 7 13:54:54 2006 New Revision: 429474 URL: http://svn.apache.org/viewvc?rev=429474&view=rev Log: It is now possible to limit a files actual size, as opposed to the request size. PR: FILEUPLOAD-88 Permitted-by: Andrey Aristarkhov, aristarkhov@bitechnology.ru Added: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/Closeable.java jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/LimitedInputStream.java Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/FileUploadTestCase.java jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/SizesTest.java jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java?rev=429474&r1=429473&r2=429474&view=diff ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java (original) +++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java Mon Aug 7 13:54:54 2006 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2005 The Apache Software Foundation + * Copyright 2001-2006 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,6 @@ */ package org.apache.commons.fileupload; -import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -27,8 +26,10 @@ import javax.servlet.http.HttpServletRequest; -import org.apache.commons.fileupload.servlet.ServletRequestContext; import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload.servlet.ServletRequestContext; +import org.apache.commons.fileupload.util.Closeable; +import org.apache.commons.fileupload.util.LimitedInputStream; /** @@ -150,11 +151,16 @@ /** - * The maximum size permitted for an uploaded file. A value of -1 indicates - * no maximum. + * The maximum size permitted for the complete request, as opposed to + * {@link #fileSizeMax}. A value of -1 indicates no maximum. */ private long sizeMax = -1; + /** + * The maximum size permitted for a single uploaded file, as opposed + * to {@link #sizeMax}. A value of -1 indicates no maximum. + */ + private long fileSizeMax = -1; /** * The content encoding to use when reading part headers. @@ -186,9 +192,11 @@ /** - * Returns the maximum allowed upload size. + * Returns the maximum allowed size of a complete request, as opposed + * to {@link #getFileSizeMax()}. * - * @return The maximum allowed size, in bytes. + * @return The maximum allowed size, in bytes. The default value of + * -1 indicates, that there is no limit. * * @see #setSizeMax(long) * @@ -199,9 +207,11 @@ /** - * Sets the maximum allowed upload size. If negative, there is no maximum. + * Sets the maximum allowed size of a complete request, as opposed + * to {@link #setFileSizeMax(long)}. * - * @param sizeMax The maximum allowed size, in bytes, or -1 for no maximum. + * @param sizeMax The maximum allowed size, in bytes. The default value of + * -1 indicates, that there is no limit. * * @see #getSizeMax() * @@ -210,6 +220,25 @@ this.sizeMax = sizeMax; } + /** + * Returns the maximum allowed size of a single uploaded file, + * as opposed to {@link #getSizeMax()}. + * + * @see #setFileSizeMax(long) + */ + public long getFileSizeMax() { + return fileSizeMax; + } + + /** + * Sets the maximum allowed size of a single uploaded file, + * as opposed to {@link #getSizeMax()}. + * + * @see #getFileSizeMax() + */ + public void setFileSizeMax(long fileSizeMax) { + this.fileSizeMax = fileSizeMax; + } /** * Retrieves the character encoding used when reading the headers of an @@ -520,7 +549,7 @@ private class FileItemStreamImpl implements FileItemStream { private final String contentType, fieldName, name; private final boolean formField; - private final MultipartStream.ItemInputStream stream; + private final InputStream stream; private boolean opened; FileItemStreamImpl(String pName, String pFieldName, @@ -529,7 +558,20 @@ fieldName = pFieldName; contentType = pContentType; formField = pFormField; - stream = multi.newInputStream(); + InputStream istream = multi.newInputStream(); + if (fileSizeMax != -1) { + istream = new LimitedInputStream(istream, fileSizeMax){ + protected void raiseError(long pSizeMax, long pCount) throws IOException { + FileUploadException e = new FileSizeLimitExceededException( + "The field " + fieldName + " exceeds its maximum permitted " + + " size of " + pSizeMax + " characters.", + pCount, pSizeMax); + throw new FileUploadIOException(e); + + } + }; + } + stream = istream; } public String getContentType() { @@ -552,7 +594,7 @@ if (opened) { throw new IllegalStateException("The stream was already opened."); } - if (stream.isClosed()) { + if (((Closeable) stream).isClosed()) { throw new FileItemStream.ItemSkippedException(); } return stream; @@ -594,7 +636,15 @@ if (sizeMax >= 0) { int requestSize = ctx.getContentLength(); if (requestSize == -1) { - input = new LimitedInputStream(input, sizeMax); + input = new LimitedInputStream(input, sizeMax){ + protected void raiseError(long pSizeMax, long pCount) throws IOException { + FileUploadException ex = new SizeLimitExceededException( + "the request was rejected because its size (" + pCount + + ") exceeds the configured maximum (" + pSizeMax + ")", + pCount, pSizeMax); + throw new FileUploadIOException(ex); + } + }; } else { if (sizeMax >= 0 && requestSize > sizeMax) { throw new SizeLimitExceededException( @@ -709,48 +759,6 @@ } /** - * An input stream, which limits its data size. This stream is - * used, if the content length is unknown. - */ - private static class LimitedInputStream extends FilterInputStream { - private long sizeMax; - private long count; - - private void checkLimit() throws IOException { - if (count > sizeMax) { - FileUploadException ex = new SizeLimitExceededException( - "the request was rejected because its size (" + count - + ") exceeds the configured maximum (" + sizeMax + ")", - count, sizeMax); - throw new FileUploadIOException(ex); - } - } - - public int read() throws IOException { - int res = super.read(); - if (res != -1) { - count++; - checkLimit(); - } - return res; - } - - 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; - } - - LimitedInputStream(InputStream pIn, long pSizeMax) { - super(pIn); - sizeMax = pSizeMax; - } - } - - /** * This exception is thrown for hiding an inner * {@link FileUploadException} in an {@link IOException}. */ @@ -818,40 +826,48 @@ } } - /** - * Thrown to indicate that the request size exceeds the configured maximum. - */ - public static class SizeLimitExceededException - extends FileUploadException { - private static final long serialVersionUID = -2474893167098052828L; - + protected abstract static class SizeException extends FileUploadException { /** * The actual size of the request. */ - private long actual; + private final long actual; /** * The maximum permitted size of the request. */ - private long permitted; + private final long permitted; + + protected SizeException(String message, long actual, long permitted) { + super(message); + this.actual = actual; + this.permitted = permitted; + } /** - * Constructs a SizeExceededException with no - * detail message. + * Retrieves the actual size of the request. + * + * @return The actual size of the request. */ - public SizeLimitExceededException() { - super(); + public long getActualSize() { + return actual; } /** - * Constructs a SizeExceededException with - * the specified detail message. + * Retrieves the permitted size of the request. * - * @param message The detail message. + * @return The permitted size of the request. */ - public SizeLimitExceededException(String message) { - super(message); + public long getPermittedSize() { + return permitted; } + } + + /** + * Thrown to indicate that the request size exceeds the configured maximum. + */ + public static class SizeLimitExceededException + extends SizeException { + private static final long serialVersionUID = -2474893167098052828L; /** * Constructs a SizeExceededException with @@ -863,27 +879,28 @@ */ public SizeLimitExceededException(String message, long actual, long permitted) { - super(message); - this.actual = actual; - this.permitted = permitted; + super(message, actual, permitted); } + } - /** - * Retrieves the actual size of the request. - * - * @return The actual size of the request. - */ - public long getActualSize() { - return actual; - } + /** + * Thrown to indicate that A files size exceeds the configured maximum. + */ + public static class FileSizeLimitExceededException + extends SizeException { + private static final long serialVersionUID = 8150776562029630058L; - /** - * Retrieves the permitted size of the request. + /** + * Constructs a SizeExceededException with + * the specified detail message, and actual and permitted sizes. * - * @return The permitted size of the request. + * @param message The detail message. + * @param actual The actual request size. + * @param permitted The maximum permitted request size. */ - public long getPermittedSize() { - return permitted; + public FileSizeLimitExceededException(String message, long actual, + long permitted) { + super(message, actual, permitted); } } Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java?rev=429474&r1=429473&r2=429474&view=diff ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java (original) +++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java Mon Aug 7 13:54:54 2006 @@ -21,6 +21,8 @@ import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import org.apache.commons.fileupload.util.Closeable; + /** *

Low level API for processing file uploads. * @@ -704,7 +706,7 @@ /** * An {@link InputStream} for reading an items contents. */ - public class ItemInputStream extends InputStream { + public class ItemInputStream extends InputStream implements Closeable { private long total; private int pad, pos; private boolean closed; @@ -734,9 +736,8 @@ public int available() throws IOException { if (pos == -1) { return tail - head - pad; - } else { - return pos - head; } + return pos - head; } public int read() throws IOException { Added: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/Closeable.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/Closeable.java?rev=429474&view=auto ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/Closeable.java (added) +++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/Closeable.java Mon Aug 7 13:54:54 2006 @@ -0,0 +1,34 @@ +/* + * Copyright 2006 The Apache Software Foundation + * + * Licensed 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.commons.fileupload.util; + +import java.io.IOException; + + +/** + * Interface of an object, which may be closed. + */ +public interface Closeable { + /** + * Closes the object. + */ + public void close() throws IOException; + + /** + * Returns, whether the object is already closed. + */ + public boolean isClosed() throws IOException; +} Added: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/LimitedInputStream.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/LimitedInputStream.java?rev=429474&view=auto ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/LimitedInputStream.java (added) +++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/util/LimitedInputStream.java Mon Aug 7 13:54:54 2006 @@ -0,0 +1,78 @@ +/* + * Copyright 2006 The Apache Software Foundation + * + * Licensed 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.commons.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 { + private long sizeMax; + private long count; + 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; + } + + protected abstract void raiseError(long pSizeMax, long pCount) throws IOException; + + private void checkLimit() throws IOException { + if (count > sizeMax) { + raiseError(sizeMax, count); + } + } + + public int read() throws IOException { + int res = super.read(); + if (res != -1) { + count++; + checkLimit(); + } + return res; + } + + 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; + } + + public boolean isClosed() throws IOException { + return closed; + } + + public void close() throws IOException { + closed = true; + super.close(); + } +} Modified: jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/FileUploadTestCase.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/FileUploadTestCase.java?rev=429474&r1=429473&r2=429474&view=diff ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/FileUploadTestCase.java (original) +++ jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/FileUploadTestCase.java Mon Aug 7 13:54:54 2006 @@ -15,9 +15,10 @@ * Base class for deriving test cases. */ public abstract class FileUploadTestCase extends TestCase { - protected List parseUpload(byte[] bytes) throws FileUploadException { - String contentType = "multipart/form-data; boundary=---1234"; - return parseUpload(bytes, contentType); + protected static final String CONTENT_TYPE = "multipart/form-data; boundary=---1234"; + + protected List parseUpload(byte[] bytes) throws FileUploadException { + return parseUpload(bytes, CONTENT_TYPE); } protected List parseUpload(byte[] bytes, String contentType) throws FileUploadException { @@ -32,6 +33,6 @@ throws UnsupportedEncodingException, FileUploadException { byte[] bytes = content.getBytes("US-ASCII"); - return parseUpload(bytes, "multipart/form-data; boundary=---1234"); + return parseUpload(bytes, CONTENT_TYPE); } } Modified: jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/SizesTest.java URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/SizesTest.java?rev=429474&r1=429473&r2=429474&view=diff ============================================================================== --- jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/SizesTest.java (original) +++ jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/SizesTest.java Mon Aug 7 13:54:54 2006 @@ -72,4 +72,45 @@ } assertTrue(!fileIter.hasNext()); } + + /** Checks, whether limiting the file size works. + */ + public void testFileSizeLimit() + throws IOException, FileUploadException + { + final String request = + "-----1234\r\n" + + "Content-Disposition: form-data; name=\"file\"; filename=\"foo.tab\"\r\n" + + "Content-Type: text/whatever\r\n" + + "\r\n" + + "This is the content of the file\n" + + "\r\n" + + "-----1234--\r\n"; + + ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory()); + upload.setFileSizeMax(-1); + HttpServletRequest req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + List fileItems = upload.parseRequest(req); + assertEquals(1, fileItems.size()); + FileItem item = (FileItem) fileItems.get(0); + assertEquals("This is the content of the file\n", new String(item.get())); + + upload = new ServletFileUpload(new DiskFileItemFactory()); + upload.setFileSizeMax(40); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + fileItems = upload.parseRequest(req); + assertEquals(1, fileItems.size()); + item = (FileItem) fileItems.get(0); + assertEquals("This is the content of the file\n", new String(item.get())); + + upload = new ServletFileUpload(new DiskFileItemFactory()); + upload.setFileSizeMax(30); + req = new MockHttpServletRequest(request.getBytes("US-ASCII"), CONTENT_TYPE); + try { + upload.parseRequest(req); + fail("Expected exception."); + } catch (FileUploadBase.FileSizeLimitExceededException e) { + assertEquals(30, e.getPermittedSize()); + } + } } Modified: jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml?rev=429474&r1=429473&r2=429474&view=diff ============================================================================== --- jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml (original) +++ jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml Mon Aug 7 13:54:54 2006 @@ -71,6 +71,11 @@ Added support for header continuation lines. + + It is now possible to limit the actual file size and not + the request size. + --------------------------------------------------------------------- To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org