commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From joc...@apache.org
Subject svn commit: r428141 - in /jakarta/commons/proper/fileupload/trunk: ./ .settings/ src/java/org/apache/commons/fileupload/ src/java/org/apache/commons/fileupload/portlet/ src/java/org/apache/commons/fileupload/servlet/ src/test/org/apache/commons/fileupl...
Date Wed, 02 Aug 2006 20:49:48 GMT
Author: jochen
Date: Wed Aug  2 13:49:46 2006
New Revision: 428141

URL: http://svn.apache.org/viewvc?rev=428141&view=rev
Log:
Merged in the streaming branch.

Added:
    jakarta/commons/proper/fileupload/trunk/.settings/
      - copied from r420345, jakarta/commons/proper/fileupload/branches/streaming/.settings/
    jakarta/commons/proper/fileupload/trunk/.settings/org.eclipse.jdt.core.prefs
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/.settings/org.eclipse.jdt.core.prefs
    jakarta/commons/proper/fileupload/trunk/.settings/org.eclipse.jdt.ui.prefs
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/.settings/org.eclipse.jdt.ui.prefs
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileItemIterator.java
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/src/java/org/apache/commons/fileupload/FileItemIterator.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileItemStream.java
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/src/java/org/apache/commons/fileupload/FileItemStream.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/StreamUtil.java
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/src/java/org/apache/commons/fileupload/StreamUtil.java
    jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/StreamingTest.java
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/src/test/org/apache/commons/fileupload/StreamingTest.java
    jakarta/commons/proper/fileupload/trunk/xdocs/streaming.xml
      - copied unchanged from r420345, jakarta/commons/proper/fileupload/branches/streaming/xdocs/streaming.xml
Modified:
    jakarta/commons/proper/fileupload/trunk/.project
    jakarta/commons/proper/fileupload/trunk/maven.xml
    jakarta/commons/proper/fileupload/trunk/project.properties
    jakarta/commons/proper/fileupload/trunk/project.xml
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUpload.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadBase.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/MultipartStream.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java
    jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java
    jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/DiskFileItemSerializeTest.java
    jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
    jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/TestAll.java
    jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml
    jakarta/commons/proper/fileupload/trunk/xdocs/index.xml
    jakarta/commons/proper/fileupload/trunk/xdocs/navigation.xml
    jakarta/commons/proper/fileupload/trunk/xdocs/using.xml

Modified: jakarta/commons/proper/fileupload/trunk/.project
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/.project?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/.project (original)
+++ jakarta/commons/proper/fileupload/trunk/.project Wed Aug  2 13:49:46 2006
@@ -15,4 +15,4 @@
   <natures>
     <nature>org.eclipse.jdt.core.javanature</nature>
   </natures>
-</projectDescription>
\ No newline at end of file
+</projectDescription>

Modified: jakarta/commons/proper/fileupload/trunk/maven.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/maven.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/maven.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/maven.xml Wed Aug  2 13:49:46 2006
@@ -14,7 +14,7 @@
    limitations under the License.
 -->
 
-<project default="java:jar"
+<project default="jar:jar"
   xmlns:ant="jelly:ant">
 
   <!-- ================================================================== -->

Modified: jakarta/commons/proper/fileupload/trunk/project.properties
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/project.properties?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/project.properties (original)
+++ jakarta/commons/proper/fileupload/trunk/project.properties Wed Aug  2 13:49:46 2006
@@ -44,7 +44,7 @@
 
 maven.changelog.type=date
 #maven.changelog.date=lastRelease
-maven.changelog.date=2005-12-24
+maven.changelog.date=2006-06-08
 
 # documentation properties
 maven.xdoc.date=left

Modified: jakarta/commons/proper/fileupload/trunk/project.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/project.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/project.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/project.xml Wed Aug  2 13:49:46 2006
@@ -21,7 +21,7 @@
   <name>FileUpload</name>
   <groupId>commons-fileupload</groupId>
   <artifactId>commons-fileupload</artifactId>
-  <currentVersion>1.1.1</currentVersion>
+  <currentVersion>1.2-SNAPSHOT</currentVersion>
   <inceptionYear>2002</inceptionYear>
   <shortDescription>File upload component for Java servlets</shortDescription>
   <description>

Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUpload.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUpload.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUpload.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUpload.java
Wed Aug  2 13:49:46 2006
@@ -15,6 +15,8 @@
  */
 package org.apache.commons.fileupload;
 
+import javax.servlet.http.HttpServletRequest;
+
 /**
  * <p>High level API for processing file uploads.</p>
  *

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=428141&r1=428140&r2=428141&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
Wed Aug  2 13:49:46 2006
@@ -15,14 +15,16 @@
  */
 package org.apache.commons.fileupload;
 
+import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.NoSuchElementException;
+
 import javax.servlet.http.HttpServletRequest;
 
 import org.apache.commons.fileupload.servlet.ServletRequestContext;
@@ -274,6 +276,24 @@
      *
      * @param ctx The context for the 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.
+     */
+    public FileItemIterator getItemIterator(RequestContext ctx)
+            throws FileUploadException {
+        return new FileItemIteratorImpl(ctx);
+    }
+
+    /**
+     * Processes an <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC 1867</a>
+     * compliant <code>multipart/form-data</code> stream.
+     *
+     * @param ctx The context for the request to be parsed.
+     *
      * @return A list of <code>FileItem</code> instances parsed from the
      *         request, in the order that they were transmitted.
      *
@@ -282,110 +302,27 @@
      */
     public List /* FileItem */ parseRequest(RequestContext ctx)
             throws FileUploadException {
-        if (ctx == null) {
-            throw new NullPointerException("ctx parameter");
-        }
-
-        ArrayList items = new ArrayList();
-        String contentType = ctx.getContentType();
-
-        if ((null == contentType)
-            || (!contentType.toLowerCase().startsWith(MULTIPART))) {
-            throw new InvalidContentTypeException(
-                "the request doesn't contain a "
-                + MULTIPART_FORM_DATA
-                + " or "
-                + MULTIPART_MIXED
-                + " stream, content type header is "
-                + contentType);
-        }
-        int requestSize = ctx.getContentLength();
-
-        if (requestSize == -1) {
-            throw new UnknownSizeException(
-                "the request was rejected because its size is unknown");
-        }
-
-        if (sizeMax >= 0 && requestSize > sizeMax) {
-            throw new SizeLimitExceededException(
-                "the request was rejected because its size (" + requestSize
-                + ") exceeds the configured maximum (" + sizeMax + ")",
-                requestSize, sizeMax);
-        }
-
-        String charEncoding = headerEncoding;
-        if (charEncoding == null) {
-            charEncoding = ctx.getCharacterEncoding();
-        }
-
-        try {
-            byte[] boundary = getBoundary(contentType);
-            if (boundary == null) {
-                throw new FileUploadException(
-                        "the request was rejected because "
-                        + "no multipart boundary was found");
-            }
-
-            InputStream input = ctx.getInputStream();
-
-            MultipartStream multi = new MultipartStream(input, boundary);
-            multi.setHeaderEncoding(charEncoding);
-
-            boolean nextPart = multi.skipPreamble();
-            while (nextPart) {
-                Map headers = parseHeaders(multi.readHeaders());
-                String fieldName = getFieldName(headers);
-                if (fieldName != null) {
-                    String subContentType = getHeader(headers, CONTENT_TYPE);
-                    if (subContentType != null && subContentType
-                        .toLowerCase().startsWith(MULTIPART_MIXED)) {
-                        // Multiple files.
-                        byte[] subBoundary = getBoundary(subContentType);
-                        multi.setBoundary(subBoundary);
-                        boolean nextSubPart = multi.skipPreamble();
-                        while (nextSubPart) {
-                            headers = parseHeaders(multi.readHeaders());
-                            if (getFileName(headers) != null) {
-                                FileItem item =
-                                        createItem(headers, false);
-                                OutputStream os = item.getOutputStream();
-                                try {
-                                    multi.readBodyData(os);
-                                } finally {
-                                    os.close();
-                                }
-                                items.add(item);
-                            } else {
-                                // Ignore anything but files inside
-                                // multipart/mixed.
-                                multi.discardBodyData();
-                            }
-                            nextSubPart = multi.readBoundary();
-                        }
-                        multi.setBoundary(boundary);
-                    } else {
-                        FileItem item = createItem(headers,
-                                getFileName(headers) == null);
-                        OutputStream os = item.getOutputStream();
-                        try {
-                            multi.readBodyData(os);
-                        } finally {
-                            os.close();
-                        }
-                        items.add(item);
-                    }
-                } else {
-                    // Skip this part.
-                    multi.discardBodyData();
-                }
-                nextPart = multi.readBoundary();
+        FileItemIterator iter = getItemIterator(ctx);
+        List items = new ArrayList();
+        FileItemFactory fac = getFileItemFactory();
+        final byte[] buffer = new byte[8192];
+        while (iter.hasNext()) {
+            FileItemStream item = iter.next();
+            FileItem fileItem = fac.createItem(item.getFieldName(),
+                    item.getContentType(), item.isFormField(),
+                    item.getName());
+            try {
+                StreamUtil.copy(item.openStream(), fileItem.getOutputStream(),
+                            true, buffer);
+            } catch (FileUploadIOException e) {
+                throw (FileUploadException) e.getCause();
+            } catch (IOException e) {
+                throw new IOFileUploadException(
+                    "Processing of " + MULTIPART_FORM_DATA
+                        + " request failed. " + e.getMessage(), e);
             }
-        } catch (IOException e) {
-            throw new FileUploadException(
-                "Processing of " + MULTIPART_FORM_DATA
-                    + " request failed. " + e.getMessage());
+            items.add(fileItem);
         }
-
         return items;
     }
 
@@ -483,28 +420,6 @@
 
 
     /**
-     * Creates a new {@link FileItem} instance.
-     *
-     * @param headers       A <code>Map</code> containing the HTTP request
-     *                      headers.
-     * @param isFormField   Whether or not this item is a form field, as
-     *                      opposed to a file.
-     *
-     * @return A newly created <code>FileItem</code> instance.
-     *
-     * @throws FileUploadException if an error occurs.
-     */
-    protected FileItem createItem(Map /* String, String */ headers,
-                                  boolean isFormField)
-        throws FileUploadException {
-        return getFileItemFactory().createItem(getFieldName(headers),
-                getHeader(headers, CONTENT_TYPE),
-                isFormField,
-                getFileName(headers));
-    }
-
-
-    /**
      * <p> Parses the <code>header-part</code> and returns as key/value
      * pairs.
      *
@@ -578,62 +493,332 @@
         return (String) headers.get(name.toLowerCase());
     }
 
+    /**
+     * The iterator, which is returned by
+     * {@link FileUploadBase#getItemIterator(RequestContext)}.
+     */
+    private class FileItemIteratorImpl implements FileItemIterator {
+        private class FileItemStreamImpl implements FileItemStream {
+            private final String contentType, fieldName, name;
+            private final boolean formField;
+            private final MultipartStream.ItemInputStream stream;
+            private boolean opened;
+
+            FileItemStreamImpl(String pName, String pFieldName,
+                    String pContentType, boolean pFormField) {
+                name = pName;
+                fieldName = pFieldName;
+                contentType = pContentType;
+                formField = pFormField;
+                stream = multi.newInputStream();
+            }
+
+            public String getContentType() {
+                return contentType;
+            }
+
+            public String getFieldName() {
+                return fieldName;
+            }
+
+            public String getName() {
+                return name;
+            }
+
+            public boolean isFormField() {
+                return formField;
+            }
+
+            public InputStream openStream() throws IOException {
+                if (opened) {
+                    throw new IllegalStateException("The stream was already opened.");
+                }
+                if (stream.isClosed()) {
+                    throw new FileItemStream.ItemSkippedException();
+                }
+                return stream;
+            }
+
+            void close() throws IOException {
+                stream.close();
+            }
+        }
+
+        private final MultipartStream multi;
+        private final byte[] boundary;
+        private FileItemStreamImpl currentItem;
+        private String currentFieldName;
+        private boolean skipPreamble;
+        private boolean itemValid;
+        private boolean eof;
+
+        FileItemIteratorImpl(RequestContext ctx) throws FileUploadException {
+            if (ctx == null) {
+                throw new NullPointerException("ctx parameter");
+            }
+
+            String contentType = ctx.getContentType();
+            if ((null == contentType)
+                || (!contentType.toLowerCase().startsWith(MULTIPART))) {
+                throw new InvalidContentTypeException(
+                    "the request doesn't contain a "
+                    + MULTIPART_FORM_DATA
+                    + " or "
+                    + MULTIPART_MIXED
+                    + " stream, content type header is "
+                    + contentType);
+            }
+
+            try {
+                InputStream input = ctx.getInputStream();
+
+                if (sizeMax >= 0) {
+                    int requestSize = ctx.getContentLength();
+                    if (requestSize == -1) {
+                        input = new LimitedInputStream(input, sizeMax);
+                    } else {
+                        if (sizeMax >= 0 && requestSize > sizeMax) {
+                            throw new SizeLimitExceededException(
+                                    "the request was rejected because its size (" + requestSize
+                                    + ") exceeds the configured maximum (" + sizeMax + ")",
+                                    requestSize, sizeMax);
+                        }
+                    }
+                }
+
+                String charEncoding = headerEncoding;
+                if (charEncoding == null) {
+                    charEncoding = ctx.getCharacterEncoding();
+                }
+
+                boundary = getBoundary(contentType);
+                if (boundary == null) {
+                    throw new FileUploadException(
+                            "the request was rejected because "
+                            + "no multipart boundary was found");
+                }
+
+                multi = new MultipartStream(input, boundary);
+                multi.setHeaderEncoding(charEncoding);
+
+                skipPreamble = true;
+                findNextItem();
+            } catch (FileUploadIOException e) {
+                throw (FileUploadException) e.getCause();
+            } catch (IOException e) {
+                throw new FileUploadException(
+                    "Processing of " + MULTIPART_FORM_DATA
+                        + " request failed. " + e.getMessage());
+            }
+        }
+
+        private boolean findNextItem() throws IOException {
+            if (eof) {
+                return false;
+            }
+            if (currentItem != null) {
+                currentItem.close();
+                currentItem = null;
+            }
+            for (;;) {
+                boolean nextPart;
+                if (skipPreamble) {
+                    nextPart = multi.skipPreamble();
+                } else {
+                    nextPart = multi.readBoundary();
+                }
+                if (!nextPart) {
+                    if (currentFieldName == null) {
+                        // Outer multipart terminated -> No more data
+                        eof = true;
+                        return false;
+                    }
+                    // Inner multipart terminated -> Return to parsing the outer
+                    multi.setBoundary(boundary);
+                    currentFieldName = null;
+                    continue;
+                }
+                Map headers = parseHeaders(multi.readHeaders());
+                if (currentFieldName == null) {
+                    // We're parsing the outer multipart
+                    String fieldName = getFieldName(headers);
+                    if (fieldName != null) {
+                        String subContentType = getHeader(headers, CONTENT_TYPE);
+                        if (subContentType != null  &&
+                            subContentType.toLowerCase().startsWith(MULTIPART_MIXED)) {
+                            currentFieldName = fieldName;
+                            // Multiple files associated with this field name
+                            byte[] subBoundary = getBoundary(subContentType);
+                            multi.setBoundary(subBoundary);
+                            skipPreamble = true;
+                            continue;
+                        } else {
+                            String fileName = getFileName(headers);
+                            currentItem = new FileItemStreamImpl(fileName,
+                                    fieldName, getHeader(headers, CONTENT_TYPE),
+                                    fileName == null);
+                            itemValid = true;
+                            return true;
+                        }
+                    }
+                } else {
+                    String fileName = getFileName(headers);
+                    if (fileName != null) {
+                        currentItem = new FileItemStreamImpl(fileName,
+                                currentFieldName, getHeader(headers, CONTENT_TYPE),
+                                false);
+                        itemValid = true;
+                        return true;
+                    }
+                }
+                multi.discardBodyData();
+            }
+        }
+
+        public boolean hasNext() throws FileUploadException {
+            if (eof) {
+                return false;
+            }
+            if (itemValid) {
+                return true;
+            }
+            try {
+                return findNextItem();
+            } catch (FileUploadIOException e) {
+                throw (FileUploadException) e.getCause();
+            } catch (IOException e) {
+                throw new FileUploadException(
+                    "Processing of " + MULTIPART_FORM_DATA
+                        + " request failed. " + e.getMessage());
+            }
+        }
+
+        public FileItemStream next() throws FileUploadException {
+            if (eof  ||  (!itemValid && !hasNext())) {
+                throw new NoSuchElementException();
+            }
+            itemValid = false;
+            return currentItem;
+        }
+    }
 
     /**
-     * Thrown to indicate that the request is not a multipart request.
+     * An input stream, which limits its data size. This stream is
+     * used, if the content length is unknown.
      */
-    public static class InvalidContentTypeException
-        extends FileUploadException {
-        /**
-         * Constructs a <code>InvalidContentTypeException</code> with no
-         * detail message.
-         */
-        public InvalidContentTypeException() {
-            super();
+    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}.
+     */
+    public static class FileUploadIOException extends IOException {
+        private static final long serialVersionUID = -7047616958165584154L;
+        private final FileUploadException cause;
+
         /**
-         * Constructs an <code>InvalidContentTypeException</code> with
-         * the specified detail message.
-         *
-         * @param message The detail message.
+         * Creates a <code>FileUploadIOException</code> with the
+         * given cause.
          */
-        public InvalidContentTypeException(String message) {
-            super(message);
+        public FileUploadIOException(FileUploadException pCause) {
+            // We're not doing super(pCause) cause of 1.3 compatibility.
+            cause = pCause;
         }
-    }
 
+        public Throwable getCause() {
+            return cause;
+        }
+    }
 
     /**
-     * Thrown to indicate that the request size is not specified.
+     * Thrown to indicate that the request is not a multipart request.
      */
-    public static class UnknownSizeException
+    public static class InvalidContentTypeException
         extends FileUploadException {
+        private static final long serialVersionUID = -9073026332015646668L;
+
         /**
-         * Constructs a <code>UnknownSizeException</code> with no
+         * Constructs a <code>InvalidContentTypeException</code> with no
          * detail message.
          */
-        public UnknownSizeException() {
+        public InvalidContentTypeException() {
             super();
         }
 
         /**
-         * Constructs an <code>UnknownSizeException</code> with
+         * Constructs an <code>InvalidContentTypeException</code> with
          * the specified detail message.
          *
          * @param message The detail message.
          */
-        public UnknownSizeException(String message) {
+        public InvalidContentTypeException(String message) {
             super(message);
         }
     }
 
+    /**
+     * Thrown to indicate an IOException.
+     */
+    public static class IOFileUploadException extends FileUploadException {
+		private static final long serialVersionUID = 1749796615868477269L;
+		private final IOException cause;
+
+    	/**
+    	 * Creates a new instance with the given cause.
+    	 */
+    	public IOFileUploadException(String pMsg, IOException pException) {
+    		super(pMsg);
+    		cause = pException;
+    	}
+
+    	public Throwable getCause() {
+    		return cause;
+    	}
+    }
 
     /**
      * Thrown to indicate that the request size exceeds the configured maximum.
      */
     public static class SizeLimitExceededException
         extends FileUploadException {
+        private static final long serialVersionUID = -2474893167098052828L;
+
         /**
          * The actual size of the request.
          */

Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/FileUploadException.java
Wed Aug  2 13:49:46 2006
@@ -23,7 +23,7 @@
  */
 public class FileUploadException
     extends Exception {
-
+	
     /**
      * Constructs a new <code>FileUploadException</code> without message.
      */
@@ -39,4 +39,6 @@
     public FileUploadException(final String msg) {
         super(msg);
     }
+
+
 }

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=428141&r1=428140&r2=428141&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
Wed Aug  2 13:49:46 2006
@@ -496,24 +496,13 @@
     public int readBodyData(OutputStream output)
         throws MalformedStreamException,
                IOException {
-        final ItemInputStream istream = new ItemInputStream();
-        final byte[] bytes = new byte[8192];
-        for (;;) {
-            int res = istream.read(bytes);
-            if (res == -1) {
-                if (output != null) {
-                    output.flush();
-                }
-                return (int) istream.getBytesRead();
-            }
-            if (res > 0  &&  output != null) {
-                if (output != null) {
-                    output.write(bytes, 0, res);
-                }
-            }
-        }
+        final InputStream istream = newInputStream();
+        return (int) StreamUtil.copy(istream, output, false);
     }
 
+    ItemInputStream newInputStream() {
+        return new ItemInputStream();
+    }
 
     /**
      * <p> Reads <code>body-data</code> from the current
@@ -712,6 +701,7 @@
     public class ItemInputStream extends InputStream {
         private long total;
         private int pad, pos;
+        private boolean closed;
 
         ItemInputStream() {
             findSeparator();
@@ -744,6 +734,9 @@
         }
 
         public int read() throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
             if (available() == 0) {
                 if (makeAvailable() == 0) {
                     return -1;
@@ -755,6 +748,9 @@
         }
 
         public int read(byte[] b, int off, int len) throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
             if (len == 0) {
                 return 0;
             }
@@ -773,6 +769,9 @@
         }
 
         public void close() throws IOException {
+            if (closed) {
+                return;
+            }
             for (;;) {
                 int av = available();
                 if (av == 0) {
@@ -783,9 +782,13 @@
                 }
                 skip(av);
             }
+            closed = true;
         }
 
         public long skip(long bytes) throws IOException {
+            if (closed) {
+                throw new FileItemStream.ItemSkippedException();
+            }
             int av = available();
             if (av == 0) {
                 av = makeAvailable();
@@ -820,6 +823,12 @@
             tail = pad + bytesRead;
             findSeparator();
             return available();
+        }
+
+        /** Returns, whether the stream is closed.
+         */
+        public boolean isClosed() {
+            return closed;
         }
     }
 

Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/portlet/PortletFileUpload.java
Wed Aug  2 13:49:46 2006
@@ -16,8 +16,12 @@
 package org.apache.commons.fileupload.portlet;
 
 import java.util.List;
+
 import javax.portlet.ActionRequest;
+import javax.servlet.http.HttpServletRequest;
+
 import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.FileItemIterator;
 import org.apache.commons.fileupload.FileUpload;
 import org.apache.commons.fileupload.FileUploadBase;
 import org.apache.commons.fileupload.FileUploadException;
@@ -111,5 +115,22 @@
     public List /* FileItem */ parseRequest(ActionRequest request)
             throws FileUploadException {
         return parseRequest(new PortletRequestContext(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 portlet 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.
+     */
+    public FileItemIterator getItemIterator(ActionRequest request) throws FileUploadException
{
+        return super.getItemIterator(new PortletRequestContext(request));
     }
 }

Modified: jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/java/org/apache/commons/fileupload/servlet/ServletFileUpload.java
Wed Aug  2 13:49:46 2006
@@ -16,8 +16,11 @@
 package org.apache.commons.fileupload.servlet;
 
 import java.util.List;
+
 import javax.servlet.http.HttpServletRequest;
+
 import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.FileItemIterator;
 import org.apache.commons.fileupload.FileUpload;
 import org.apache.commons.fileupload.FileUploadException;
 
@@ -114,5 +117,23 @@
     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.
+     */
+    public FileItemIterator getItemIterator(HttpServletRequest request) throws FileUploadException
{
+        return super.getItemIterator(new ServletRequestContext(request));
     }
 }

Modified: jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/DiskFileItemSerializeTest.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/DiskFileItemSerializeTest.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/DiskFileItemSerializeTest.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/DiskFileItemSerializeTest.java
Wed Aug  2 13:49:46 2006
@@ -31,7 +31,7 @@
 
 /**
  * Serialization Unit tests for 
- *  {@link org.apache.commons.fileupload.disk.DiskFileItemTest}.
+ *  {@link org.apache.commons.fileupload.disk.DiskFileItem}.
  */
 public class DiskFileItemSerializeTest extends TestCase
  {

Modified: jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/MockHttpServletRequest.java
Wed Aug  2 13:49:46 2006
@@ -18,6 +18,7 @@
 import java.io.BufferedReader;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.security.Principal;
 import java.util.Enumeration;
@@ -41,15 +42,34 @@
 class MockHttpServletRequest implements HttpServletRequest
 {
 
-	private byte[] m_requestData;
+	private final InputStream m_requestData;
+	private final int length;
 	private String m_strContentType;
 	private Map m_headers = new java.util.HashMap();
 
+	/**
+	 * Creates a new instance with the given request data
+	 * and content type.
+	 */
 	public MockHttpServletRequest(
 			final byte[] requestData,
 			final String strContentType)
 	{
+		this(new ByteArrayInputStream(requestData),
+				requestData.length, strContentType);
+	}
+
+	/**
+	 * Creates a new instance with the given request data
+	 * and content type.
+	 */
+	public MockHttpServletRequest(
+			final InputStream requestData,
+			final int requestLength,
+			final String strContentType)
+	{
 		m_requestData = requestData;
+		length = requestLength;
 		m_strContentType = strContentType;
 		m_headers.put(FileUploadBase.CONTENT_TYPE, strContentType);
 	}
@@ -302,7 +322,7 @@
 		}
 		else
 		{
-			iLength = m_requestData.length;
+			iLength = length;
 		}
 		return iLength;
 	}
@@ -476,16 +496,20 @@
 	private static class MyServletInputStream
 		extends javax.servlet.ServletInputStream
 	{
-		private ByteArrayInputStream m_bais;
+		private final InputStream in;
 
-		public MyServletInputStream(byte[] data)
+		/**
+		 * Creates a new instance, which returns the given
+		 * streams data.
+		 */
+		public MyServletInputStream(InputStream pStream)
 		{
-			m_bais = new ByteArrayInputStream(data);
+			in = pStream;
 		}
 
-		public int read()
+		public int read() throws IOException
 		{
-			return m_bais.read();
+			return in.read();
 		}
 	}
 }

Modified: jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/TestAll.java
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/TestAll.java?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/TestAll.java
(original)
+++ jakarta/commons/proper/fileupload/trunk/src/test/org/apache/commons/fileupload/TestAll.java
Wed Aug  2 13:49:46 2006
@@ -23,20 +23,30 @@
  *
  */
 public class TestAll extends TestCase {
-
+	/**
+	 * Creates a new instance.
+	 */
     public TestAll(String testName) {
         super(testName);
     }
 
+    /**
+     * Runs the test suite (all other test cases).
+     */
     public static Test suite() {
         TestSuite suite = new TestSuite();
+        suite.addTest(new TestSuite(DefaultFileItemTest.class));
+        suite.addTest(new TestSuite(DiskFileItemSerializeTest.class));
         suite.addTest(new TestSuite(ParameterParserTest.class));
         suite.addTest(new TestSuite(MultipartStreamTest.class));
         suite.addTest(new TestSuite(ServletFileUploadTest.class));
-        suite.addTest(new TestSuite(DefaultFileItemTest.class));
+        suite.addTest(new TestSuite(StreamingTest.class));
         return suite;
     }
 
+    /**
+     * Command line interface, which invokes all tests.
+     */
     public static void main(String args[]) {
         String[] testCaseName = { TestAll.class.getName() };
         junit.textui.TestRunner.main(testCaseName);

Modified: jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/xdocs/changes.xml Wed Aug  2 13:49:46 2006
@@ -45,6 +45,12 @@
 	  <action dev="jochen" type="update" issue="FILEUPLOAD-109">
 	    Eliminated duplicate code.
 	  </action>
+	  <action dev="jochen" type="add" issue="FILEUPLOAD-112">
+	    Added a streaming API.
+	  </action>
+	  <action dev="jochen" type="fix" issue="FILEUPLOAD-93">
+	    Eliminated the necessity of a content-length header.
+	  </action>
 
 	</release>
 

Modified: jakarta/commons/proper/fileupload/trunk/xdocs/index.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/xdocs/index.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/xdocs/index.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/xdocs/index.xml Wed Aug  2 13:49:46 2006
@@ -45,6 +45,7 @@
         The following documentation is available:
         <ul>
           <li><a href="using.html">User Guide</a></li>
+          <li><a href="streaming.html">Streaming API</a></li>
           <li><a href="faq.html">Frequently Asked Questions</a></li>
           <li><a href="apidocs/index.html">JavaDoc API</a></li>
           <li><a href="maven-reports.html">Project Reports</a></li>

Modified: jakarta/commons/proper/fileupload/trunk/xdocs/navigation.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/xdocs/navigation.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/xdocs/navigation.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/xdocs/navigation.xml Wed Aug  2 13:49:46 2006
@@ -31,6 +31,7 @@
     <menu name="Commons FileUpload">
       <item name="Overview"                 href="/index.html"/>
       <item name="User guide"               href="/using.html"/>
+      <item name="Streaming API"            href="/streaming.html"/>
       <!--item name="Customization"            href="/customizing.html"/-->
       <item name="FAQ"                      href="/faq.html"/>
       <item name="Javadoc"                  href="apidocs/index.html"/>

Modified: jakarta/commons/proper/fileupload/trunk/xdocs/using.xml
URL: http://svn.apache.org/viewvc/jakarta/commons/proper/fileupload/trunk/xdocs/using.xml?rev=428141&r1=428140&r2=428141&view=diff
==============================================================================
--- jakarta/commons/proper/fileupload/trunk/xdocs/using.xml (original)
+++ jakarta/commons/proper/fileupload/trunk/xdocs/using.xml Wed Aug  2 13:49:46 2006
@@ -52,6 +52,12 @@
       regardless of its underlying implementation.
     </p>
     <p>
+      This page describes the traditional API of the commons fileupload
+      library. The traditional API is a convenient approach. However, for
+      ultimate performance, you might prefer the faster
+      <a href="streaming.html">Streaming API</a>.
+    </p>
+    <p>
       Each file item has a number of properties that might be of interest for
       your application. For example, every item has a name and a content type,
       and can provide an <code>InputStream</code> to access its data. On the



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message