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, [EMAIL PROTECTED]

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
+     * [EMAIL PROTECTED] #fileSizeMax}. A value of -1 indicates no maximum.
      */
     private long sizeMax = -1;
 
+    /**
+     * The maximum size permitted for a single uploaded file, as opposed
+     * to [EMAIL PROTECTED] #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 [EMAIL PROTECTED] #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 [EMAIL PROTECTED] #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 [EMAIL PROTECTED] #getSizeMax()}.
+     *
+     * @see #setFileSizeMax(long)
+     */
+    public long getFileSizeMax() {
+       return fileSizeMax;
+    }
+
+    /**
+     * Sets the maximum allowed size of a single uploaded file,
+     * as opposed to [EMAIL PROTECTED] #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 
      * [EMAIL PROTECTED] FileUploadException} in an [EMAIL PROTECTED] 
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 <code>SizeExceededException</code> 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 <code>SizeExceededException</code> 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 <code>SizeExceededException</code> 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 <code>SizeExceededException</code> 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;
+
 /**
  * <p> Low level API for processing file uploads.
  *
@@ -704,7 +706,7 @@
     /**
      * An [EMAIL PROTECTED] 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.
       </action>
 
+      <action dev="jochen" type="add" issue="FILEUPLOAD-88"
+          due-to="Andrey Aristarkhov" due-to-email="[EMAIL PROTECTED]">
+        It is now possible to limit the actual file size and not
+        the request size.
+      </action>
        </release>
 
     <release version="1.1.1" date="2006-06-08" description="Bugfix release">



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to