From: markt Date: Sun, 1 Aug 2010 09:28:02 +0000 (+0000) Subject: Switch back to standard commons file-upload layout - simpler to merge updates. Part 2. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=0e5f1bb1eae771971ba87b7fd4085613ff490931;p=tomcat7.0 Switch back to standard commons file-upload layout - simpler to merge updates. Part 2. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@981187 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/java/org/apache/tomcat/util/http/fileupload/Closeable.java b/java/org/apache/tomcat/util/http/fileupload/Closeable.java deleted file mode 100644 index 04d877b58..000000000 --- a/java/org/apache/tomcat/util/http/fileupload/Closeable.java +++ /dev/null @@ -1,38 +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; - - -/** - * 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/DiskFileItem.java b/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java deleted file mode 100644 index 3d48a0d07..000000000 --- a/java/org/apache/tomcat/util/http/fileupload/DiskFileItem.java +++ /dev/null @@ -1,728 +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.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; - - -/** - *

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.

- * - * @author Rafal Krzewski - * @author Sean Legassick - * @author Jason van Zyl - * @author John McNally - * @author Martin Cooper - * @author Sean C. Sullivan - * - * @since FileUpload 1.1 - * - * @version $Id$ - */ -public class DiskFileItem - implements FileItem, FileItemHeadersSupport { - - // ----------------------------------------------------- Manifest constants - - /** - * The UID to use when serializing this instance. - */ - private static final long serialVersionUID = 2237570099615271025L; - - - /** - * Default content charset to be used when no explicit charset - * parameter is provided by the sender. Media subtypes of the - * "text" type are defined to have a default charset value of - * "ISO-8859-1" when received via HTTP. - */ - public static final String DEFAULT_CHARSET = "ISO-8859-1"; - - - // ----------------------------------------------------------- Data members - - - /** - * UID used in unique file name generation. - */ - private static final String UID = - new java.rmi.server.UID().toString() - .replace(':', '_').replace('-', '_'); - - /** - * Counter used in unique identifier generation. - */ - private static int counter = 0; - - - /** - * The name of the form field as provided by the browser. - */ - private String fieldName; - - - /** - * The content type passed by the browser, or 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 - Map params = parser.parse(getContentType(), ';'); - return params.get("charset"); - } - - - /** - * Returns the original filename in the client's filesystem. - * - * @return The original filename in the client's filesystem. - */ - public String getName() { - return fileName; - } - - - // ------------------------------------------------------- FileItem methods - - - /** - * Provides a hint as to whether or not the file contents will be read - * from memory. - * - * @return true 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/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; - - -/** - *

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: - *

- *

- * - *

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.

- * - * @author Martin Cooper - * - * @since FileUpload 1.1 - * - * @version $Id$ - */ -public class DiskFileItemFactory implements FileItemFactory { - - // ----------------------------------------------------- Manifest constants - - - /** - * The default threshold above which uploads will be stored on disk. - */ - public static final int DEFAULT_SIZE_THRESHOLD = 10240; - - - // ----------------------------------------------------- Instance Variables - - - /** - * The directory in which uploaded files will be stored, if stored on disk. - */ - private File repository; - - - /** - * The threshold above which uploads will be stored on disk. - */ - private int sizeThreshold = DEFAULT_SIZE_THRESHOLD; - - - /** - *

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 isFormField true 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 Map> headerNameToValueListMap = - new HashMap>(); - - /** - * List to preserve order of headers as added. This would not be - * needed if a LinkedHashMap could be used, but don't - * want to depend on 1.4. - */ - private final List headerNameList = new ArrayList(); - - public String getHeader(String name) { - String nameLower = name.toLowerCase(Locale.ENGLISH); - List headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - return null; - } - return headerValueList.get(0); - } - - public Iterator getHeaderNames() { - return headerNameList.iterator(); - } - - public Iterator getHeaders(String name) { - String nameLower = name.toLowerCase(Locale.ENGLISH); - List headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - return Collections.emptyList().iterator(); - } - return headerValueList.iterator(); - } - - /** - * Method to add header values to this instance. - * - * @param name name of this header - * @param value value of this header - */ - public synchronized void addHeader(String name, String value) { - String nameLower = name.toLowerCase(); - List headerValueList = headerNameToValueListMap.get(nameLower); - if (null == headerValueList) { - headerValueList = new ArrayList(); - headerNameToValueListMap.put(nameLower, headerValueList); - headerNameList.add(nameLower); - } - headerValueList.add(value); - } -} diff --git a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java index 49985c66b..f98525754 100644 --- a/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java +++ b/java/org/apache/tomcat/util/http/fileupload/FileUploadBase.java @@ -28,6 +28,10 @@ import java.util.NoSuchElementException; import javax.servlet.http.HttpServletRequest; import org.apache.tomcat.util.http.fileupload.MultipartStream.ItemInputStream; +import org.apache.tomcat.util.http.fileupload.util.Closeable; +import org.apache.tomcat.util.http.fileupload.util.FileItemHeadersImpl; +import org.apache.tomcat.util.http.fileupload.util.LimitedInputStream; +import org.apache.tomcat.util.http.fileupload.util.Streams; /** diff --git a/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java b/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java deleted file mode 100644 index bbef674d3..000000000 --- a/java/org/apache/tomcat/util/http/fileupload/LimitedInputStream.java +++ /dev/null @@ -1,158 +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.FilterInputStream; -import java.io.IOException; -import java.io.InputStream; - - -/** - * An input stream, which limits its data size. This stream is - * used, if the content length is unknown. - */ -public abstract class LimitedInputStream - extends FilterInputStream implements Closeable { - /** - * The maximum size of an item, in bytes. - */ - private long sizeMax; - /** - * The current number of bytes. - */ - private long count; - /** - * Whether this stream is already closed. - */ - private boolean closed; - - /** - * Creates a new instance. - * @param pIn The input stream, which shall be limited. - * @param pSizeMax The limit; no more than this number of bytes - * shall be returned by the source stream. - */ - public LimitedInputStream(InputStream pIn, long pSizeMax) { - super(pIn); - sizeMax = pSizeMax; - } - - /** - * Called to indicate, that the input streams limit has - * been exceeded. - * @param pSizeMax The input streams limit, in bytes. - * @param pCount The actual number of bytes. - * @throws IOException The called method is expected - * to raise an IOException. - */ - protected abstract void raiseError(long pSizeMax, long pCount) - throws IOException; - - /** Called to check, whether the input streams - * limit is reached. - * @throws IOException The given limit is exceeded. - */ - private void checkLimit() throws IOException { - if (count > sizeMax) { - raiseError(sizeMax, count); - } - } - - /** - * Reads the next byte of data from this input stream. The value - * byte is returned as an int 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. - * - * @return true 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 List parseRequest(HttpServletRequest request) - throws FileUploadException { - return parseRequest(new ServletRequestContext(request)); - } - - - /** - * Processes an RFC 1867 - * compliant multipart/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.

+ * + * @author Rafal Krzewski + * @author Sean Legassick + * @author Jason van Zyl + * @author John McNally + * @author Martin Cooper + * @author Sean C. Sullivan + * + * @since FileUpload 1.1 + * + * @version $Id$ + */ +public class DiskFileItem + implements FileItem, FileItemHeadersSupport { + + // ----------------------------------------------------- Manifest constants + + /** + * The UID to use when serializing this instance. + */ + private static final long serialVersionUID = 2237570099615271025L; + + + /** + * Default content charset to be used when no explicit charset + * parameter is provided by the sender. Media subtypes of the + * "text" type are defined to have a default charset value of + * "ISO-8859-1" when received via HTTP. + */ + public static final String DEFAULT_CHARSET = "ISO-8859-1"; + + + // ----------------------------------------------------------- Data members + + + /** + * UID used in unique file name generation. + */ + private static final String UID = + new java.rmi.server.UID().toString() + .replace(':', '_').replace('-', '_'); + + /** + * Counter used in unique identifier generation. + */ + private static int counter = 0; + + + /** + * The name of the form field as provided by the browser. + */ + private String fieldName; + + + /** + * The content type passed by the browser, or 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 + Map params = parser.parse(getContentType(), ';'); + return params.get("charset"); + } + + + /** + * Returns the original filename in the client's filesystem. + * + * @return The original filename in the client's filesystem. + */ + public String getName() { + return fileName; + } + + + // ------------------------------------------------------- FileItem methods + + + /** + * Provides a hint as to whether or not the file contents will be read + * from memory. + * + * @return true 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: + *

    + *
  • Size threshold is 10KB.
  • + *
  • Repository is the system default temp directory, as returned by + * 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.

+ * + * @author Martin Cooper + * + * @since FileUpload 1.1 + * + * @version $Id$ + */ +public class DiskFileItemFactory implements FileItemFactory { + + // ----------------------------------------------------- Manifest constants + + + /** + * The default threshold above which uploads will be stored on disk. + */ + public static final int DEFAULT_SIZE_THRESHOLD = 10240; + + + // ----------------------------------------------------- Instance Variables + + + /** + * The directory in which uploaded files will be stored, if stored on disk. + */ + private File repository; + + + /** + * The threshold above which uploads will be stored on disk. + */ + private int sizeThreshold = DEFAULT_SIZE_THRESHOLD; + + + /** + *

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 isFormField true 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. + * + * @return true 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 List parseRequest(HttpServletRequest request) + throws FileUploadException { + return parseRequest(new ServletRequestContext(request)); + } + + + /** + * Processes an RFC 1867 + * compliant multipart/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 of String keys to a List of + * String instances. + */ + private final Map> headerNameToValueListMap = + new HashMap>(); + + /** + * List to preserve order of headers as added. This would not be + * needed if a LinkedHashMap could be used, but don't + * want to depend on 1.4. + */ + private final List headerNameList = new ArrayList(); + + public String getHeader(String name) { + String nameLower = name.toLowerCase(Locale.ENGLISH); + List headerValueList = headerNameToValueListMap.get(nameLower); + if (null == headerValueList) { + return null; + } + return headerValueList.get(0); + } + + public Iterator getHeaderNames() { + return headerNameList.iterator(); + } + + public Iterator getHeaders(String name) { + String nameLower = name.toLowerCase(Locale.ENGLISH); + List headerValueList = headerNameToValueListMap.get(nameLower); + if (null == headerValueList) { + return Collections.emptyList().iterator(); + } + return headerValueList.iterator(); + } + + /** + * Method to add header values to this instance. + * + * @param name name of this header + * @param value value of this header + */ + public synchronized void addHeader(String name, String value) { + String nameLower = name.toLowerCase(); + List headerValueList = headerNameToValueListMap.get(nameLower); + if (null == headerValueList) { + headerValueList = new ArrayList(); + headerNameToValueListMap.put(nameLower, headerValueList); + headerNameList.add(nameLower); + } + headerValueList.add(value); + } +} diff --git a/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java new file mode 100644 index 000000000..0f4a40eca --- /dev/null +++ b/java/org/apache/tomcat/util/http/fileupload/util/LimitedInputStream.java @@ -0,0 +1,158 @@ +/* + * 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.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + + +/** + * An input stream, which limits its data size. This stream is + * used, if the content length is unknown. + */ +public abstract class LimitedInputStream + extends FilterInputStream implements Closeable { + /** + * The maximum size of an item, in bytes. + */ + private long sizeMax; + /** + * The current number of bytes. + */ + private long count; + /** + * Whether this stream is already closed. + */ + private boolean closed; + + /** + * Creates a new instance. + * @param pIn The input stream, which shall be limited. + * @param pSizeMax The limit; no more than this number of bytes + * shall be returned by the source stream. + */ + public LimitedInputStream(InputStream pIn, long pSizeMax) { + super(pIn); + sizeMax = pSizeMax; + } + + /** + * Called to indicate, that the input streams limit has + * been exceeded. + * @param pSizeMax The input streams limit, in bytes. + * @param pCount The actual number of bytes. + * @throws IOException The called method is expected + * to raise an IOException. + */ + protected abstract void raiseError(long pSizeMax, long pCount) + throws IOException; + + /** Called to check, whether the input streams + * limit is reached. + * @throws IOException The given limit is exceeded. + */ + private void checkLimit() throws IOException { + if (count > sizeMax) { + raiseError(sizeMax, count); + } + } + + /** + * Reads the next byte of data from this input stream. The value + * byte is returned as an int 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); + } +}