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 [EMAIL PROTECTED] 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
+ * [EMAIL PROTECTED] 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
+ * [EMAIL PROTECTED] FileUploadException} in an [EMAIL PROTECTED]
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
- * [EMAIL PROTECTED] org.apache.commons.fileupload.disk.DiskFileItemTest}.
+ * [EMAIL PROTECTED] 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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]