From: markt The default implementation of the
- * {@link org.apache.commons.fileupload.FileItem FileItem} interface.
- *
- * After retrieving an instance of this class from a {@link
- * org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} instance (see
- * {@link org.apache.commons.fileupload.DiskFileUpload
- * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may
- * either request all contents of file at once using {@link #get()} or
- * request an {@link java.io.InputStream InputStream} with
- * {@link #getInputStream()} and process the file without attempting to load
- * it into memory, which may come handy with large files.
- *
- * When using the
- * This implementation first attempts to rename the uploaded item to the
- * specified destination file, if the item was originally written to disk.
- * Otherwise, the data will be copied to the specified file.
- *
- * This method is only guaranteed to work once, the first time it
- * is invoked for a particular item. This is because, in the event that the
- * method renames a temporary file, that file will no longer be available
- * to copy or rename again at a later time.
- *
- * @param file The The default {@link org.apache.commons.fileupload.FileItemFactory}
- * implementation. This implementation creates
- * {@link org.apache.commons.fileupload.FileItem} instances which keep their
- * content either in memory, for smaller items, or in a temporary file on disk,
- * for larger items. The size threshold, above which content will be stored on
- * disk, is configurable, as is the directory in which temporary files will be
- * created. If not otherwise configured, the default configuration values are as
- * follows:
- * DiskFileItemFactory, then you should
- * consider the following: Temporary files are automatically deleted as
- * soon as they are no longer needed. (More precisely, when the
- * corresponding instance of {@link java.io.File} is garbage collected.)
- * This is done by the so-called reaper thread, which is started
- * automatically when the class {@link org.apache.commons.io.FileCleaner}
- * is loaded.
- * It might make sense to terminate that thread, for example, if
- * your web application ends. See the section on "Resource cleanup"
- * in the users guide of commons-fileupload.null if
- * not defined.
- */
- private String contentType;
-
-
- /**
- * Whether or not this item is a simple form field.
- */
- private boolean isFormField;
-
-
- /**
- * The original filename in the user's filesystem.
- */
- private String fileName;
-
-
- /**
- * The size of the item, in bytes. This is used to cache the size when a
- * file item is moved from its original location.
- */
- private long size = -1;
-
-
- /**
- * The threshold above which uploads will be stored on disk.
- */
- private int sizeThreshold;
-
-
- /**
- * The directory in which uploaded files will be stored, if stored on disk.
- */
- private File repository;
-
-
- /**
- * Cached contents of the file.
- */
- private byte[] cachedContent;
-
-
- /**
- * Output stream for this item.
- */
- private transient DeferredFileOutputStream dfos;
-
- /**
- * The temporary file to use.
- */
- private transient File tempFile;
-
- /**
- * File to allow for serialization of the content of this item.
- */
- private File dfosFile;
-
- /**
- * The file items headers.
- */
- private FileItemHeaders headers;
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Constructs a new DiskFileItem instance.
- *
- * @param fieldName The name of the form field.
- * @param contentType The content type passed by the browser or
- * null if not specified.
- * @param isFormField Whether or not this item is a plain form field, as
- * opposed to a file upload.
- * @param fileName The original filename in the user's filesystem, or
- * null if not specified.
- * @param sizeThreshold The threshold, in bytes, below which items will be
- * retained in memory and above which they will be
- * stored as a file.
- * @param repository The data repository, which is the directory in
- * which files will be created, should the item size
- * exceed the threshold.
- */
- public DiskFileItem(String fieldName,
- String contentType, boolean isFormField, String fileName,
- int sizeThreshold, File repository) {
- this.fieldName = fieldName;
- this.contentType = contentType;
- this.isFormField = isFormField;
- this.fileName = fileName;
- this.sizeThreshold = sizeThreshold;
- this.repository = repository;
- }
-
-
- // ------------------------------- Methods from javax.activation.DataSource
-
-
- /**
- * Returns an {@link java.io.InputStream InputStream} that can be
- * used to retrieve the contents of the file.
- *
- * @return An {@link java.io.InputStream InputStream} that can be
- * used to retrieve the contents of the file.
- *
- * @throws IOException if an error occurs.
- */
- public InputStream getInputStream()
- throws IOException {
- if (!isInMemory()) {
- return new FileInputStream(dfos.getFile());
- }
-
- if (cachedContent == null) {
- cachedContent = dfos.getData();
- }
- return new ByteArrayInputStream(cachedContent);
- }
-
-
- /**
- * Returns the content type passed by the agent or null if
- * not defined.
- *
- * @return The content type passed by the agent or null if
- * not defined.
- */
- public String getContentType() {
- return contentType;
- }
-
-
- /**
- * Returns the content charset passed by the agent or null if
- * not defined.
- *
- * @return The content charset passed by the agent or null if
- * not defined.
- */
- public String getCharSet() {
- ParameterParser parser = new ParameterParser();
- parser.setLowerCaseNames(true);
- // Parameter parser can handle null input
- Maptrue if the file contents will be read
- * from memory; false otherwise.
- */
- public boolean isInMemory() {
- if (cachedContent != null) {
- return true;
- }
- return dfos.isInMemory();
- }
-
-
- /**
- * Returns the size of the file.
- *
- * @return The size of the file, in bytes.
- */
- public long getSize() {
- if (size >= 0) {
- return size;
- } else if (cachedContent != null) {
- return cachedContent.length;
- } else if (dfos.isInMemory()) {
- return dfos.getData().length;
- } else {
- return dfos.getFile().length();
- }
- }
-
-
- /**
- * Returns the contents of the file as an array of bytes. If the
- * contents of the file were not yet cached in memory, they will be
- * loaded from the disk storage and cached.
- *
- * @return The contents of the file as an array of bytes.
- */
- public byte[] get() {
- if (isInMemory()) {
- if (cachedContent == null) {
- cachedContent = dfos.getData();
- }
- return cachedContent;
- }
-
- byte[] fileData = new byte[(int) getSize()];
- FileInputStream fis = null;
-
- try {
- fis = new FileInputStream(dfos.getFile());
- fis.read(fileData);
- } catch (IOException e) {
- fileData = null;
- } finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
-
- return fileData;
- }
-
-
- /**
- * Returns the contents of the file as a String, using the specified
- * encoding. This method uses {@link #get()} to retrieve the
- * contents of the file.
- *
- * @param charset The charset to use.
- *
- * @return The contents of the file, as a string.
- *
- * @throws UnsupportedEncodingException if the requested character
- * encoding is not available.
- */
- public String getString(final String charset)
- throws UnsupportedEncodingException {
- return new String(get(), charset);
- }
-
-
- /**
- * Returns the contents of the file as a String, using the default
- * character encoding. This method uses {@link #get()} to retrieve the
- * contents of the file.
- *
- * @return The contents of the file, as a string.
- *
- * @todo Consider making this method throw UnsupportedEncodingException.
- */
- public String getString() {
- byte[] rawdata = get();
- String charset = getCharSet();
- if (charset == null) {
- charset = DEFAULT_CHARSET;
- }
- try {
- return new String(rawdata, charset);
- } catch (UnsupportedEncodingException e) {
- return new String(rawdata);
- }
- }
-
-
- /**
- * A convenience method to write an uploaded item to disk. The client code
- * is not concerned with whether or not the item is stored in memory, or on
- * disk in a temporary location. They just want to write the uploaded item
- * to a file.
- * File into which the uploaded item should
- * be stored.
- *
- * @throws Exception if an error occurs.
- */
- public void write(File file) throws Exception {
- if (isInMemory()) {
- FileOutputStream fout = null;
- try {
- fout = new FileOutputStream(file);
- fout.write(get());
- } finally {
- if (fout != null) {
- fout.close();
- }
- }
- } else {
- File outputFile = getStoreLocation();
- if (outputFile != null) {
- // Save the length of the file
- size = outputFile.length();
- /*
- * The uploaded file is being stored on disk
- * in a temporary location so move it to the
- * desired file.
- */
- if (!outputFile.renameTo(file)) {
- BufferedInputStream in = null;
- BufferedOutputStream out = null;
- try {
- in = new BufferedInputStream(
- new FileInputStream(outputFile));
- out = new BufferedOutputStream(
- new FileOutputStream(file));
- IOUtils.copy(in, out);
- } finally {
- if (in != null) {
- try {
- in.close();
- } catch (IOException e) {
- // ignore
- }
- }
- if (out != null) {
- try {
- out.close();
- } catch (IOException e) {
- // ignore
- }
- }
- }
- }
- } else {
- /*
- * For whatever reason we cannot write the
- * file to disk.
- */
- throw new FileUploadException(
- "Cannot write uploaded file to disk!");
- }
- }
- }
-
-
- /**
- * Deletes the underlying storage for a file item, including deleting any
- * associated temporary disk file. Although this storage will be deleted
- * automatically when the FileItem instance is garbage
- * collected, this method can be used to ensure that this is done at an
- * earlier time, thus preserving system resources.
- */
- public void delete() {
- cachedContent = null;
- File outputFile = getStoreLocation();
- if (outputFile != null && outputFile.exists()) {
- outputFile.delete();
- }
- }
-
-
- /**
- * Returns the name of the field in the multipart form corresponding to
- * this file item.
- *
- * @return The name of the form field.
- *
- * @see #setFieldName(java.lang.String)
- *
- */
- public String getFieldName() {
- return fieldName;
- }
-
-
- /**
- * Sets the field name used to reference this file item.
- *
- * @param fieldName The name of the form field.
- *
- * @see #getFieldName()
- *
- */
- public void setFieldName(String fieldName) {
- this.fieldName = fieldName;
- }
-
-
- /**
- * Determines whether or not a FileItem instance represents
- * a simple form field.
- *
- * @return true if the instance represents a simple form
- * field; false if it represents an uploaded file.
- *
- * @see #setFormField(boolean)
- *
- */
- public boolean isFormField() {
- return isFormField;
- }
-
-
- /**
- * Specifies whether or not a FileItem instance represents
- * a simple form field.
- *
- * @param state true if the instance represents a simple form
- * field; false if it represents an uploaded file.
- *
- * @see #isFormField()
- *
- */
- public void setFormField(boolean state) {
- isFormField = state;
- }
-
-
- /**
- * Returns an {@link java.io.OutputStream OutputStream} that can
- * be used for storing the contents of the file.
- *
- * @return An {@link java.io.OutputStream OutputStream} that can be used
- * for storing the contensts of the file.
- *
- * @throws IOException if an error occurs.
- */
- public OutputStream getOutputStream()
- throws IOException {
- if (dfos == null) {
- File outputFile = getTempFile();
- dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
- }
- return dfos;
- }
-
-
- // --------------------------------------------------------- Public methods
-
-
- /**
- * Returns the {@link java.io.File} object for the FileItem's
- * data's temporary location on the disk. Note that for
- * FileItems that have their data stored in memory,
- * this method will return null. When handling large
- * files, you can use {@link java.io.File#renameTo(java.io.File)} to
- * move the file to new location without copying the data, if the
- * source and destination locations reside within the same logical
- * volume.
- *
- * @return The data file, or null if the data is stored in
- * memory.
- */
- public File getStoreLocation() {
- return dfos == null ? null : dfos.getFile();
- }
-
-
- // ------------------------------------------------------ Protected methods
-
-
- /**
- * Removes the file contents from the temporary storage.
- */
- @Override
- protected void finalize() {
- File outputFile = dfos.getFile();
-
- if (outputFile != null && outputFile.exists()) {
- outputFile.delete();
- }
- }
-
-
- /**
- * Creates and returns a {@link java.io.File File} representing a uniquely
- * named temporary file in the configured repository path. The lifetime of
- * the file is tied to the lifetime of the FileItem instance;
- * the file will be deleted when the instance is garbage collected.
- *
- * @return The {@link java.io.File File} to be used for temporary storage.
- */
- protected File getTempFile() {
- if (tempFile == null) {
- File tempDir = repository;
- if (tempDir == null) {
- tempDir = new File(System.getProperty("java.io.tmpdir"));
- }
-
- String tempFileName =
- "upload_" + UID + "_" + getUniqueId() + ".tmp";
-
- tempFile = new File(tempDir, tempFileName);
- }
- return tempFile;
- }
-
-
- // -------------------------------------------------------- Private methods
-
-
- /**
- * Returns an identifier that is unique within the class loader used to
- * load this class, but does not have random-like apearance.
- *
- * @return A String with the non-random looking instance identifier.
- */
- private static String getUniqueId() {
- final int limit = 100000000;
- int current;
- synchronized (DiskFileItem.class) {
- current = counter++;
- }
- String id = Integer.toString(current);
-
- // If you manage to get more than 100 million of ids, you'll
- // start getting ids longer than 8 characters.
- if (current < limit) {
- id = ("00000000" + id).substring(id.length());
- }
- return id;
- }
-
-
-
-
- /**
- * Returns a string representation of this object.
- *
- * @return a string representation of this object.
- */
- @Override
- public String toString() {
- return "name=" + this.getName()
- + ", StoreLocation="
- + String.valueOf(this.getStoreLocation())
- + ", size="
- + this.getSize()
- + "bytes, "
- + "isFormField=" + isFormField()
- + ", FieldName="
- + this.getFieldName();
- }
-
-
- // -------------------------------------------------- Serialization methods
-
-
- /**
- * Writes the state of this object during serialization.
- *
- * @param out The stream to which the state should be written.
- *
- * @throws IOException if an error occurs.
- */
- private void writeObject(ObjectOutputStream out) throws IOException {
- // Read the data
- if (dfos.isInMemory()) {
- cachedContent = get();
- } else {
- cachedContent = null;
- dfosFile = dfos.getFile();
- }
-
- // write out values
- out.defaultWriteObject();
- }
-
- /**
- * Reads the state of this object during deserialization.
- *
- * @param in The stream from which the state should be read.
- *
- * @throws IOException if an error occurs.
- * @throws ClassNotFoundException if class cannot be found.
- */
- private void readObject(ObjectInputStream in)
- throws IOException, ClassNotFoundException {
- // read values
- in.defaultReadObject();
-
- OutputStream output = getOutputStream();
- if (cachedContent != null) {
- output.write(cachedContent);
- } else {
- FileInputStream input = new FileInputStream(dfosFile);
- IOUtils.copy(input, output);
- dfosFile.delete();
- dfosFile = null;
- }
- output.close();
-
- cachedContent = null;
- }
-
- /**
- * Returns the file item headers.
- * @return The file items headers.
- */
- public FileItemHeaders getHeaders() {
- return headers;
- }
-
- /**
- * Sets the file item headers.
- * @param pHeaders The file items headers.
- */
- public void setHeaders(FileItemHeaders pHeaders) {
- headers = pHeaders;
- }
-}
diff --git a/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java b/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java
deleted file mode 100644
index 1dc8f2b45..000000000
--- a/java/org/apache/tomcat/util/http/fileupload/DiskFileItemFactory.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.tomcat.util.http.fileupload;
-
-import java.io.File;
-
-
-/**
- *
- *
- * System.getProperty("java.io.tmpdir").
When using the DiskFileItemFactory, then you should
- * consider the following: Temporary files are automatically deleted as
- * soon as they are no longer needed. (More precisely, when the
- * corresponding instance of {@link java.io.File} is garbage collected.)
- * Cleaning up those files is done by an instance of
- * {@link FileCleaningTracker}, and an associated thread. In a complex
- * environment, for example in a web application, you should consider
- * terminating this thread, for example, when your web application
- * ends. See the section on "Resource cleanup"
- * in the users guide of commons-fileupload.
The instance of {@link FileCleaningTracker}, which is responsible - * for deleting temporary files.
- *May be null, if tracking files is not required.
- */ - private FileCleaningTracker fileCleaningTracker; - - // ----------------------------------------------------------- Constructors - - - /** - * Constructs an unconfigured instance of this class. The resulting factory - * may be configured by calling the appropriate setter methods. - */ - public DiskFileItemFactory() { - this(DEFAULT_SIZE_THRESHOLD, null); - } - - - /** - * Constructs a preconfigured instance of this class. - * - * @param sizeThreshold The threshold, in bytes, below which items will be - * retained in memory and above which they will be - * stored as a file. - * @param repository The data repository, which is the directory in - * which files will be created, should the item size - * exceed the threshold. - */ - public DiskFileItemFactory(int sizeThreshold, File repository) { - this.sizeThreshold = sizeThreshold; - this.repository = repository; - } - - // ------------------------------------------------------------- Properties - - - /** - * Returns the directory used to temporarily store files that are larger - * than the configured size threshold. - * - * @return The directory in which temporary files will be located. - * - * @see #setRepository(java.io.File) - * - */ - public File getRepository() { - return repository; - } - - - /** - * Sets the directory used to temporarily store files that are larger - * than the configured size threshold. - * - * @param repository The directory in which temporary files will be located. - * - * @see #getRepository() - * - */ - public void setRepository(File repository) { - this.repository = repository; - } - - - /** - * Returns the size threshold beyond which files are written directly to - * disk. The default value is 10240 bytes. - * - * @return The size threshold, in bytes. - * - * @see #setSizeThreshold(int) - */ - public int getSizeThreshold() { - return sizeThreshold; - } - - - /** - * Sets the size threshold beyond which files are written directly to disk. - * - * @param sizeThreshold The size threshold, in bytes. - * - * @see #getSizeThreshold() - * - */ - public void setSizeThreshold(int sizeThreshold) { - this.sizeThreshold = sizeThreshold; - } - - - // --------------------------------------------------------- Public Methods - - /** - * Create a new {@link org.apache.commons.fileupload.disk.DiskFileItem} - * instance from the supplied parameters and the local factory - * configuration. - * - * @param fieldName The name of the form field. - * @param contentType The content type of the form field. - * @param isFormFieldtrue if this is a plain form field;
- * false otherwise.
- * @param fileName The name of the uploaded file, if any, as supplied
- * by the browser or other client.
- *
- * @return The newly created file item.
- */
- public FileItem createItem(String fieldName, String contentType,
- boolean isFormField, String fileName) {
- DiskFileItem result = new DiskFileItem(fieldName, contentType,
- isFormField, fileName, sizeThreshold, repository);
- FileCleaningTracker tracker = getFileCleaningTracker();
- if (tracker != null) {
- tracker.track(result.getTempFile(), this);
- }
- return result;
- }
-
-
- /**
- * Returns the tracker, which is responsible for deleting temporary
- * files.
- * @return An instance of {@link FileCleaningTracker}, defaults to
- * {@link org.apache.commons.io.FileCleaner#getInstance()}. Null,
- * if temporary files aren't tracked.
- */
- public FileCleaningTracker getFileCleaningTracker() {
- return fileCleaningTracker;
- }
-
- /**
- * Returns the tracker, which is responsible for deleting temporary
- * files.
- * @param pTracker An instance of {@link FileCleaningTracker},
- * which will from now on track the created files. May be null
- * to disable tracking.
- */
- public void setFileCleaningTracker(FileCleaningTracker pTracker) {
- fileCleaningTracker = pTracker;
- }
-}
diff --git a/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java b/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java
deleted file mode 100644
index efbdf8e9c..000000000
--- a/java/org/apache/tomcat/util/http/fileupload/FileItemHeadersImpl.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.tomcat.util.http.fileupload;
-
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-
-
-/**
- * Default implementation of the {@link FileItemHeaders} interface.
- *
- * @author Michael C. Macaluso
- * @since 1.3
- */
-public class FileItemHeadersImpl implements FileItemHeaders, Serializable {
- private static final long serialVersionUID = -4455695752627032559L;
-
- /**
- * Map of String keys to a List of
- * String instances.
- */
- private final MapLinkedHashMap could be used, but don't
- * want to depend on 1.4.
- */
- private final Listint in the range
- * 0 to 255. If no byte is available
- * because the end of the stream has been reached, the value
- * -1 is returned. This method blocks until input data
- * is available, the end of the stream is detected, or an exception
- * is thrown.
- *
- * This method
- * simply performs in.read() and returns the result.
- *
- * @return the next byte of data, or -1 if the end of the
- * stream is reached.
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- public int read() throws IOException {
- int res = super.read();
- if (res != -1) {
- count++;
- checkLimit();
- }
- return res;
- }
-
- /**
- * Reads up to len bytes of data from this input stream
- * into an array of bytes. If len is not zero, the method
- * blocks until some input is available; otherwise, no
- * bytes are read and 0 is returned.
- *
- * This method simply performs in.read(b, off, len)
- * and returns the result.
- *
- * @param b the buffer into which the data is read.
- * @param off The start offset in the destination array
- * b.
- * @param len the maximum number of bytes read.
- * @return the total number of bytes read into the buffer, or
- * -1 if there is no more data because the end of
- * the stream has been reached.
- * @exception NullPointerException If b is null.
- * @exception IndexOutOfBoundsException If off is negative,
- * len is negative, or len is greater than
- * b.length - off
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- 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;
- }
-
- /**
- * Returns, whether this stream is already closed.
- * @return True, if the stream is closed, otherwise false.
- * @throws IOException An I/O error occurred.
- */
- public boolean isClosed() throws IOException {
- return closed;
- }
-
- /**
- * Closes this input stream and releases any system resources
- * associated with the stream.
- * This
- * method simply performs in.close().
- *
- * @exception IOException if an I/O error occurs.
- * @see java.io.FilterInputStream#in
- */
- @Override
- public void close() throws IOException {
- closed = true;
- super.close();
- }
-}
diff --git a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
index 9c6477392..4a8873aba 100644
--- a/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
+++ b/java/org/apache/tomcat/util/http/fileupload/MultipartStream.java
@@ -22,6 +22,9 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
+import org.apache.tomcat.util.http.fileupload.util.Closeable;
+import org.apache.tomcat.util.http.fileupload.util.Streams;
+
/**
*
Low level API for processing file uploads. diff --git a/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java b/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java deleted file mode 100644 index 49a9885f9..000000000 --- a/java/org/apache/tomcat/util/http/fileupload/ServletFileUpload.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.tomcat.util.http.fileupload; - -import java.io.IOException; -import java.util.List; -import java.util.Locale; - -import javax.servlet.http.HttpServletRequest; - - -/** - *
High level API for processing file uploads.
- * - *This class handles multiple files per single HTML widget, sent using
- * multipart/mixed encoding type, as specified by
- * RFC 1867. Use {@link
- * #parseRequest(HttpServletRequest)} to acquire a list of {@link
- * org.apache.commons.fileupload.FileItem}s associated with a given HTML
- * widget.
How the data for individual parts is stored is determined by the factory - * used to create them; a given part may be in memory, on disk, or somewhere - * else.
- * - * @author Rafal Krzewski - * @author Daniel Rall - * @author Jason van Zyl - * @author John McNally - * @author Martin Cooper - * @author Sean C. Sullivan - * - * @version $Id$ - */ -public class ServletFileUpload extends FileUpload { - - // ---------------------------------------------------------- Class methods - - - /** - * Utility method that determines whether the request contains multipart - * content. - * - * @param request The servlet request to be evaluated. Must be non-null. - * - * @returntrue if the request is multipart;
- * false otherwise.
- */
- public static final boolean isMultipartContent(
- HttpServletRequest request) {
- if (!"post".equals(request.getMethod().toLowerCase(Locale.ENGLISH))) {
- return false;
- }
- String contentType = request.getContentType();
- if (contentType == null) {
- return false;
- }
- if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
- return true;
- }
- return false;
- }
-
-
- // ----------------------------------------------------------- Constructors
-
-
- /**
- * Constructs an uninitialised instance of this class. A factory must be
- * configured, using setFileItemFactory(), before attempting
- * to parse requests.
- *
- * @see FileUpload#FileUpload(FileItemFactory)
- */
- public ServletFileUpload() {
- super();
- }
-
-
- /**
- * Constructs an instance of this class which uses the supplied factory to
- * create FileItem instances.
- *
- * @see FileUpload#FileUpload()
- * @param fileItemFactory The factory to use for creating file items.
- */
- public ServletFileUpload(FileItemFactory fileItemFactory) {
- super(fileItemFactory);
- }
-
-
- // --------------------------------------------------------- Public methods
-
-
- /**
- * Processes an RFC 1867
- * compliant multipart/form-data stream.
- *
- * @param request The servlet request to be parsed.
- *
- * @return A list of FileItem instances 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 Listmultipart/form-data stream.
- *
- * @param request The servlet request to be parsed.
- *
- * @return An iterator to instances of FileItemStream
- * parsed from the request, in the order that they were
- * transmitted.
- *
- * @throws FileUploadException if there are problems reading/parsing
- * the request or storing files.
- * @throws IOException An I/O error occurred. This may be a network
- * error while communicating with the client or a problem while
- * storing the uploaded content.
- */
- public FileItemIterator getItemIterator(HttpServletRequest request)
- throws FileUploadException, IOException {
- return super.getItemIterator(new ServletRequestContext(request));
- }
-}
diff --git a/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java b/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java
deleted file mode 100644
index bb5460a1d..000000000
--- a/java/org/apache/tomcat/util/http/fileupload/ServletRequestContext.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.tomcat.util.http.fileupload;
-
-import java.io.InputStream;
-import java.io.IOException;
-import javax.servlet.http.HttpServletRequest;
-
-
-/**
- * Provides access to the request information needed for a request made to - * an HTTP servlet.
- * - * @author Martin Cooper - * - * @since FileUpload 1.1 - * - * @version $Id$ - */ -public class ServletRequestContext implements RequestContext { - - // ----------------------------------------------------- Instance Variables - - /** - * The request for which the context is being provided. - */ - private HttpServletRequest request; - - - // ----------------------------------------------------------- Constructors - - /** - * Construct a context for this request. - * - * @param request The request to which this context applies. - */ - public ServletRequestContext(HttpServletRequest request) { - this.request = request; - } - - - // --------------------------------------------------------- Public Methods - - /** - * Retrieve the character encoding for the request. - * - * @return The character encoding for the request. - */ - public String getCharacterEncoding() { - return request.getCharacterEncoding(); - } - - /** - * Retrieve the content type of the request. - * - * @return The content type of the request. - */ - public String getContentType() { - return request.getContentType(); - } - - /** - * Retrieve the content length of the request. - * - * @return The content length of the request. - */ - public int getContentLength() { - return request.getContentLength(); - } - - /** - * Retrieve the input stream for the request. - * - * @return The input stream for the request. - * - * @throws IOException if a problem occurs. - */ - public InputStream getInputStream() throws IOException { - return request.getInputStream(); - } - - /** - * Returns a string representation of this object. - * - * @return a string representation of this object. - */ - @Override - public String toString() { - return "ContentLength=" - + this.getContentLength() - + ", ContentType=" - + this.getContentType(); - } -} diff --git a/java/org/apache/tomcat/util/http/fileupload/Streams.java b/java/org/apache/tomcat/util/http/fileupload/Streams.java deleted file mode 100644 index d89f9373e..000000000 --- a/java/org/apache/tomcat/util/http/fileupload/Streams.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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.tomcat.util.http.fileupload; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - - -/** Utility class for working with streams. - */ -public final class Streams { - /** - * Private constructor, to prevent instantiation. - * This class has only static methods. - */ - private Streams() { - // Does nothing - } - - /** - * Default buffer size for use in - * {@link #copy(InputStream, OutputStream, boolean)}. - */ - private static final int DEFAULT_BUFFER_SIZE = 8192; - - /** - * Copies the contents of the given {@link InputStream} - * to the given {@link OutputStream}. Shortcut for - *- * copy(pInputStream, pOutputStream, new byte[8192]); - *- * @param pInputStream The input stream, which is being read. - * It is guaranteed, that {@link InputStream#close()} is called - * on the stream. - * @param pOutputStream The output stream, to which data should - * be written. May be null, in which case the input streams - * contents are simply discarded. - * @param pClose True guarantees, that {@link OutputStream#close()} - * is called on the stream. False indicates, that only - * {@link OutputStream#flush()} should be called finally. - * - * @return Number of bytes, which have been copied. - * @throws IOException An I/O error occurred. - */ - public static long copy(InputStream pInputStream, - OutputStream pOutputStream, boolean pClose) - throws IOException { - return copy(pInputStream, pOutputStream, pClose, - new byte[DEFAULT_BUFFER_SIZE]); - } - - /** - * Copies the contents of the given {@link InputStream} - * to the given {@link OutputStream}. - * @param pIn The input stream, which is being read. - * It is guaranteed, that {@link InputStream#close()} is called - * on the stream. - * @param pOut The output stream, to which data should - * be written. May be null, in which case the input streams - * contents are simply discarded. - * @param pClose True guarantees, that {@link OutputStream#close()} - * is called on the stream. False indicates, that only - * {@link OutputStream#flush()} should be called finally. - * @param pBuffer Temporary buffer, which is to be used for - * copying data. - * @return Number of bytes, which have been copied. - * @throws IOException An I/O error occurred. - */ - public static long copy(InputStream pIn, - OutputStream pOut, boolean pClose, - byte[] pBuffer) - throws IOException { - OutputStream out = pOut; - InputStream in = pIn; - try { - long total = 0; - for (;;) { - int res = in.read(pBuffer); - if (res == -1) { - break; - } - if (res > 0) { - total += res; - if (out != null) { - out.write(pBuffer, 0, res); - } - } - } - if (out != null) { - if (pClose) { - out.close(); - } else { - out.flush(); - } - out = null; - } - in.close(); - in = null; - return total; - } finally { - if (in != null) { - try { - in.close(); - } catch (Throwable t) { - /* Ignore me */ - } - } - if (pClose && out != null) { - try { - out.close(); - } catch (Throwable t) { - /* Ignore me */ - } - } - } - } - - /** - * This convenience method allows to read a - * {@link org.apache.commons.fileupload.FileItemStream}'s - * content into a string. The platform's default character encoding - * is used for converting bytes into characters. - * @param pStream The input stream to read. - * @see #asString(InputStream, String) - * @return The streams contents, as a string. - * @throws IOException An I/O error occurred. - */ - public static String asString(InputStream pStream) throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy(pStream, baos, true); - return baos.toString(); - } - - /** - * This convenience method allows to read a - * {@link org.apache.commons.fileupload.FileItemStream}'s - * content into a string, using the given character encoding. - * @param pStream The input stream to read. - * @param pEncoding The character encoding, typically "UTF-8". - * @see #asString(InputStream) - * @return The streams contents, as a string. - * @throws IOException An I/O error occurred. - */ - public static String asString(InputStream pStream, String pEncoding) - throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - copy(pStream, baos, true); - return baos.toString(pEncoding); - } -} diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java new file mode 100644 index 000000000..3c5babed2 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItem.java @@ -0,0 +1,736 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.tomcat.util.http.fileupload.disk; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.util.Map; + +import org.apache.tomcat.util.http.fileupload.DeferredFileOutputStream; +import org.apache.tomcat.util.http.fileupload.FileItem; +import org.apache.tomcat.util.http.fileupload.FileItemHeaders; +import org.apache.tomcat.util.http.fileupload.FileItemHeadersSupport; +import org.apache.tomcat.util.http.fileupload.FileUploadException; +import org.apache.tomcat.util.http.fileupload.IOUtils; +import org.apache.tomcat.util.http.fileupload.ParameterParser; + + +/** + *
The default implementation of the + * {@link org.apache.commons.fileupload.FileItem FileItem} interface. + * + *
After retrieving an instance of this class from a {@link + * org.apache.commons.fileupload.DiskFileUpload DiskFileUpload} instance (see + * {@link org.apache.commons.fileupload.DiskFileUpload + * #parseRequest(javax.servlet.http.HttpServletRequest)}), you may + * either request all contents of file at once using {@link #get()} or + * request an {@link java.io.InputStream InputStream} with + * {@link #getInputStream()} and process the file without attempting to load + * it into memory, which may come handy with large files. + * + *
When using the DiskFileItemFactory, then you should
+ * consider the following: Temporary files are automatically deleted as
+ * soon as they are no longer needed. (More precisely, when the
+ * corresponding instance of {@link java.io.File} is garbage collected.)
+ * This is done by the so-called reaper thread, which is started
+ * automatically when the class {@link org.apache.commons.io.FileCleaner}
+ * is loaded.
+ * It might make sense to terminate that thread, for example, if
+ * your web application ends. See the section on "Resource cleanup"
+ * in the users guide of commons-fileupload.
null if
+ * not defined.
+ */
+ private String contentType;
+
+
+ /**
+ * Whether or not this item is a simple form field.
+ */
+ private boolean isFormField;
+
+
+ /**
+ * The original filename in the user's filesystem.
+ */
+ private String fileName;
+
+
+ /**
+ * The size of the item, in bytes. This is used to cache the size when a
+ * file item is moved from its original location.
+ */
+ private long size = -1;
+
+
+ /**
+ * The threshold above which uploads will be stored on disk.
+ */
+ private int sizeThreshold;
+
+
+ /**
+ * The directory in which uploaded files will be stored, if stored on disk.
+ */
+ private File repository;
+
+
+ /**
+ * Cached contents of the file.
+ */
+ private byte[] cachedContent;
+
+
+ /**
+ * Output stream for this item.
+ */
+ private transient DeferredFileOutputStream dfos;
+
+ /**
+ * The temporary file to use.
+ */
+ private transient File tempFile;
+
+ /**
+ * File to allow for serialization of the content of this item.
+ */
+ private File dfosFile;
+
+ /**
+ * The file items headers.
+ */
+ private FileItemHeaders headers;
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs a new DiskFileItem instance.
+ *
+ * @param fieldName The name of the form field.
+ * @param contentType The content type passed by the browser or
+ * null if not specified.
+ * @param isFormField Whether or not this item is a plain form field, as
+ * opposed to a file upload.
+ * @param fileName The original filename in the user's filesystem, or
+ * null if not specified.
+ * @param sizeThreshold The threshold, in bytes, below which items will be
+ * retained in memory and above which they will be
+ * stored as a file.
+ * @param repository The data repository, which is the directory in
+ * which files will be created, should the item size
+ * exceed the threshold.
+ */
+ public DiskFileItem(String fieldName,
+ String contentType, boolean isFormField, String fileName,
+ int sizeThreshold, File repository) {
+ this.fieldName = fieldName;
+ this.contentType = contentType;
+ this.isFormField = isFormField;
+ this.fileName = fileName;
+ this.sizeThreshold = sizeThreshold;
+ this.repository = repository;
+ }
+
+
+ // ------------------------------- Methods from javax.activation.DataSource
+
+
+ /**
+ * Returns an {@link java.io.InputStream InputStream} that can be
+ * used to retrieve the contents of the file.
+ *
+ * @return An {@link java.io.InputStream InputStream} that can be
+ * used to retrieve the contents of the file.
+ *
+ * @throws IOException if an error occurs.
+ */
+ public InputStream getInputStream()
+ throws IOException {
+ if (!isInMemory()) {
+ return new FileInputStream(dfos.getFile());
+ }
+
+ if (cachedContent == null) {
+ cachedContent = dfos.getData();
+ }
+ return new ByteArrayInputStream(cachedContent);
+ }
+
+
+ /**
+ * Returns the content type passed by the agent or null if
+ * not defined.
+ *
+ * @return The content type passed by the agent or null if
+ * not defined.
+ */
+ public String getContentType() {
+ return contentType;
+ }
+
+
+ /**
+ * Returns the content charset passed by the agent or null if
+ * not defined.
+ *
+ * @return The content charset passed by the agent or null if
+ * not defined.
+ */
+ public String getCharSet() {
+ ParameterParser parser = new ParameterParser();
+ parser.setLowerCaseNames(true);
+ // Parameter parser can handle null input
+ Maptrue if the file contents will be read
+ * from memory; false otherwise.
+ */
+ public boolean isInMemory() {
+ if (cachedContent != null) {
+ return true;
+ }
+ return dfos.isInMemory();
+ }
+
+
+ /**
+ * Returns the size of the file.
+ *
+ * @return The size of the file, in bytes.
+ */
+ public long getSize() {
+ if (size >= 0) {
+ return size;
+ } else if (cachedContent != null) {
+ return cachedContent.length;
+ } else if (dfos.isInMemory()) {
+ return dfos.getData().length;
+ } else {
+ return dfos.getFile().length();
+ }
+ }
+
+
+ /**
+ * Returns the contents of the file as an array of bytes. If the
+ * contents of the file were not yet cached in memory, they will be
+ * loaded from the disk storage and cached.
+ *
+ * @return The contents of the file as an array of bytes.
+ */
+ public byte[] get() {
+ if (isInMemory()) {
+ if (cachedContent == null) {
+ cachedContent = dfos.getData();
+ }
+ return cachedContent;
+ }
+
+ byte[] fileData = new byte[(int) getSize()];
+ FileInputStream fis = null;
+
+ try {
+ fis = new FileInputStream(dfos.getFile());
+ fis.read(fileData);
+ } catch (IOException e) {
+ fileData = null;
+ } finally {
+ if (fis != null) {
+ try {
+ fis.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+
+ return fileData;
+ }
+
+
+ /**
+ * Returns the contents of the file as a String, using the specified
+ * encoding. This method uses {@link #get()} to retrieve the
+ * contents of the file.
+ *
+ * @param charset The charset to use.
+ *
+ * @return The contents of the file, as a string.
+ *
+ * @throws UnsupportedEncodingException if the requested character
+ * encoding is not available.
+ */
+ public String getString(final String charset)
+ throws UnsupportedEncodingException {
+ return new String(get(), charset);
+ }
+
+
+ /**
+ * Returns the contents of the file as a String, using the default
+ * character encoding. This method uses {@link #get()} to retrieve the
+ * contents of the file.
+ *
+ * @return The contents of the file, as a string.
+ *
+ * @todo Consider making this method throw UnsupportedEncodingException.
+ */
+ public String getString() {
+ byte[] rawdata = get();
+ String charset = getCharSet();
+ if (charset == null) {
+ charset = DEFAULT_CHARSET;
+ }
+ try {
+ return new String(rawdata, charset);
+ } catch (UnsupportedEncodingException e) {
+ return new String(rawdata);
+ }
+ }
+
+
+ /**
+ * A convenience method to write an uploaded item to disk. The client code
+ * is not concerned with whether or not the item is stored in memory, or on
+ * disk in a temporary location. They just want to write the uploaded item
+ * to a file.
+ * + * This implementation first attempts to rename the uploaded item to the + * specified destination file, if the item was originally written to disk. + * Otherwise, the data will be copied to the specified file. + *
+ * This method is only guaranteed to work once, the first time it
+ * is invoked for a particular item. This is because, in the event that the
+ * method renames a temporary file, that file will no longer be available
+ * to copy or rename again at a later time.
+ *
+ * @param file The File into which the uploaded item should
+ * be stored.
+ *
+ * @throws Exception if an error occurs.
+ */
+ public void write(File file) throws Exception {
+ if (isInMemory()) {
+ FileOutputStream fout = null;
+ try {
+ fout = new FileOutputStream(file);
+ fout.write(get());
+ } finally {
+ if (fout != null) {
+ fout.close();
+ }
+ }
+ } else {
+ File outputFile = getStoreLocation();
+ if (outputFile != null) {
+ // Save the length of the file
+ size = outputFile.length();
+ /*
+ * The uploaded file is being stored on disk
+ * in a temporary location so move it to the
+ * desired file.
+ */
+ if (!outputFile.renameTo(file)) {
+ BufferedInputStream in = null;
+ BufferedOutputStream out = null;
+ try {
+ in = new BufferedInputStream(
+ new FileInputStream(outputFile));
+ out = new BufferedOutputStream(
+ new FileOutputStream(file));
+ IOUtils.copy(in, out);
+ } finally {
+ if (in != null) {
+ try {
+ in.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ if (out != null) {
+ try {
+ out.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * For whatever reason we cannot write the
+ * file to disk.
+ */
+ throw new FileUploadException(
+ "Cannot write uploaded file to disk!");
+ }
+ }
+ }
+
+
+ /**
+ * Deletes the underlying storage for a file item, including deleting any
+ * associated temporary disk file. Although this storage will be deleted
+ * automatically when the FileItem instance is garbage
+ * collected, this method can be used to ensure that this is done at an
+ * earlier time, thus preserving system resources.
+ */
+ public void delete() {
+ cachedContent = null;
+ File outputFile = getStoreLocation();
+ if (outputFile != null && outputFile.exists()) {
+ outputFile.delete();
+ }
+ }
+
+
+ /**
+ * Returns the name of the field in the multipart form corresponding to
+ * this file item.
+ *
+ * @return The name of the form field.
+ *
+ * @see #setFieldName(java.lang.String)
+ *
+ */
+ public String getFieldName() {
+ return fieldName;
+ }
+
+
+ /**
+ * Sets the field name used to reference this file item.
+ *
+ * @param fieldName The name of the form field.
+ *
+ * @see #getFieldName()
+ *
+ */
+ public void setFieldName(String fieldName) {
+ this.fieldName = fieldName;
+ }
+
+
+ /**
+ * Determines whether or not a FileItem instance represents
+ * a simple form field.
+ *
+ * @return true if the instance represents a simple form
+ * field; false if it represents an uploaded file.
+ *
+ * @see #setFormField(boolean)
+ *
+ */
+ public boolean isFormField() {
+ return isFormField;
+ }
+
+
+ /**
+ * Specifies whether or not a FileItem instance represents
+ * a simple form field.
+ *
+ * @param state true if the instance represents a simple form
+ * field; false if it represents an uploaded file.
+ *
+ * @see #isFormField()
+ *
+ */
+ public void setFormField(boolean state) {
+ isFormField = state;
+ }
+
+
+ /**
+ * Returns an {@link java.io.OutputStream OutputStream} that can
+ * be used for storing the contents of the file.
+ *
+ * @return An {@link java.io.OutputStream OutputStream} that can be used
+ * for storing the contensts of the file.
+ *
+ * @throws IOException if an error occurs.
+ */
+ public OutputStream getOutputStream()
+ throws IOException {
+ if (dfos == null) {
+ File outputFile = getTempFile();
+ dfos = new DeferredFileOutputStream(sizeThreshold, outputFile);
+ }
+ return dfos;
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Returns the {@link java.io.File} object for the FileItem's
+ * data's temporary location on the disk. Note that for
+ * FileItems that have their data stored in memory,
+ * this method will return null. When handling large
+ * files, you can use {@link java.io.File#renameTo(java.io.File)} to
+ * move the file to new location without copying the data, if the
+ * source and destination locations reside within the same logical
+ * volume.
+ *
+ * @return The data file, or null if the data is stored in
+ * memory.
+ */
+ public File getStoreLocation() {
+ return dfos == null ? null : dfos.getFile();
+ }
+
+
+ // ------------------------------------------------------ Protected methods
+
+
+ /**
+ * Removes the file contents from the temporary storage.
+ */
+ @Override
+ protected void finalize() {
+ File outputFile = dfos.getFile();
+
+ if (outputFile != null && outputFile.exists()) {
+ outputFile.delete();
+ }
+ }
+
+
+ /**
+ * Creates and returns a {@link java.io.File File} representing a uniquely
+ * named temporary file in the configured repository path. The lifetime of
+ * the file is tied to the lifetime of the FileItem instance;
+ * the file will be deleted when the instance is garbage collected.
+ *
+ * @return The {@link java.io.File File} to be used for temporary storage.
+ */
+ protected File getTempFile() {
+ if (tempFile == null) {
+ File tempDir = repository;
+ if (tempDir == null) {
+ tempDir = new File(System.getProperty("java.io.tmpdir"));
+ }
+
+ String tempFileName =
+ "upload_" + UID + "_" + getUniqueId() + ".tmp";
+
+ tempFile = new File(tempDir, tempFileName);
+ }
+ return tempFile;
+ }
+
+
+ // -------------------------------------------------------- Private methods
+
+
+ /**
+ * Returns an identifier that is unique within the class loader used to
+ * load this class, but does not have random-like apearance.
+ *
+ * @return A String with the non-random looking instance identifier.
+ */
+ private static String getUniqueId() {
+ final int limit = 100000000;
+ int current;
+ synchronized (DiskFileItem.class) {
+ current = counter++;
+ }
+ String id = Integer.toString(current);
+
+ // If you manage to get more than 100 million of ids, you'll
+ // start getting ids longer than 8 characters.
+ if (current < limit) {
+ id = ("00000000" + id).substring(id.length());
+ }
+ return id;
+ }
+
+
+
+
+ /**
+ * Returns a string representation of this object.
+ *
+ * @return a string representation of this object.
+ */
+ @Override
+ public String toString() {
+ return "name=" + this.getName()
+ + ", StoreLocation="
+ + String.valueOf(this.getStoreLocation())
+ + ", size="
+ + this.getSize()
+ + "bytes, "
+ + "isFormField=" + isFormField()
+ + ", FieldName="
+ + this.getFieldName();
+ }
+
+
+ // -------------------------------------------------- Serialization methods
+
+
+ /**
+ * Writes the state of this object during serialization.
+ *
+ * @param out The stream to which the state should be written.
+ *
+ * @throws IOException if an error occurs.
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ // Read the data
+ if (dfos.isInMemory()) {
+ cachedContent = get();
+ } else {
+ cachedContent = null;
+ dfosFile = dfos.getFile();
+ }
+
+ // write out values
+ out.defaultWriteObject();
+ }
+
+ /**
+ * Reads the state of this object during deserialization.
+ *
+ * @param in The stream from which the state should be read.
+ *
+ * @throws IOException if an error occurs.
+ * @throws ClassNotFoundException if class cannot be found.
+ */
+ private void readObject(ObjectInputStream in)
+ throws IOException, ClassNotFoundException {
+ // read values
+ in.defaultReadObject();
+
+ OutputStream output = getOutputStream();
+ if (cachedContent != null) {
+ output.write(cachedContent);
+ } else {
+ FileInputStream input = new FileInputStream(dfosFile);
+ IOUtils.copy(input, output);
+ dfosFile.delete();
+ dfosFile = null;
+ }
+ output.close();
+
+ cachedContent = null;
+ }
+
+ /**
+ * Returns the file item headers.
+ * @return The file items headers.
+ */
+ public FileItemHeaders getHeaders() {
+ return headers;
+ }
+
+ /**
+ * Sets the file item headers.
+ * @param pHeaders The file items headers.
+ */
+ public void setHeaders(FileItemHeaders pHeaders) {
+ headers = pHeaders;
+ }
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
new file mode 100644
index 000000000..09c8ded43
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/disk/DiskFileItemFactory.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.tomcat.util.http.fileupload.disk;
+
+import java.io.File;
+
+import org.apache.tomcat.util.http.fileupload.FileCleaningTracker;
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemFactory;
+
+
+/**
+ *
The default {@link org.apache.commons.fileupload.FileItemFactory} + * implementation. This implementation creates + * {@link org.apache.commons.fileupload.FileItem} instances which keep their + * content either in memory, for smaller items, or in a temporary file on disk, + * for larger items. The size threshold, above which content will be stored on + * disk, is configurable, as is the directory in which temporary files will be + * created.
+ * + *If not otherwise configured, the default configuration values are as + * follows: + *
System.getProperty("java.io.tmpdir").When using the DiskFileItemFactory, then you should
+ * consider the following: Temporary files are automatically deleted as
+ * soon as they are no longer needed. (More precisely, when the
+ * corresponding instance of {@link java.io.File} is garbage collected.)
+ * Cleaning up those files is done by an instance of
+ * {@link FileCleaningTracker}, and an associated thread. In a complex
+ * environment, for example in a web application, you should consider
+ * terminating this thread, for example, when your web application
+ * ends. See the section on "Resource cleanup"
+ * in the users guide of commons-fileupload.
The instance of {@link FileCleaningTracker}, which is responsible + * for deleting temporary files.
+ *May be null, if tracking files is not required.
+ */ + private FileCleaningTracker fileCleaningTracker; + + // ----------------------------------------------------------- Constructors + + + /** + * Constructs an unconfigured instance of this class. The resulting factory + * may be configured by calling the appropriate setter methods. + */ + public DiskFileItemFactory() { + this(DEFAULT_SIZE_THRESHOLD, null); + } + + + /** + * Constructs a preconfigured instance of this class. + * + * @param sizeThreshold The threshold, in bytes, below which items will be + * retained in memory and above which they will be + * stored as a file. + * @param repository The data repository, which is the directory in + * which files will be created, should the item size + * exceed the threshold. + */ + public DiskFileItemFactory(int sizeThreshold, File repository) { + this.sizeThreshold = sizeThreshold; + this.repository = repository; + } + + // ------------------------------------------------------------- Properties + + + /** + * Returns the directory used to temporarily store files that are larger + * than the configured size threshold. + * + * @return The directory in which temporary files will be located. + * + * @see #setRepository(java.io.File) + * + */ + public File getRepository() { + return repository; + } + + + /** + * Sets the directory used to temporarily store files that are larger + * than the configured size threshold. + * + * @param repository The directory in which temporary files will be located. + * + * @see #getRepository() + * + */ + public void setRepository(File repository) { + this.repository = repository; + } + + + /** + * Returns the size threshold beyond which files are written directly to + * disk. The default value is 10240 bytes. + * + * @return The size threshold, in bytes. + * + * @see #setSizeThreshold(int) + */ + public int getSizeThreshold() { + return sizeThreshold; + } + + + /** + * Sets the size threshold beyond which files are written directly to disk. + * + * @param sizeThreshold The size threshold, in bytes. + * + * @see #getSizeThreshold() + * + */ + public void setSizeThreshold(int sizeThreshold) { + this.sizeThreshold = sizeThreshold; + } + + + // --------------------------------------------------------- Public Methods + + /** + * Create a new {@link org.apache.tomcat.util.http.fileupload.disk.commons.fileupload.disk.DiskFileItem} + * instance from the supplied parameters and the local factory + * configuration. + * + * @param fieldName The name of the form field. + * @param contentType The content type of the form field. + * @param isFormFieldtrue if this is a plain form field;
+ * false otherwise.
+ * @param fileName The name of the uploaded file, if any, as supplied
+ * by the browser or other client.
+ *
+ * @return The newly created file item.
+ */
+ public FileItem createItem(String fieldName, String contentType,
+ boolean isFormField, String fileName) {
+ DiskFileItem result = new DiskFileItem(fieldName, contentType,
+ isFormField, fileName, sizeThreshold, repository);
+ FileCleaningTracker tracker = getFileCleaningTracker();
+ if (tracker != null) {
+ tracker.track(result.getTempFile(), this);
+ }
+ return result;
+ }
+
+
+ /**
+ * Returns the tracker, which is responsible for deleting temporary
+ * files.
+ * @return An instance of {@link FileCleaningTracker}, defaults to
+ * {@link org.apache.commons.io.FileCleaner#getInstance()}. Null,
+ * if temporary files aren't tracked.
+ */
+ public FileCleaningTracker getFileCleaningTracker() {
+ return fileCleaningTracker;
+ }
+
+ /**
+ * Returns the tracker, which is responsible for deleting temporary
+ * files.
+ * @param pTracker An instance of {@link FileCleaningTracker},
+ * which will from now on track the created files. May be null
+ * to disable tracking.
+ */
+ public void setFileCleaningTracker(FileCleaningTracker pTracker) {
+ fileCleaningTracker = pTracker;
+ }
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
new file mode 100644
index 000000000..a95cc75ac
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletFileUpload.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.tomcat.util.http.fileupload.servlet;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.util.http.fileupload.FileItem;
+import org.apache.tomcat.util.http.fileupload.FileItemFactory;
+import org.apache.tomcat.util.http.fileupload.FileItemIterator;
+import org.apache.tomcat.util.http.fileupload.FileUpload;
+import org.apache.tomcat.util.http.fileupload.FileUploadException;
+
+
+/**
+ * High level API for processing file uploads.
+ * + *This class handles multiple files per single HTML widget, sent using
+ * multipart/mixed encoding type, as specified by
+ * RFC 1867. Use {@link
+ * #parseRequest(HttpServletRequest)} to acquire a list of {@link
+ * org.apache.commons.fileupload.FileItem}s associated with a given HTML
+ * widget.
How the data for individual parts is stored is determined by the factory + * used to create them; a given part may be in memory, on disk, or somewhere + * else.
+ * + * @author Rafal Krzewski + * @author Daniel Rall + * @author Jason van Zyl + * @author John McNally + * @author Martin Cooper + * @author Sean C. Sullivan + * + * @version $Id$ + */ +public class ServletFileUpload extends FileUpload { + + // ---------------------------------------------------------- Class methods + + + /** + * Utility method that determines whether the request contains multipart + * content. + * + * @param request The servlet request to be evaluated. Must be non-null. + * + * @returntrue if the request is multipart;
+ * false otherwise.
+ */
+ public static final boolean isMultipartContent(
+ HttpServletRequest request) {
+ if (!"post".equals(request.getMethod().toLowerCase(Locale.ENGLISH))) {
+ return false;
+ }
+ String contentType = request.getContentType();
+ if (contentType == null) {
+ return false;
+ }
+ if (contentType.toLowerCase(Locale.ENGLISH).startsWith(MULTIPART)) {
+ return true;
+ }
+ return false;
+ }
+
+
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Constructs an uninitialised instance of this class. A factory must be
+ * configured, using setFileItemFactory(), before attempting
+ * to parse requests.
+ *
+ * @see FileUpload#FileUpload(FileItemFactory)
+ */
+ public ServletFileUpload() {
+ super();
+ }
+
+
+ /**
+ * Constructs an instance of this class which uses the supplied factory to
+ * create FileItem instances.
+ *
+ * @see FileUpload#FileUpload()
+ * @param fileItemFactory The factory to use for creating file items.
+ */
+ public ServletFileUpload(FileItemFactory fileItemFactory) {
+ super(fileItemFactory);
+ }
+
+
+ // --------------------------------------------------------- Public methods
+
+
+ /**
+ * Processes an RFC 1867
+ * compliant multipart/form-data stream.
+ *
+ * @param request The servlet request to be parsed.
+ *
+ * @return A list of FileItem instances 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 Listmultipart/form-data stream.
+ *
+ * @param request The servlet request to be parsed.
+ *
+ * @return An iterator to instances of FileItemStream
+ * parsed from the request, in the order that they were
+ * transmitted.
+ *
+ * @throws FileUploadException if there are problems reading/parsing
+ * the request or storing files.
+ * @throws IOException An I/O error occurred. This may be a network
+ * error while communicating with the client or a problem while
+ * storing the uploaded content.
+ */
+ public FileItemIterator getItemIterator(HttpServletRequest request)
+ throws FileUploadException, IOException {
+ return super.getItemIterator(new ServletRequestContext(request));
+ }
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
new file mode 100644
index 000000000..6db1d8e3f
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/servlet/ServletRequestContext.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.tomcat.util.http.fileupload.servlet;
+
+import java.io.InputStream;
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.tomcat.util.http.fileupload.RequestContext;
+
+
+/**
+ * Provides access to the request information needed for a request made to + * an HTTP servlet.
+ * + * @author Martin Cooper + * + * @since FileUpload 1.1 + * + * @version $Id$ + */ +public class ServletRequestContext implements RequestContext { + + // ----------------------------------------------------- Instance Variables + + /** + * The request for which the context is being provided. + */ + private HttpServletRequest request; + + + // ----------------------------------------------------------- Constructors + + /** + * Construct a context for this request. + * + * @param request The request to which this context applies. + */ + public ServletRequestContext(HttpServletRequest request) { + this.request = request; + } + + + // --------------------------------------------------------- Public Methods + + /** + * Retrieve the character encoding for the request. + * + * @return The character encoding for the request. + */ + public String getCharacterEncoding() { + return request.getCharacterEncoding(); + } + + /** + * Retrieve the content type of the request. + * + * @return The content type of the request. + */ + public String getContentType() { + return request.getContentType(); + } + + /** + * Retrieve the content length of the request. + * + * @return The content length of the request. + */ + public int getContentLength() { + return request.getContentLength(); + } + + /** + * Retrieve the input stream for the request. + * + * @return The input stream for the request. + * + * @throws IOException if a problem occurs. + */ + public InputStream getInputStream() throws IOException { + return request.getInputStream(); + } + + /** + * Returns a string representation of this object. + * + * @return a string representation of this object. + */ + @Override + public String toString() { + return "ContentLength=" + + this.getContentLength() + + ", ContentType=" + + this.getContentType(); + } +} diff --git a/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java b/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java new file mode 100644 index 000000000..2c18c4750 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/util/Closeable.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.tomcat.util.http.fileupload.util; + +import java.io.IOException; + + +/** + * Interface of an object, which may be closed. + */ +public interface Closeable { + /** + * Closes the object. + * @throws IOException An I/O error occurred. + */ + void close() throws IOException; + + /** + * Returns, whether the object is already closed. + * @return True, if the object is closed, otherwise false. + * @throws IOException An I/O error occurred. + */ + boolean isClosed() throws IOException; +} diff --git a/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java new file mode 100644 index 000000000..72c8563b7 --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/util/FileItemHeadersImpl.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.tomcat.util.http.fileupload.util; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.tomcat.util.http.fileupload.FileItemHeaders; + + +/** + * Default implementation of the {@link FileItemHeaders} interface. + * + * @author Michael C. Macaluso + * @since 1.3 + */ +public class FileItemHeadersImpl implements FileItemHeaders, Serializable { + private static final long serialVersionUID = -4455695752627032559L; + + /** + * Map ofString keys to a List of
+ * String instances.
+ */
+ private final MapLinkedHashMap could be used, but don't
+ * want to depend on 1.4.
+ */
+ private final Listint in the range
+ * 0 to 255. If no byte is available
+ * because the end of the stream has been reached, the value
+ * -1 is returned. This method blocks until input data
+ * is available, the end of the stream is detected, or an exception
+ * is thrown.
+ *
+ * This method
+ * simply performs in.read() and returns the result.
+ *
+ * @return the next byte of data, or -1 if the end of the
+ * stream is reached.
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ public int read() throws IOException {
+ int res = super.read();
+ if (res != -1) {
+ count++;
+ checkLimit();
+ }
+ return res;
+ }
+
+ /**
+ * Reads up to len bytes of data from this input stream
+ * into an array of bytes. If len is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and 0 is returned.
+ *
+ * This method simply performs in.read(b, off, len)
+ * and returns the result.
+ *
+ * @param b the buffer into which the data is read.
+ * @param off The start offset in the destination array
+ * b.
+ * @param len the maximum number of bytes read.
+ * @return the total number of bytes read into the buffer, or
+ * -1 if there is no more data because the end of
+ * the stream has been reached.
+ * @exception NullPointerException If b is null.
+ * @exception IndexOutOfBoundsException If off is negative,
+ * len is negative, or len is greater than
+ * b.length - off
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ 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;
+ }
+
+ /**
+ * Returns, whether this stream is already closed.
+ * @return True, if the stream is closed, otherwise false.
+ * @throws IOException An I/O error occurred.
+ */
+ public boolean isClosed() throws IOException {
+ return closed;
+ }
+
+ /**
+ * Closes this input stream and releases any system resources
+ * associated with the stream.
+ * This
+ * method simply performs in.close().
+ *
+ * @exception IOException if an I/O error occurs.
+ * @see java.io.FilterInputStream#in
+ */
+ @Override
+ public void close() throws IOException {
+ closed = true;
+ super.close();
+ }
+}
diff --git a/java/org/apache/tomcat/util/http/fileupload/util/Streams.java b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
new file mode 100644
index 000000000..7f177ca47
--- /dev/null
+++ b/java/org/apache/tomcat/util/http/fileupload/util/Streams.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.tomcat.util.http.fileupload.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+
+/** Utility class for working with streams.
+ */
+public final class Streams {
+ /**
+ * Private constructor, to prevent instantiation.
+ * This class has only static methods.
+ */
+ private Streams() {
+ // Does nothing
+ }
+
+ /**
+ * Default buffer size for use in
+ * {@link #copy(InputStream, OutputStream, boolean)}.
+ */
+ private static final int DEFAULT_BUFFER_SIZE = 8192;
+
+ /**
+ * Copies the contents of the given {@link InputStream}
+ * to the given {@link OutputStream}. Shortcut for
+ *
+ * copy(pInputStream, pOutputStream, new byte[8192]); + *+ * @param pInputStream The input stream, which is being read. + * It is guaranteed, that {@link InputStream#close()} is called + * on the stream. + * @param pOutputStream The output stream, to which data should + * be written. May be null, in which case the input streams + * contents are simply discarded. + * @param pClose True guarantees, that {@link OutputStream#close()} + * is called on the stream. False indicates, that only + * {@link OutputStream#flush()} should be called finally. + * + * @return Number of bytes, which have been copied. + * @throws IOException An I/O error occurred. + */ + public static long copy(InputStream pInputStream, + OutputStream pOutputStream, boolean pClose) + throws IOException { + return copy(pInputStream, pOutputStream, pClose, + new byte[DEFAULT_BUFFER_SIZE]); + } + + /** + * Copies the contents of the given {@link InputStream} + * to the given {@link OutputStream}. + * @param pIn The input stream, which is being read. + * It is guaranteed, that {@link InputStream#close()} is called + * on the stream. + * @param pOut The output stream, to which data should + * be written. May be null, in which case the input streams + * contents are simply discarded. + * @param pClose True guarantees, that {@link OutputStream#close()} + * is called on the stream. False indicates, that only + * {@link OutputStream#flush()} should be called finally. + * @param pBuffer Temporary buffer, which is to be used for + * copying data. + * @return Number of bytes, which have been copied. + * @throws IOException An I/O error occurred. + */ + public static long copy(InputStream pIn, + OutputStream pOut, boolean pClose, + byte[] pBuffer) + throws IOException { + OutputStream out = pOut; + InputStream in = pIn; + try { + long total = 0; + for (;;) { + int res = in.read(pBuffer); + if (res == -1) { + break; + } + if (res > 0) { + total += res; + if (out != null) { + out.write(pBuffer, 0, res); + } + } + } + if (out != null) { + if (pClose) { + out.close(); + } else { + out.flush(); + } + out = null; + } + in.close(); + in = null; + return total; + } finally { + if (in != null) { + try { + in.close(); + } catch (Throwable t) { + /* Ignore me */ + } + } + if (pClose && out != null) { + try { + out.close(); + } catch (Throwable t) { + /* Ignore me */ + } + } + } + } + + /** + * This convenience method allows to read a + * {@link org.apache.commons.fileupload.FileItemStream}'s + * content into a string. The platform's default character encoding + * is used for converting bytes into characters. + * @param pStream The input stream to read. + * @see #asString(InputStream, String) + * @return The streams contents, as a string. + * @throws IOException An I/O error occurred. + */ + public static String asString(InputStream pStream) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + copy(pStream, baos, true); + return baos.toString(); + } + + /** + * This convenience method allows to read a + * {@link org.apache.commons.fileupload.FileItemStream}'s + * content into a string, using the given character encoding. + * @param pStream The input stream to read. + * @param pEncoding The character encoding, typically "UTF-8". + * @see #asString(InputStream) + * @return The streams contents, as a string. + * @throws IOException An I/O error occurred. + */ + public static String asString(InputStream pStream, String pEncoding) + throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + copy(pStream, baos, true); + return baos.toString(pEncoding); + } +}